• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2020 Collabora Ltd.
4  */
5 #include <linux/clk.h>
6 #include <linux/clk-provider.h>
7 #include <linux/init.h>
8 #include <linux/io.h>
9 #include <linux/iopoll.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/of_clk.h>
12 #include <linux/of_device.h>
13 #include <linux/platform_device.h>
14 #include <linux/pm_domain.h>
15 #include <linux/regmap.h>
16 #include <linux/regulator/consumer.h>
17 #include <linux/soc/mediatek/infracfg.h>
18 
19 #include "mt8167-pm-domains.h"
20 #include "mt8173-pm-domains.h"
21 #include "mt8183-pm-domains.h"
22 #include "mt8192-pm-domains.h"
23 
24 #define MTK_POLL_DELAY_US		10
25 #define MTK_POLL_TIMEOUT		USEC_PER_SEC
26 
27 #define PWR_RST_B_BIT			BIT(0)
28 #define PWR_ISO_BIT			BIT(1)
29 #define PWR_ON_BIT			BIT(2)
30 #define PWR_ON_2ND_BIT			BIT(3)
31 #define PWR_CLK_DIS_BIT			BIT(4)
32 #define PWR_SRAM_CLKISO_BIT		BIT(5)
33 #define PWR_SRAM_ISOINT_B_BIT		BIT(6)
34 
35 struct scpsys_domain {
36 	struct generic_pm_domain genpd;
37 	const struct scpsys_domain_data *data;
38 	struct scpsys *scpsys;
39 	int num_clks;
40 	struct clk_bulk_data *clks;
41 	int num_subsys_clks;
42 	struct clk_bulk_data *subsys_clks;
43 	struct regmap *infracfg;
44 	struct regmap *smi;
45 	struct regulator *supply;
46 };
47 
48 struct scpsys {
49 	struct device *dev;
50 	struct regmap *base;
51 	const struct scpsys_soc_data *soc_data;
52 	struct genpd_onecell_data pd_data;
53 	struct generic_pm_domain *domains[];
54 };
55 
56 #define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd)
57 
scpsys_domain_is_on(struct scpsys_domain * pd)58 static bool scpsys_domain_is_on(struct scpsys_domain *pd)
59 {
60 	struct scpsys *scpsys = pd->scpsys;
61 	u32 status, status2;
62 
63 	regmap_read(scpsys->base, scpsys->soc_data->pwr_sta_offs, &status);
64 	status &= pd->data->sta_mask;
65 
66 	regmap_read(scpsys->base, scpsys->soc_data->pwr_sta2nd_offs, &status2);
67 	status2 &= pd->data->sta_mask;
68 
69 	/* A domain is on when both status bits are set. */
70 	return status && status2;
71 }
72 
scpsys_sram_enable(struct scpsys_domain * pd)73 static int scpsys_sram_enable(struct scpsys_domain *pd)
74 {
75 	u32 pdn_ack = pd->data->sram_pdn_ack_bits;
76 	struct scpsys *scpsys = pd->scpsys;
77 	unsigned int tmp;
78 	int ret;
79 
80 	regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits);
81 
82 	/* Either wait until SRAM_PDN_ACK all 1 or 0 */
83 	ret = regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp,
84 				       (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
85 	if (ret < 0)
86 		return ret;
87 
88 	if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) {
89 		regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT);
90 		udelay(1);
91 		regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT);
92 	}
93 
94 	return 0;
95 }
96 
scpsys_sram_disable(struct scpsys_domain * pd)97 static int scpsys_sram_disable(struct scpsys_domain *pd)
98 {
99 	u32 pdn_ack = pd->data->sram_pdn_ack_bits;
100 	struct scpsys *scpsys = pd->scpsys;
101 	unsigned int tmp;
102 
103 	if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) {
104 		regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT);
105 		udelay(1);
106 		regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT);
107 	}
108 
109 	regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits);
110 
111 	/* Either wait until SRAM_PDN_ACK all 1 or 0 */
112 	return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp,
113 					(tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US,
114 					MTK_POLL_TIMEOUT);
115 }
116 
_scpsys_bus_protect_enable(const struct scpsys_bus_prot_data * bpd,struct regmap * regmap)117 static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data *bpd, struct regmap *regmap)
118 {
119 	int i, ret;
120 
121 	for (i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) {
122 		u32 val, mask = bpd[i].bus_prot_mask;
123 
124 		if (!mask)
125 			break;
126 
127 		if (bpd[i].bus_prot_reg_update)
128 			regmap_set_bits(regmap, bpd[i].bus_prot_set, mask);
129 		else
130 			regmap_write(regmap, bpd[i].bus_prot_set, mask);
131 
132 		ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta,
133 					       val, (val & mask) == mask,
134 					       MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
135 		if (ret)
136 			return ret;
137 	}
138 
139 	return 0;
140 }
141 
scpsys_bus_protect_enable(struct scpsys_domain * pd)142 static int scpsys_bus_protect_enable(struct scpsys_domain *pd)
143 {
144 	int ret;
145 
146 	ret = _scpsys_bus_protect_enable(pd->data->bp_infracfg, pd->infracfg);
147 	if (ret)
148 		return ret;
149 
150 	return _scpsys_bus_protect_enable(pd->data->bp_smi, pd->smi);
151 }
152 
_scpsys_bus_protect_disable(const struct scpsys_bus_prot_data * bpd,struct regmap * regmap)153 static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd,
154 				       struct regmap *regmap)
155 {
156 	int i, ret;
157 
158 	for (i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) {
159 		u32 val, mask = bpd[i].bus_prot_mask;
160 
161 		if (!mask)
162 			continue;
163 
164 		if (bpd[i].bus_prot_reg_update)
165 			regmap_clear_bits(regmap, bpd[i].bus_prot_clr, mask);
166 		else
167 			regmap_write(regmap, bpd[i].bus_prot_clr, mask);
168 
169 		if (bpd[i].ignore_clr_ack)
170 			continue;
171 
172 		ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta,
173 					       val, !(val & mask),
174 					       MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT);
175 		if (ret)
176 			return ret;
177 	}
178 
179 	return 0;
180 }
181 
scpsys_bus_protect_disable(struct scpsys_domain * pd)182 static int scpsys_bus_protect_disable(struct scpsys_domain *pd)
183 {
184 	int ret;
185 
186 	ret = _scpsys_bus_protect_disable(pd->data->bp_smi, pd->smi);
187 	if (ret)
188 		return ret;
189 
190 	return _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg);
191 }
192 
scpsys_regulator_enable(struct regulator * supply)193 static int scpsys_regulator_enable(struct regulator *supply)
194 {
195 	return supply ? regulator_enable(supply) : 0;
196 }
197 
scpsys_regulator_disable(struct regulator * supply)198 static int scpsys_regulator_disable(struct regulator *supply)
199 {
200 	return supply ? regulator_disable(supply) : 0;
201 }
202 
scpsys_power_on(struct generic_pm_domain * genpd)203 static int scpsys_power_on(struct generic_pm_domain *genpd)
204 {
205 	struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
206 	struct scpsys *scpsys = pd->scpsys;
207 	bool tmp;
208 	int ret;
209 
210 	ret = scpsys_regulator_enable(pd->supply);
211 	if (ret)
212 		return ret;
213 
214 	ret = clk_bulk_prepare_enable(pd->num_clks, pd->clks);
215 	if (ret)
216 		goto err_reg;
217 
218 	/* subsys power on */
219 	regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
220 	regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
221 
222 	/* wait until PWR_ACK = 1 */
223 	ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US,
224 				 MTK_POLL_TIMEOUT);
225 	if (ret < 0)
226 		goto err_pwr_ack;
227 
228 	regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
229 	regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
230 	regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
231 
232 	ret = clk_bulk_prepare_enable(pd->num_subsys_clks, pd->subsys_clks);
233 	if (ret)
234 		goto err_pwr_ack;
235 
236 	ret = scpsys_sram_enable(pd);
237 	if (ret < 0)
238 		goto err_disable_subsys_clks;
239 
240 	ret = scpsys_bus_protect_disable(pd);
241 	if (ret < 0)
242 		goto err_disable_sram;
243 
244 	return 0;
245 
246 err_disable_sram:
247 	scpsys_sram_disable(pd);
248 err_disable_subsys_clks:
249 	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
250 err_pwr_ack:
251 	clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
252 err_reg:
253 	scpsys_regulator_disable(pd->supply);
254 	return ret;
255 }
256 
scpsys_power_off(struct generic_pm_domain * genpd)257 static int scpsys_power_off(struct generic_pm_domain *genpd)
258 {
259 	struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd);
260 	struct scpsys *scpsys = pd->scpsys;
261 	bool tmp;
262 	int ret;
263 
264 	ret = scpsys_bus_protect_enable(pd);
265 	if (ret < 0)
266 		return ret;
267 
268 	ret = scpsys_sram_disable(pd);
269 	if (ret < 0)
270 		return ret;
271 
272 	clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
273 
274 	/* subsys power off */
275 	regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT);
276 	regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT);
277 	regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT);
278 	regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT);
279 	regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT);
280 
281 	/* wait until PWR_ACK = 0 */
282 	ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US,
283 				 MTK_POLL_TIMEOUT);
284 	if (ret < 0)
285 		return ret;
286 
287 	clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
288 
289 	scpsys_regulator_disable(pd->supply);
290 
291 	return 0;
292 }
293 
294 static struct
scpsys_add_one_domain(struct scpsys * scpsys,struct device_node * node)295 generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
296 {
297 	const struct scpsys_domain_data *domain_data;
298 	struct scpsys_domain *pd;
299 	struct device_node *root_node = scpsys->dev->of_node;
300 	struct device_node *smi_node;
301 	struct property *prop;
302 	const char *clk_name;
303 	int i, ret, num_clks;
304 	struct clk *clk;
305 	int clk_ind = 0;
306 	u32 id;
307 
308 	ret = of_property_read_u32(node, "reg", &id);
309 	if (ret) {
310 		dev_err(scpsys->dev, "%pOF: failed to retrieve domain id from reg: %d\n",
311 			node, ret);
312 		return ERR_PTR(-EINVAL);
313 	}
314 
315 	if (id >= scpsys->soc_data->num_domains) {
316 		dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
317 		return ERR_PTR(-EINVAL);
318 	}
319 
320 	domain_data = &scpsys->soc_data->domains_data[id];
321 	if (domain_data->sta_mask == 0) {
322 		dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id);
323 		return ERR_PTR(-EINVAL);
324 	}
325 
326 	pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL);
327 	if (!pd)
328 		return ERR_PTR(-ENOMEM);
329 
330 	pd->data = domain_data;
331 	pd->scpsys = scpsys;
332 
333 	if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) {
334 		/*
335 		 * Find regulator in current power domain node.
336 		 * devm_regulator_get() finds regulator in a node and its child
337 		 * node, so set of_node to current power domain node then change
338 		 * back to original node after regulator is found for current
339 		 * power domain node.
340 		 */
341 		scpsys->dev->of_node = node;
342 		pd->supply = devm_regulator_get(scpsys->dev, "domain");
343 		scpsys->dev->of_node = root_node;
344 		if (IS_ERR(pd->supply)) {
345 			dev_err_probe(scpsys->dev, PTR_ERR(pd->supply),
346 				      "%pOF: failed to get power supply.\n",
347 				      node);
348 			return ERR_CAST(pd->supply);
349 		}
350 	}
351 
352 	pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg");
353 	if (IS_ERR(pd->infracfg))
354 		return ERR_CAST(pd->infracfg);
355 
356 	smi_node = of_parse_phandle(node, "mediatek,smi", 0);
357 	if (smi_node) {
358 		pd->smi = device_node_to_regmap(smi_node);
359 		of_node_put(smi_node);
360 		if (IS_ERR(pd->smi))
361 			return ERR_CAST(pd->smi);
362 	}
363 
364 	num_clks = of_clk_get_parent_count(node);
365 	if (num_clks > 0) {
366 		/* Calculate number of subsys_clks */
367 		of_property_for_each_string(node, "clock-names", prop, clk_name) {
368 			char *subsys;
369 
370 			subsys = strchr(clk_name, '-');
371 			if (subsys)
372 				pd->num_subsys_clks++;
373 			else
374 				pd->num_clks++;
375 		}
376 
377 		pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL);
378 		if (!pd->clks)
379 			return ERR_PTR(-ENOMEM);
380 
381 		pd->subsys_clks = devm_kcalloc(scpsys->dev, pd->num_subsys_clks,
382 					       sizeof(*pd->subsys_clks), GFP_KERNEL);
383 		if (!pd->subsys_clks)
384 			return ERR_PTR(-ENOMEM);
385 
386 	}
387 
388 	for (i = 0; i < pd->num_clks; i++) {
389 		clk = of_clk_get(node, i);
390 		if (IS_ERR(clk)) {
391 			ret = PTR_ERR(clk);
392 			dev_err_probe(scpsys->dev, ret,
393 				      "%pOF: failed to get clk at index %d: %d\n", node, i, ret);
394 			goto err_put_clocks;
395 		}
396 
397 		pd->clks[clk_ind++].clk = clk;
398 	}
399 
400 	for (i = 0; i < pd->num_subsys_clks; i++) {
401 		clk = of_clk_get(node, i + clk_ind);
402 		if (IS_ERR(clk)) {
403 			ret = PTR_ERR(clk);
404 			dev_err_probe(scpsys->dev, ret,
405 				      "%pOF: failed to get clk at index %d: %d\n", node,
406 				      i + clk_ind, ret);
407 			goto err_put_subsys_clocks;
408 		}
409 
410 		pd->subsys_clks[i].clk = clk;
411 	}
412 
413 	/*
414 	 * Initially turn on all domains to make the domains usable
415 	 * with !CONFIG_PM and to get the hardware in sync with the
416 	 * software.  The unused domains will be switched off during
417 	 * late_init time.
418 	 */
419 	if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
420 		if (scpsys_domain_is_on(pd))
421 			dev_warn(scpsys->dev,
422 				 "%pOF: A default off power domain has been ON\n", node);
423 	} else {
424 		ret = scpsys_power_on(&pd->genpd);
425 		if (ret < 0) {
426 			dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
427 			goto err_put_subsys_clocks;
428 		}
429 	}
430 
431 	if (scpsys->domains[id]) {
432 		ret = -EINVAL;
433 		dev_err(scpsys->dev,
434 			"power domain with id %d already exists, check your device-tree\n", id);
435 		goto err_put_subsys_clocks;
436 	}
437 
438 	if (!pd->data->name)
439 		pd->genpd.name = node->name;
440 	else
441 		pd->genpd.name = pd->data->name;
442 
443 	pd->genpd.power_off = scpsys_power_off;
444 	pd->genpd.power_on = scpsys_power_on;
445 
446 	if (MTK_SCPD_CAPS(pd, MTK_SCPD_ACTIVE_WAKEUP))
447 		pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
448 
449 	if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF))
450 		pm_genpd_init(&pd->genpd, NULL, true);
451 	else
452 		pm_genpd_init(&pd->genpd, NULL, false);
453 
454 	scpsys->domains[id] = &pd->genpd;
455 
456 	return scpsys->pd_data.domains[id];
457 
458 err_put_subsys_clocks:
459 	clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
460 err_put_clocks:
461 	clk_bulk_put(pd->num_clks, pd->clks);
462 	return ERR_PTR(ret);
463 }
464 
scpsys_add_subdomain(struct scpsys * scpsys,struct device_node * parent)465 static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent)
466 {
467 	struct generic_pm_domain *child_pd, *parent_pd;
468 	struct device_node *child;
469 	int ret;
470 
471 	for_each_child_of_node(parent, child) {
472 		u32 id;
473 
474 		ret = of_property_read_u32(parent, "reg", &id);
475 		if (ret) {
476 			dev_err(scpsys->dev, "%pOF: failed to get parent domain id\n", child);
477 			goto err_put_node;
478 		}
479 
480 		if (!scpsys->pd_data.domains[id]) {
481 			ret = -EINVAL;
482 			dev_err(scpsys->dev, "power domain with id %d does not exist\n", id);
483 			goto err_put_node;
484 		}
485 
486 		parent_pd = scpsys->pd_data.domains[id];
487 
488 		child_pd = scpsys_add_one_domain(scpsys, child);
489 		if (IS_ERR(child_pd)) {
490 			ret = PTR_ERR(child_pd);
491 			dev_err_probe(scpsys->dev, ret, "%pOF: failed to get child domain id\n",
492 				      child);
493 			goto err_put_node;
494 		}
495 
496 		ret = pm_genpd_add_subdomain(parent_pd, child_pd);
497 		if (ret) {
498 			dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n",
499 				child_pd->name, parent_pd->name);
500 			goto err_put_node;
501 		} else {
502 			dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name,
503 				child_pd->name);
504 		}
505 
506 		/* recursive call to add all subdomains */
507 		ret = scpsys_add_subdomain(scpsys, child);
508 		if (ret)
509 			goto err_put_node;
510 	}
511 
512 	return 0;
513 
514 err_put_node:
515 	of_node_put(child);
516 	return ret;
517 }
518 
scpsys_remove_one_domain(struct scpsys_domain * pd)519 static void scpsys_remove_one_domain(struct scpsys_domain *pd)
520 {
521 	int ret;
522 
523 	if (scpsys_domain_is_on(pd))
524 		scpsys_power_off(&pd->genpd);
525 
526 	/*
527 	 * We're in the error cleanup already, so we only complain,
528 	 * but won't emit another error on top of the original one.
529 	 */
530 	ret = pm_genpd_remove(&pd->genpd);
531 	if (ret < 0)
532 		dev_err(pd->scpsys->dev,
533 			"failed to remove domain '%s' : %d - state may be inconsistent\n",
534 			pd->genpd.name, ret);
535 
536 	clk_bulk_put(pd->num_clks, pd->clks);
537 	clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
538 }
539 
scpsys_domain_cleanup(struct scpsys * scpsys)540 static void scpsys_domain_cleanup(struct scpsys *scpsys)
541 {
542 	struct generic_pm_domain *genpd;
543 	struct scpsys_domain *pd;
544 	int i;
545 
546 	for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) {
547 		genpd = scpsys->pd_data.domains[i];
548 		if (genpd) {
549 			pd = to_scpsys_domain(genpd);
550 			scpsys_remove_one_domain(pd);
551 		}
552 	}
553 }
554 
555 static const struct of_device_id scpsys_of_match[] = {
556 	{
557 		.compatible = "mediatek,mt8167-power-controller",
558 		.data = &mt8167_scpsys_data,
559 	},
560 	{
561 		.compatible = "mediatek,mt8173-power-controller",
562 		.data = &mt8173_scpsys_data,
563 	},
564 	{
565 		.compatible = "mediatek,mt8183-power-controller",
566 		.data = &mt8183_scpsys_data,
567 	},
568 	{
569 		.compatible = "mediatek,mt8192-power-controller",
570 		.data = &mt8192_scpsys_data,
571 	},
572 	{ }
573 };
574 
scpsys_probe(struct platform_device * pdev)575 static int scpsys_probe(struct platform_device *pdev)
576 {
577 	struct device *dev = &pdev->dev;
578 	struct device_node *np = dev->of_node;
579 	const struct scpsys_soc_data *soc;
580 	struct device_node *node;
581 	struct device *parent;
582 	struct scpsys *scpsys;
583 	int ret;
584 
585 	soc = of_device_get_match_data(&pdev->dev);
586 	if (!soc) {
587 		dev_err(&pdev->dev, "no power controller data\n");
588 		return -EINVAL;
589 	}
590 
591 	scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL);
592 	if (!scpsys)
593 		return -ENOMEM;
594 
595 	scpsys->dev = dev;
596 	scpsys->soc_data = soc;
597 
598 	scpsys->pd_data.domains = scpsys->domains;
599 	scpsys->pd_data.num_domains = soc->num_domains;
600 
601 	parent = dev->parent;
602 	if (!parent) {
603 		dev_err(dev, "no parent for syscon devices\n");
604 		return -ENODEV;
605 	}
606 
607 	scpsys->base = syscon_node_to_regmap(parent->of_node);
608 	if (IS_ERR(scpsys->base)) {
609 		dev_err(dev, "no regmap available\n");
610 		return PTR_ERR(scpsys->base);
611 	}
612 
613 	ret = -ENODEV;
614 	for_each_available_child_of_node(np, node) {
615 		struct generic_pm_domain *domain;
616 
617 		domain = scpsys_add_one_domain(scpsys, node);
618 		if (IS_ERR(domain)) {
619 			ret = PTR_ERR(domain);
620 			of_node_put(node);
621 			goto err_cleanup_domains;
622 		}
623 
624 		ret = scpsys_add_subdomain(scpsys, node);
625 		if (ret) {
626 			of_node_put(node);
627 			goto err_cleanup_domains;
628 		}
629 	}
630 
631 	if (ret) {
632 		dev_dbg(dev, "no power domains present\n");
633 		return ret;
634 	}
635 
636 	ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data);
637 	if (ret) {
638 		dev_err(dev, "failed to add provider: %d\n", ret);
639 		goto err_cleanup_domains;
640 	}
641 
642 	return 0;
643 
644 err_cleanup_domains:
645 	scpsys_domain_cleanup(scpsys);
646 	return ret;
647 }
648 
649 static struct platform_driver scpsys_pm_domain_driver = {
650 	.probe = scpsys_probe,
651 	.driver = {
652 		.name = "mtk-power-controller",
653 		.suppress_bind_attrs = true,
654 		.of_match_table = scpsys_of_match,
655 	},
656 };
657 builtin_platform_driver(scpsys_pm_domain_driver);
658