Commit | Line | Data |
---|---|---|
c84e3587 SH |
1 | /* |
2 | * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 as | |
6 | * published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | */ | |
13 | #include <linux/clk.h> | |
14 | #include <linux/delay.h> | |
15 | #include <linux/io.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/mfd/syscon.h> | |
e50be5cd | 18 | #include <linux/init.h> |
c84e3587 SH |
19 | #include <linux/of_device.h> |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/pm_domain.h> | |
22 | #include <linux/regmap.h> | |
23 | #include <linux/soc/mediatek/infracfg.h> | |
4688f385 | 24 | #include <linux/regulator/consumer.h> |
c84e3587 SH |
25 | #include <dt-bindings/power/mt8173-power.h> |
26 | ||
27 | #define SPM_VDE_PWR_CON 0x0210 | |
28 | #define SPM_MFG_PWR_CON 0x0214 | |
29 | #define SPM_VEN_PWR_CON 0x0230 | |
30 | #define SPM_ISP_PWR_CON 0x0238 | |
31 | #define SPM_DIS_PWR_CON 0x023c | |
32 | #define SPM_VEN2_PWR_CON 0x0298 | |
33 | #define SPM_AUDIO_PWR_CON 0x029c | |
34 | #define SPM_MFG_2D_PWR_CON 0x02c0 | |
35 | #define SPM_MFG_ASYNC_PWR_CON 0x02c4 | |
36 | #define SPM_USB_PWR_CON 0x02cc | |
37 | #define SPM_PWR_STATUS 0x060c | |
38 | #define SPM_PWR_STATUS_2ND 0x0610 | |
39 | ||
40 | #define PWR_RST_B_BIT BIT(0) | |
41 | #define PWR_ISO_BIT BIT(1) | |
42 | #define PWR_ON_BIT BIT(2) | |
43 | #define PWR_ON_2ND_BIT BIT(3) | |
44 | #define PWR_CLK_DIS_BIT BIT(4) | |
45 | ||
46 | #define PWR_STATUS_DISP BIT(3) | |
47 | #define PWR_STATUS_MFG BIT(4) | |
48 | #define PWR_STATUS_ISP BIT(5) | |
49 | #define PWR_STATUS_VDEC BIT(7) | |
50 | #define PWR_STATUS_VENC_LT BIT(20) | |
51 | #define PWR_STATUS_VENC BIT(21) | |
52 | #define PWR_STATUS_MFG_2D BIT(22) | |
53 | #define PWR_STATUS_MFG_ASYNC BIT(23) | |
54 | #define PWR_STATUS_AUDIO BIT(24) | |
55 | #define PWR_STATUS_USB BIT(25) | |
56 | ||
57 | enum clk_id { | |
41b3e0f0 | 58 | MT8173_CLK_NONE, |
c84e3587 SH |
59 | MT8173_CLK_MM, |
60 | MT8173_CLK_MFG, | |
41b3e0f0 JL |
61 | MT8173_CLK_VENC, |
62 | MT8173_CLK_VENC_LT, | |
63 | MT8173_CLK_MAX, | |
c84e3587 SH |
64 | }; |
65 | ||
41b3e0f0 JL |
66 | #define MAX_CLKS 2 |
67 | ||
c84e3587 SH |
68 | struct scp_domain_data { |
69 | const char *name; | |
70 | u32 sta_mask; | |
71 | int ctl_offs; | |
72 | u32 sram_pdn_bits; | |
73 | u32 sram_pdn_ack_bits; | |
74 | u32 bus_prot_mask; | |
41b3e0f0 | 75 | enum clk_id clk_id[MAX_CLKS]; |
47e90154 | 76 | bool active_wakeup; |
c84e3587 SH |
77 | }; |
78 | ||
be29523d | 79 | static const struct scp_domain_data scp_domain_data[] = { |
c84e3587 SH |
80 | [MT8173_POWER_DOMAIN_VDEC] = { |
81 | .name = "vdec", | |
82 | .sta_mask = PWR_STATUS_VDEC, | |
83 | .ctl_offs = SPM_VDE_PWR_CON, | |
84 | .sram_pdn_bits = GENMASK(11, 8), | |
85 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
41b3e0f0 | 86 | .clk_id = {MT8173_CLK_MM}, |
c84e3587 SH |
87 | }, |
88 | [MT8173_POWER_DOMAIN_VENC] = { | |
89 | .name = "venc", | |
90 | .sta_mask = PWR_STATUS_VENC, | |
91 | .ctl_offs = SPM_VEN_PWR_CON, | |
92 | .sram_pdn_bits = GENMASK(11, 8), | |
93 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
41b3e0f0 | 94 | .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, |
c84e3587 SH |
95 | }, |
96 | [MT8173_POWER_DOMAIN_ISP] = { | |
97 | .name = "isp", | |
98 | .sta_mask = PWR_STATUS_ISP, | |
99 | .ctl_offs = SPM_ISP_PWR_CON, | |
100 | .sram_pdn_bits = GENMASK(11, 8), | |
101 | .sram_pdn_ack_bits = GENMASK(13, 12), | |
41b3e0f0 | 102 | .clk_id = {MT8173_CLK_MM}, |
c84e3587 SH |
103 | }, |
104 | [MT8173_POWER_DOMAIN_MM] = { | |
105 | .name = "mm", | |
106 | .sta_mask = PWR_STATUS_DISP, | |
107 | .ctl_offs = SPM_DIS_PWR_CON, | |
108 | .sram_pdn_bits = GENMASK(11, 8), | |
109 | .sram_pdn_ack_bits = GENMASK(12, 12), | |
41b3e0f0 | 110 | .clk_id = {MT8173_CLK_MM}, |
c84e3587 SH |
111 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | |
112 | MT8173_TOP_AXI_PROT_EN_MM_M1, | |
113 | }, | |
114 | [MT8173_POWER_DOMAIN_VENC_LT] = { | |
115 | .name = "venc_lt", | |
116 | .sta_mask = PWR_STATUS_VENC_LT, | |
117 | .ctl_offs = SPM_VEN2_PWR_CON, | |
118 | .sram_pdn_bits = GENMASK(11, 8), | |
119 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
41b3e0f0 | 120 | .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, |
c84e3587 SH |
121 | }, |
122 | [MT8173_POWER_DOMAIN_AUDIO] = { | |
123 | .name = "audio", | |
124 | .sta_mask = PWR_STATUS_AUDIO, | |
125 | .ctl_offs = SPM_AUDIO_PWR_CON, | |
126 | .sram_pdn_bits = GENMASK(11, 8), | |
127 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
41b3e0f0 | 128 | .clk_id = {MT8173_CLK_NONE}, |
c84e3587 SH |
129 | }, |
130 | [MT8173_POWER_DOMAIN_USB] = { | |
131 | .name = "usb", | |
132 | .sta_mask = PWR_STATUS_USB, | |
133 | .ctl_offs = SPM_USB_PWR_CON, | |
134 | .sram_pdn_bits = GENMASK(11, 8), | |
135 | .sram_pdn_ack_bits = GENMASK(15, 12), | |
41b3e0f0 | 136 | .clk_id = {MT8173_CLK_NONE}, |
47e90154 | 137 | .active_wakeup = true, |
c84e3587 SH |
138 | }, |
139 | [MT8173_POWER_DOMAIN_MFG_ASYNC] = { | |
140 | .name = "mfg_async", | |
141 | .sta_mask = PWR_STATUS_MFG_ASYNC, | |
142 | .ctl_offs = SPM_MFG_ASYNC_PWR_CON, | |
143 | .sram_pdn_bits = GENMASK(11, 8), | |
144 | .sram_pdn_ack_bits = 0, | |
41b3e0f0 | 145 | .clk_id = {MT8173_CLK_MFG}, |
c84e3587 SH |
146 | }, |
147 | [MT8173_POWER_DOMAIN_MFG_2D] = { | |
148 | .name = "mfg_2d", | |
149 | .sta_mask = PWR_STATUS_MFG_2D, | |
150 | .ctl_offs = SPM_MFG_2D_PWR_CON, | |
151 | .sram_pdn_bits = GENMASK(11, 8), | |
152 | .sram_pdn_ack_bits = GENMASK(13, 12), | |
41b3e0f0 | 153 | .clk_id = {MT8173_CLK_NONE}, |
c84e3587 SH |
154 | }, |
155 | [MT8173_POWER_DOMAIN_MFG] = { | |
156 | .name = "mfg", | |
157 | .sta_mask = PWR_STATUS_MFG, | |
158 | .ctl_offs = SPM_MFG_PWR_CON, | |
159 | .sram_pdn_bits = GENMASK(13, 8), | |
160 | .sram_pdn_ack_bits = GENMASK(21, 16), | |
41b3e0f0 | 161 | .clk_id = {MT8173_CLK_NONE}, |
c84e3587 SH |
162 | .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | |
163 | MT8173_TOP_AXI_PROT_EN_MFG_M0 | | |
164 | MT8173_TOP_AXI_PROT_EN_MFG_M1 | | |
165 | MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, | |
166 | }, | |
167 | }; | |
168 | ||
169 | #define NUM_DOMAINS ARRAY_SIZE(scp_domain_data) | |
170 | ||
171 | struct scp; | |
172 | ||
173 | struct scp_domain { | |
174 | struct generic_pm_domain genpd; | |
175 | struct scp *scp; | |
41b3e0f0 | 176 | struct clk *clk[MAX_CLKS]; |
be29523d | 177 | const struct scp_domain_data *data; |
4688f385 | 178 | struct regulator *supply; |
c84e3587 SH |
179 | }; |
180 | ||
181 | struct scp { | |
182 | struct scp_domain domains[NUM_DOMAINS]; | |
183 | struct genpd_onecell_data pd_data; | |
184 | struct device *dev; | |
185 | void __iomem *base; | |
186 | struct regmap *infracfg; | |
187 | }; | |
188 | ||
189 | static int scpsys_domain_is_on(struct scp_domain *scpd) | |
190 | { | |
191 | struct scp *scp = scpd->scp; | |
192 | ||
be29523d MB |
193 | u32 status = readl(scp->base + SPM_PWR_STATUS) & scpd->data->sta_mask; |
194 | u32 status2 = readl(scp->base + SPM_PWR_STATUS_2ND) & | |
195 | scpd->data->sta_mask; | |
c84e3587 SH |
196 | |
197 | /* | |
198 | * A domain is on when both status bits are set. If only one is set | |
199 | * return an error. This happens while powering up a domain | |
200 | */ | |
201 | ||
202 | if (status && status2) | |
203 | return true; | |
204 | if (!status && !status2) | |
205 | return false; | |
206 | ||
207 | return -EINVAL; | |
208 | } | |
209 | ||
210 | static int scpsys_power_on(struct generic_pm_domain *genpd) | |
211 | { | |
212 | struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); | |
213 | struct scp *scp = scpd->scp; | |
214 | unsigned long timeout; | |
215 | bool expired; | |
be29523d MB |
216 | void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; |
217 | u32 sram_pdn_ack = scpd->data->sram_pdn_ack_bits; | |
c84e3587 SH |
218 | u32 val; |
219 | int ret; | |
41b3e0f0 JL |
220 | int i; |
221 | ||
4688f385 SH |
222 | if (scpd->supply) { |
223 | ret = regulator_enable(scpd->supply); | |
224 | if (ret) | |
225 | return ret; | |
226 | } | |
227 | ||
41b3e0f0 JL |
228 | for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) { |
229 | ret = clk_prepare_enable(scpd->clk[i]); | |
230 | if (ret) { | |
231 | for (--i; i >= 0; i--) | |
232 | clk_disable_unprepare(scpd->clk[i]); | |
c84e3587 | 233 | |
c84e3587 | 234 | goto err_clk; |
41b3e0f0 | 235 | } |
c84e3587 SH |
236 | } |
237 | ||
238 | val = readl(ctl_addr); | |
239 | val |= PWR_ON_BIT; | |
240 | writel(val, ctl_addr); | |
241 | val |= PWR_ON_2ND_BIT; | |
242 | writel(val, ctl_addr); | |
243 | ||
244 | /* wait until PWR_ACK = 1 */ | |
245 | timeout = jiffies + HZ; | |
246 | expired = false; | |
247 | while (1) { | |
248 | ret = scpsys_domain_is_on(scpd); | |
249 | if (ret > 0) | |
250 | break; | |
251 | ||
252 | if (expired) { | |
253 | ret = -ETIMEDOUT; | |
254 | goto err_pwr_ack; | |
255 | } | |
256 | ||
257 | cpu_relax(); | |
258 | ||
259 | if (time_after(jiffies, timeout)) | |
260 | expired = true; | |
261 | } | |
262 | ||
263 | val &= ~PWR_CLK_DIS_BIT; | |
264 | writel(val, ctl_addr); | |
265 | ||
266 | val &= ~PWR_ISO_BIT; | |
267 | writel(val, ctl_addr); | |
268 | ||
269 | val |= PWR_RST_B_BIT; | |
270 | writel(val, ctl_addr); | |
271 | ||
be29523d | 272 | val &= ~scpd->data->sram_pdn_bits; |
c84e3587 SH |
273 | writel(val, ctl_addr); |
274 | ||
275 | /* wait until SRAM_PDN_ACK all 0 */ | |
276 | timeout = jiffies + HZ; | |
277 | expired = false; | |
278 | while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) { | |
279 | ||
280 | if (expired) { | |
281 | ret = -ETIMEDOUT; | |
282 | goto err_pwr_ack; | |
283 | } | |
284 | ||
285 | cpu_relax(); | |
286 | ||
287 | if (time_after(jiffies, timeout)) | |
288 | expired = true; | |
289 | } | |
290 | ||
be29523d | 291 | if (scpd->data->bus_prot_mask) { |
c84e3587 | 292 | ret = mtk_infracfg_clear_bus_protection(scp->infracfg, |
be29523d | 293 | scpd->data->bus_prot_mask); |
c84e3587 SH |
294 | if (ret) |
295 | goto err_pwr_ack; | |
296 | } | |
297 | ||
298 | return 0; | |
299 | ||
300 | err_pwr_ack: | |
41b3e0f0 JL |
301 | for (i = MAX_CLKS - 1; i >= 0; i--) { |
302 | if (scpd->clk[i]) | |
303 | clk_disable_unprepare(scpd->clk[i]); | |
304 | } | |
c84e3587 | 305 | err_clk: |
4688f385 SH |
306 | if (scpd->supply) |
307 | regulator_disable(scpd->supply); | |
308 | ||
c84e3587 SH |
309 | dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name); |
310 | ||
311 | return ret; | |
312 | } | |
313 | ||
314 | static int scpsys_power_off(struct generic_pm_domain *genpd) | |
315 | { | |
316 | struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd); | |
317 | struct scp *scp = scpd->scp; | |
318 | unsigned long timeout; | |
319 | bool expired; | |
be29523d MB |
320 | void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs; |
321 | u32 pdn_ack = scpd->data->sram_pdn_ack_bits; | |
c84e3587 SH |
322 | u32 val; |
323 | int ret; | |
41b3e0f0 | 324 | int i; |
c84e3587 | 325 | |
be29523d | 326 | if (scpd->data->bus_prot_mask) { |
c84e3587 | 327 | ret = mtk_infracfg_set_bus_protection(scp->infracfg, |
be29523d | 328 | scpd->data->bus_prot_mask); |
c84e3587 SH |
329 | if (ret) |
330 | goto out; | |
331 | } | |
332 | ||
333 | val = readl(ctl_addr); | |
be29523d | 334 | val |= scpd->data->sram_pdn_bits; |
c84e3587 SH |
335 | writel(val, ctl_addr); |
336 | ||
337 | /* wait until SRAM_PDN_ACK all 1 */ | |
338 | timeout = jiffies + HZ; | |
339 | expired = false; | |
340 | while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) { | |
341 | if (expired) { | |
342 | ret = -ETIMEDOUT; | |
343 | goto out; | |
344 | } | |
345 | ||
346 | cpu_relax(); | |
347 | ||
348 | if (time_after(jiffies, timeout)) | |
349 | expired = true; | |
350 | } | |
351 | ||
352 | val |= PWR_ISO_BIT; | |
353 | writel(val, ctl_addr); | |
354 | ||
355 | val &= ~PWR_RST_B_BIT; | |
356 | writel(val, ctl_addr); | |
357 | ||
358 | val |= PWR_CLK_DIS_BIT; | |
359 | writel(val, ctl_addr); | |
360 | ||
361 | val &= ~PWR_ON_BIT; | |
362 | writel(val, ctl_addr); | |
363 | ||
364 | val &= ~PWR_ON_2ND_BIT; | |
365 | writel(val, ctl_addr); | |
366 | ||
367 | /* wait until PWR_ACK = 0 */ | |
368 | timeout = jiffies + HZ; | |
369 | expired = false; | |
370 | while (1) { | |
371 | ret = scpsys_domain_is_on(scpd); | |
372 | if (ret == 0) | |
373 | break; | |
374 | ||
375 | if (expired) { | |
376 | ret = -ETIMEDOUT; | |
377 | goto out; | |
378 | } | |
379 | ||
380 | cpu_relax(); | |
381 | ||
382 | if (time_after(jiffies, timeout)) | |
383 | expired = true; | |
384 | } | |
385 | ||
41b3e0f0 JL |
386 | for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) |
387 | clk_disable_unprepare(scpd->clk[i]); | |
c84e3587 | 388 | |
4688f385 SH |
389 | if (scpd->supply) |
390 | regulator_disable(scpd->supply); | |
391 | ||
c84e3587 SH |
392 | return 0; |
393 | ||
394 | out: | |
395 | dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name); | |
396 | ||
397 | return ret; | |
398 | } | |
399 | ||
47e90154 EH |
400 | static bool scpsys_active_wakeup(struct device *dev) |
401 | { | |
402 | struct generic_pm_domain *genpd; | |
403 | struct scp_domain *scpd; | |
404 | ||
405 | genpd = pd_to_genpd(dev->pm_domain); | |
406 | scpd = container_of(genpd, struct scp_domain, genpd); | |
407 | ||
be29523d | 408 | return scpd->data->active_wakeup; |
47e90154 EH |
409 | } |
410 | ||
be29523d | 411 | static int scpsys_probe(struct platform_device *pdev) |
c84e3587 SH |
412 | { |
413 | struct genpd_onecell_data *pd_data; | |
414 | struct resource *res; | |
41b3e0f0 | 415 | int i, j, ret; |
c84e3587 SH |
416 | struct scp *scp; |
417 | struct clk *clk[MT8173_CLK_MAX]; | |
418 | ||
419 | scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); | |
420 | if (!scp) | |
421 | return -ENOMEM; | |
422 | ||
423 | scp->dev = &pdev->dev; | |
424 | ||
425 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
426 | scp->base = devm_ioremap_resource(&pdev->dev, res); | |
427 | if (IS_ERR(scp->base)) | |
428 | return PTR_ERR(scp->base); | |
429 | ||
430 | pd_data = &scp->pd_data; | |
431 | ||
432 | pd_data->domains = devm_kzalloc(&pdev->dev, | |
433 | sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL); | |
434 | if (!pd_data->domains) | |
435 | return -ENOMEM; | |
436 | ||
437 | clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm"); | |
438 | if (IS_ERR(clk[MT8173_CLK_MM])) | |
439 | return PTR_ERR(clk[MT8173_CLK_MM]); | |
440 | ||
441 | clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg"); | |
442 | if (IS_ERR(clk[MT8173_CLK_MFG])) | |
443 | return PTR_ERR(clk[MT8173_CLK_MFG]); | |
444 | ||
41b3e0f0 JL |
445 | clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); |
446 | if (IS_ERR(clk[MT8173_CLK_VENC])) | |
447 | return PTR_ERR(clk[MT8173_CLK_VENC]); | |
448 | ||
449 | clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); | |
450 | if (IS_ERR(clk[MT8173_CLK_VENC_LT])) | |
451 | return PTR_ERR(clk[MT8173_CLK_VENC_LT]); | |
452 | ||
c84e3587 SH |
453 | scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, |
454 | "infracfg"); | |
455 | if (IS_ERR(scp->infracfg)) { | |
456 | dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", | |
457 | PTR_ERR(scp->infracfg)); | |
458 | return PTR_ERR(scp->infracfg); | |
459 | } | |
460 | ||
4688f385 SH |
461 | for (i = 0; i < NUM_DOMAINS; i++) { |
462 | struct scp_domain *scpd = &scp->domains[i]; | |
463 | const struct scp_domain_data *data = &scp_domain_data[i]; | |
464 | ||
465 | scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name); | |
466 | if (IS_ERR(scpd->supply)) { | |
467 | if (PTR_ERR(scpd->supply) == -ENODEV) | |
468 | scpd->supply = NULL; | |
469 | else | |
470 | return PTR_ERR(scpd->supply); | |
471 | } | |
472 | } | |
473 | ||
c84e3587 SH |
474 | pd_data->num_domains = NUM_DOMAINS; |
475 | ||
476 | for (i = 0; i < NUM_DOMAINS; i++) { | |
477 | struct scp_domain *scpd = &scp->domains[i]; | |
478 | struct generic_pm_domain *genpd = &scpd->genpd; | |
479 | const struct scp_domain_data *data = &scp_domain_data[i]; | |
480 | ||
481 | pd_data->domains[i] = genpd; | |
482 | scpd->scp = scp; | |
483 | ||
be29523d | 484 | scpd->data = data; |
41b3e0f0 JL |
485 | for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) |
486 | scpd->clk[j] = clk[data->clk_id[j]]; | |
c84e3587 SH |
487 | |
488 | genpd->name = data->name; | |
489 | genpd->power_off = scpsys_power_off; | |
490 | genpd->power_on = scpsys_power_on; | |
47e90154 | 491 | genpd->dev_ops.active_wakeup = scpsys_active_wakeup; |
c84e3587 SH |
492 | |
493 | /* | |
d9c9f3b8 JL |
494 | * Initially turn on all domains to make the domains usable |
495 | * with !CONFIG_PM and to get the hardware in sync with the | |
496 | * software. The unused domains will be switched off during | |
497 | * late_init time. | |
c84e3587 | 498 | */ |
d9c9f3b8 | 499 | genpd->power_on(genpd); |
c84e3587 | 500 | |
d9c9f3b8 | 501 | pm_genpd_init(genpd, NULL, false); |
c84e3587 SH |
502 | } |
503 | ||
504 | /* | |
505 | * We are not allowed to fail here since there is no way to unregister | |
506 | * a power domain. Once registered above we have to keep the domains | |
507 | * valid. | |
508 | */ | |
509 | ||
510 | ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC], | |
511 | pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]); | |
512 | if (ret && IS_ENABLED(CONFIG_PM)) | |
513 | dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); | |
514 | ||
515 | ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D], | |
516 | pd_data->domains[MT8173_POWER_DOMAIN_MFG]); | |
517 | if (ret && IS_ENABLED(CONFIG_PM)) | |
518 | dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); | |
519 | ||
520 | ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); | |
521 | if (ret) | |
522 | dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); | |
523 | ||
524 | return 0; | |
525 | } | |
526 | ||
527 | static const struct of_device_id of_scpsys_match_tbl[] = { | |
528 | { | |
529 | .compatible = "mediatek,mt8173-scpsys", | |
530 | }, { | |
531 | /* sentinel */ | |
532 | } | |
533 | }; | |
534 | ||
535 | static struct platform_driver scpsys_drv = { | |
be29523d | 536 | .probe = scpsys_probe, |
c84e3587 SH |
537 | .driver = { |
538 | .name = "mtk-scpsys", | |
be29523d | 539 | .suppress_bind_attrs = true, |
c84e3587 SH |
540 | .owner = THIS_MODULE, |
541 | .of_match_table = of_match_ptr(of_scpsys_match_tbl), | |
542 | }, | |
543 | }; | |
be29523d | 544 | builtin_platform_driver(scpsys_drv); |