GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / soc / mediatek / mtk-pm-domains.c
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
37 struct 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
50 struct 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
60 static 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
75 static 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
99 static 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
119 static 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
144 static 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
155 static 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
184 static 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
195 static int scpsys_regulator_enable(struct regulator *supply)
196 {
197         return supply ? regulator_enable(supply) : 0;
198 }
199
200 static int scpsys_regulator_disable(struct regulator *supply)
201 {
202         return supply ? regulator_disable(supply) : 0;
203 }
204
205 static 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
248 err_disable_sram:
249         scpsys_sram_disable(pd);
250 err_disable_subsys_clks:
251         clk_bulk_disable_unprepare(pd->num_subsys_clks, pd->subsys_clks);
252 err_pwr_ack:
253         clk_bulk_disable_unprepare(pd->num_clks, pd->clks);
254 err_reg:
255         scpsys_regulator_disable(pd->supply);
256         return ret;
257 }
258
259 static 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
296 static struct
297 generic_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
460 err_put_subsys_clocks:
461         clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks);
462 err_put_clocks:
463         clk_bulk_put(pd->num_clks, pd->clks);
464         return ERR_PTR(ret);
465 }
466
467 static 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
516 err_put_node:
517         of_node_put(child);
518         return ret;
519 }
520
521 static 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
542 static 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
557 static 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
585 static 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
654 err_cleanup_domains:
655         scpsys_domain_cleanup(scpsys);
656         return ret;
657 }
658
659 static 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 };
667 builtin_platform_driver(scpsys_pm_domain_driver);