cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mtk-pm-domains.c (16852B)


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