1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2019 BayLibre, SAS
4 * Author: Neil Armstrong <narmstrong@baylibre.com>
7 #include <linux/platform_device.h>
8 #include <linux/pm_domain.h>
9 #include <linux/bitfield.h>
10 #include <linux/regmap.h>
11 #include <linux/mfd/syscon.h>
13 #include <linux/reset-controller.h>
14 #include <linux/reset.h>
15 #include <linux/clk.h>
16 #include <linux/module.h>
17 #include <dt-bindings/power/meson8-power.h>
18 #include <dt-bindings/power/meson-axg-power.h>
19 #include <dt-bindings/power/meson-g12a-power.h>
20 #include <dt-bindings/power/meson-gxbb-power.h>
21 #include <dt-bindings/power/meson-sm1-power.h>
25 #define GX_AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2)
26 #define GX_AO_RTI_GEN_PWR_ISO0 (0x3b << 2)
29 * Meson8/Meson8b/Meson8m2 only expose the power management registers of the
30 * AO-bus as syscon. 0x3a from GX translates to 0x02, 0x3b translates to 0x03
33 #define MESON8_AO_RTI_GEN_PWR_SLEEP0 (0x02 << 2)
34 #define MESON8_AO_RTI_GEN_PWR_ISO0 (0x03 << 2)
38 #define HHI_MEM_PD_REG0 (0x40 << 2)
39 #define HHI_VPU_MEM_PD_REG0 (0x41 << 2)
40 #define HHI_VPU_MEM_PD_REG1 (0x42 << 2)
41 #define HHI_VPU_MEM_PD_REG3 (0x43 << 2)
42 #define HHI_VPU_MEM_PD_REG4 (0x44 << 2)
43 #define HHI_AUDIO_MEM_PD_REG0 (0x45 << 2)
44 #define HHI_NANOQ_MEM_PD_REG0 (0x46 << 2)
45 #define HHI_NANOQ_MEM_PD_REG1 (0x47 << 2)
46 #define HHI_VPU_MEM_PD_REG2 (0x4d << 2)
48 #define G12A_HHI_NANOQ_MEM_PD_REG0 (0x43 << 2)
49 #define G12A_HHI_NANOQ_MEM_PD_REG1 (0x44 << 2)
50 #define G12A_HHI_ISP_MEM_PD_REG0 (0x45 << 2)
51 #define G12A_HHI_ISP_MEM_PD_REG1 (0x46 << 2)
54 struct meson_ee_pwrc_domain
;
56 struct meson_ee_pwrc_mem_domain
{
61 struct meson_ee_pwrc_top_domain
{
62 unsigned int sleep_reg
;
63 unsigned int sleep_mask
;
65 unsigned int iso_mask
;
68 struct meson_ee_pwrc_domain_desc
{
70 unsigned int reset_names_count
;
71 unsigned int clk_names_count
;
72 struct meson_ee_pwrc_top_domain
*top_pd
;
73 unsigned int mem_pd_count
;
74 struct meson_ee_pwrc_mem_domain
*mem_pd
;
75 bool (*is_powered_off
)(struct meson_ee_pwrc_domain
*pwrc_domain
);
78 struct meson_ee_pwrc_domain_data
{
80 struct meson_ee_pwrc_domain_desc
*domains
;
83 /* TOP Power Domains */
85 static struct meson_ee_pwrc_top_domain gx_pwrc_vpu
= {
86 .sleep_reg
= GX_AO_RTI_GEN_PWR_SLEEP0
,
88 .iso_reg
= GX_AO_RTI_GEN_PWR_SLEEP0
,
92 static struct meson_ee_pwrc_top_domain meson8_pwrc_vpu
= {
93 .sleep_reg
= MESON8_AO_RTI_GEN_PWR_SLEEP0
,
95 .iso_reg
= MESON8_AO_RTI_GEN_PWR_SLEEP0
,
99 #define SM1_EE_PD(__bit) \
101 .sleep_reg = GX_AO_RTI_GEN_PWR_SLEEP0, \
102 .sleep_mask = BIT(__bit), \
103 .iso_reg = GX_AO_RTI_GEN_PWR_ISO0, \
104 .iso_mask = BIT(__bit), \
107 static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu
= SM1_EE_PD(8);
108 static struct meson_ee_pwrc_top_domain sm1_pwrc_nna
= SM1_EE_PD(16);
109 static struct meson_ee_pwrc_top_domain sm1_pwrc_usb
= SM1_EE_PD(17);
110 static struct meson_ee_pwrc_top_domain sm1_pwrc_pci
= SM1_EE_PD(18);
111 static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d
= SM1_EE_PD(19);
113 static struct meson_ee_pwrc_top_domain g12a_pwrc_nna
= {
114 .sleep_reg
= GX_AO_RTI_GEN_PWR_SLEEP0
,
115 .sleep_mask
= BIT(16) | BIT(17),
116 .iso_reg
= GX_AO_RTI_GEN_PWR_ISO0
,
117 .iso_mask
= BIT(16) | BIT(17),
120 static struct meson_ee_pwrc_top_domain g12a_pwrc_isp
= {
121 .sleep_reg
= GX_AO_RTI_GEN_PWR_SLEEP0
,
122 .sleep_mask
= BIT(18) | BIT(19),
123 .iso_reg
= GX_AO_RTI_GEN_PWR_ISO0
,
124 .iso_mask
= BIT(18) | BIT(19),
127 /* Memory PD Domains */
129 #define VPU_MEMPD(__reg) \
130 { __reg, GENMASK(1, 0) }, \
131 { __reg, GENMASK(3, 2) }, \
132 { __reg, GENMASK(5, 4) }, \
133 { __reg, GENMASK(7, 6) }, \
134 { __reg, GENMASK(9, 8) }, \
135 { __reg, GENMASK(11, 10) }, \
136 { __reg, GENMASK(13, 12) }, \
137 { __reg, GENMASK(15, 14) }, \
138 { __reg, GENMASK(17, 16) }, \
139 { __reg, GENMASK(19, 18) }, \
140 { __reg, GENMASK(21, 20) }, \
141 { __reg, GENMASK(23, 22) }, \
142 { __reg, GENMASK(25, 24) }, \
143 { __reg, GENMASK(27, 26) }, \
144 { __reg, GENMASK(29, 28) }, \
145 { __reg, GENMASK(31, 30) }
147 #define VPU_HHI_MEMPD(__reg) \
150 { __reg, BIT(10) }, \
151 { __reg, BIT(11) }, \
152 { __reg, BIT(12) }, \
153 { __reg, BIT(13) }, \
154 { __reg, BIT(14) }, \
157 static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu
[] = {
158 VPU_MEMPD(HHI_VPU_MEM_PD_REG0
),
159 VPU_HHI_MEMPD(HHI_MEM_PD_REG0
),
162 static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu
[] = {
163 VPU_MEMPD(HHI_VPU_MEM_PD_REG0
),
164 VPU_MEMPD(HHI_VPU_MEM_PD_REG1
),
165 VPU_MEMPD(HHI_VPU_MEM_PD_REG2
),
166 VPU_HHI_MEMPD(HHI_MEM_PD_REG0
),
169 static struct meson_ee_pwrc_mem_domain gxbb_pwrc_mem_vpu
[] = {
170 VPU_MEMPD(HHI_VPU_MEM_PD_REG0
),
171 VPU_MEMPD(HHI_VPU_MEM_PD_REG1
),
172 VPU_HHI_MEMPD(HHI_MEM_PD_REG0
),
175 static struct meson_ee_pwrc_mem_domain meson_pwrc_mem_eth
[] = {
176 { HHI_MEM_PD_REG0
, GENMASK(3, 2) },
179 static struct meson_ee_pwrc_mem_domain meson8_pwrc_audio_dsp_mem
[] = {
180 { HHI_MEM_PD_REG0
, GENMASK(1, 0) },
183 static struct meson_ee_pwrc_mem_domain meson8_pwrc_mem_vpu
[] = {
184 VPU_MEMPD(HHI_VPU_MEM_PD_REG0
),
185 VPU_MEMPD(HHI_VPU_MEM_PD_REG1
),
186 VPU_HHI_MEMPD(HHI_MEM_PD_REG0
),
189 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu
[] = {
190 VPU_MEMPD(HHI_VPU_MEM_PD_REG0
),
191 VPU_MEMPD(HHI_VPU_MEM_PD_REG1
),
192 VPU_MEMPD(HHI_VPU_MEM_PD_REG2
),
193 VPU_MEMPD(HHI_VPU_MEM_PD_REG3
),
194 { HHI_VPU_MEM_PD_REG4
, GENMASK(1, 0) },
195 { HHI_VPU_MEM_PD_REG4
, GENMASK(3, 2) },
196 { HHI_VPU_MEM_PD_REG4
, GENMASK(5, 4) },
197 { HHI_VPU_MEM_PD_REG4
, GENMASK(7, 6) },
198 VPU_HHI_MEMPD(HHI_MEM_PD_REG0
),
201 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna
[] = {
202 { HHI_NANOQ_MEM_PD_REG0
, 0xff },
203 { HHI_NANOQ_MEM_PD_REG1
, 0xff },
206 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb
[] = {
207 { HHI_MEM_PD_REG0
, GENMASK(31, 30) },
210 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie
[] = {
211 { HHI_MEM_PD_REG0
, GENMASK(29, 26) },
214 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d
[] = {
215 { HHI_MEM_PD_REG0
, GENMASK(25, 18) },
218 static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio
[] = {
219 { HHI_MEM_PD_REG0
, GENMASK(5, 4) },
222 static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio
[] = {
223 { HHI_MEM_PD_REG0
, GENMASK(5, 4) },
224 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(1, 0) },
225 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(3, 2) },
226 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(5, 4) },
227 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(7, 6) },
228 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(13, 12) },
229 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(15, 14) },
230 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(17, 16) },
231 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(19, 18) },
232 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(21, 20) },
233 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(23, 22) },
234 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(25, 24) },
235 { HHI_AUDIO_MEM_PD_REG0
, GENMASK(27, 26) },
238 static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_nna
[] = {
239 { G12A_HHI_NANOQ_MEM_PD_REG0
, GENMASK(31, 0) },
240 { G12A_HHI_NANOQ_MEM_PD_REG1
, GENMASK(31, 0) },
243 static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_isp
[] = {
244 { G12A_HHI_ISP_MEM_PD_REG0
, GENMASK(31, 0) },
245 { G12A_HHI_ISP_MEM_PD_REG1
, GENMASK(31, 0) },
248 #define VPU_PD(__name, __top_pd, __mem, __is_pwr_off, __resets, __clks) \
251 .reset_names_count = __resets, \
252 .clk_names_count = __clks, \
253 .top_pd = __top_pd, \
254 .mem_pd_count = ARRAY_SIZE(__mem), \
256 .is_powered_off = __is_pwr_off, \
259 #define TOP_PD(__name, __top_pd, __mem, __is_pwr_off) \
262 .top_pd = __top_pd, \
263 .mem_pd_count = ARRAY_SIZE(__mem), \
265 .is_powered_off = __is_pwr_off, \
268 #define MEM_PD(__name, __mem) \
269 TOP_PD(__name, NULL, __mem, NULL)
271 static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain
*pwrc_domain
);
273 static struct meson_ee_pwrc_domain_desc axg_pwrc_domains
[] = {
274 [PWRC_AXG_VPU_ID
] = VPU_PD("VPU", &gx_pwrc_vpu
, axg_pwrc_mem_vpu
,
275 pwrc_ee_is_powered_off
, 5, 2),
276 [PWRC_AXG_ETHERNET_MEM_ID
] = MEM_PD("ETH", meson_pwrc_mem_eth
),
277 [PWRC_AXG_AUDIO_ID
] = MEM_PD("AUDIO", axg_pwrc_mem_audio
),
280 static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains
[] = {
281 [PWRC_G12A_VPU_ID
] = VPU_PD("VPU", &gx_pwrc_vpu
, g12a_pwrc_mem_vpu
,
282 pwrc_ee_is_powered_off
, 11, 2),
283 [PWRC_G12A_ETH_ID
] = MEM_PD("ETH", meson_pwrc_mem_eth
),
284 [PWRC_G12A_NNA_ID
] = TOP_PD("NNA", &g12a_pwrc_nna
, g12a_pwrc_mem_nna
,
285 pwrc_ee_is_powered_off
),
286 [PWRC_G12A_ISP_ID
] = TOP_PD("ISP", &g12a_pwrc_isp
, g12a_pwrc_mem_isp
,
287 pwrc_ee_is_powered_off
),
290 static struct meson_ee_pwrc_domain_desc gxbb_pwrc_domains
[] = {
291 [PWRC_GXBB_VPU_ID
] = VPU_PD("VPU", &gx_pwrc_vpu
, gxbb_pwrc_mem_vpu
,
292 pwrc_ee_is_powered_off
, 12, 2),
293 [PWRC_GXBB_ETHERNET_MEM_ID
] = MEM_PD("ETH", meson_pwrc_mem_eth
),
296 static struct meson_ee_pwrc_domain_desc meson8_pwrc_domains
[] = {
297 [PWRC_MESON8_VPU_ID
] = VPU_PD("VPU", &meson8_pwrc_vpu
,
299 pwrc_ee_is_powered_off
, 0, 1),
300 [PWRC_MESON8_ETHERNET_MEM_ID
] = MEM_PD("ETHERNET_MEM",
302 [PWRC_MESON8_AUDIO_DSP_MEM_ID
] = MEM_PD("AUDIO_DSP_MEM",
303 meson8_pwrc_audio_dsp_mem
),
306 static struct meson_ee_pwrc_domain_desc meson8b_pwrc_domains
[] = {
307 [PWRC_MESON8_VPU_ID
] = VPU_PD("VPU", &meson8_pwrc_vpu
,
309 pwrc_ee_is_powered_off
, 11, 1),
310 [PWRC_MESON8_ETHERNET_MEM_ID
] = MEM_PD("ETHERNET_MEM",
312 [PWRC_MESON8_AUDIO_DSP_MEM_ID
] = MEM_PD("AUDIO_DSP_MEM",
313 meson8_pwrc_audio_dsp_mem
),
316 static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains
[] = {
317 [PWRC_SM1_VPU_ID
] = VPU_PD("VPU", &sm1_pwrc_vpu
, sm1_pwrc_mem_vpu
,
318 pwrc_ee_is_powered_off
, 11, 2),
319 [PWRC_SM1_NNA_ID
] = TOP_PD("NNA", &sm1_pwrc_nna
, sm1_pwrc_mem_nna
,
320 pwrc_ee_is_powered_off
),
321 [PWRC_SM1_USB_ID
] = TOP_PD("USB", &sm1_pwrc_usb
, sm1_pwrc_mem_usb
,
322 pwrc_ee_is_powered_off
),
323 [PWRC_SM1_PCIE_ID
] = TOP_PD("PCI", &sm1_pwrc_pci
, sm1_pwrc_mem_pcie
,
324 pwrc_ee_is_powered_off
),
325 [PWRC_SM1_GE2D_ID
] = TOP_PD("GE2D", &sm1_pwrc_ge2d
, sm1_pwrc_mem_ge2d
,
326 pwrc_ee_is_powered_off
),
327 [PWRC_SM1_AUDIO_ID
] = MEM_PD("AUDIO", sm1_pwrc_mem_audio
),
328 [PWRC_SM1_ETH_ID
] = MEM_PD("ETH", meson_pwrc_mem_eth
),
331 struct meson_ee_pwrc_domain
{
332 struct generic_pm_domain base
;
334 struct meson_ee_pwrc
*pwrc
;
335 struct meson_ee_pwrc_domain_desc desc
;
336 struct clk_bulk_data
*clks
;
338 struct reset_control
*rstc
;
342 struct meson_ee_pwrc
{
343 struct regmap
*regmap_ao
;
344 struct regmap
*regmap_hhi
;
345 struct meson_ee_pwrc_domain
*domains
;
346 struct genpd_onecell_data xlate
;
349 static bool pwrc_ee_is_powered_off(struct meson_ee_pwrc_domain
*pwrc_domain
)
353 regmap_read(pwrc_domain
->pwrc
->regmap_ao
,
354 pwrc_domain
->desc
.top_pd
->sleep_reg
, ®
);
356 return (reg
& pwrc_domain
->desc
.top_pd
->sleep_mask
);
359 static int meson_ee_pwrc_off(struct generic_pm_domain
*domain
)
361 struct meson_ee_pwrc_domain
*pwrc_domain
=
362 container_of(domain
, struct meson_ee_pwrc_domain
, base
);
365 if (pwrc_domain
->desc
.top_pd
)
366 regmap_update_bits(pwrc_domain
->pwrc
->regmap_ao
,
367 pwrc_domain
->desc
.top_pd
->sleep_reg
,
368 pwrc_domain
->desc
.top_pd
->sleep_mask
,
369 pwrc_domain
->desc
.top_pd
->sleep_mask
);
372 for (i
= 0 ; i
< pwrc_domain
->desc
.mem_pd_count
; ++i
)
373 regmap_update_bits(pwrc_domain
->pwrc
->regmap_hhi
,
374 pwrc_domain
->desc
.mem_pd
[i
].reg
,
375 pwrc_domain
->desc
.mem_pd
[i
].mask
,
376 pwrc_domain
->desc
.mem_pd
[i
].mask
);
380 if (pwrc_domain
->desc
.top_pd
)
381 regmap_update_bits(pwrc_domain
->pwrc
->regmap_ao
,
382 pwrc_domain
->desc
.top_pd
->iso_reg
,
383 pwrc_domain
->desc
.top_pd
->iso_mask
,
384 pwrc_domain
->desc
.top_pd
->iso_mask
);
386 if (pwrc_domain
->num_clks
) {
388 clk_bulk_disable_unprepare(pwrc_domain
->num_clks
,
395 static int meson_ee_pwrc_on(struct generic_pm_domain
*domain
)
397 struct meson_ee_pwrc_domain
*pwrc_domain
=
398 container_of(domain
, struct meson_ee_pwrc_domain
, base
);
401 if (pwrc_domain
->desc
.top_pd
)
402 regmap_update_bits(pwrc_domain
->pwrc
->regmap_ao
,
403 pwrc_domain
->desc
.top_pd
->sleep_reg
,
404 pwrc_domain
->desc
.top_pd
->sleep_mask
, 0);
407 for (i
= 0 ; i
< pwrc_domain
->desc
.mem_pd_count
; ++i
)
408 regmap_update_bits(pwrc_domain
->pwrc
->regmap_hhi
,
409 pwrc_domain
->desc
.mem_pd
[i
].reg
,
410 pwrc_domain
->desc
.mem_pd
[i
].mask
, 0);
414 ret
= reset_control_assert(pwrc_domain
->rstc
);
418 if (pwrc_domain
->desc
.top_pd
)
419 regmap_update_bits(pwrc_domain
->pwrc
->regmap_ao
,
420 pwrc_domain
->desc
.top_pd
->iso_reg
,
421 pwrc_domain
->desc
.top_pd
->iso_mask
, 0);
423 ret
= reset_control_deassert(pwrc_domain
->rstc
);
427 return clk_bulk_prepare_enable(pwrc_domain
->num_clks
,
431 static int meson_ee_pwrc_init_domain(struct platform_device
*pdev
,
432 struct meson_ee_pwrc
*pwrc
,
433 struct meson_ee_pwrc_domain
*dom
)
438 dom
->num_rstc
= dom
->desc
.reset_names_count
;
439 dom
->num_clks
= dom
->desc
.clk_names_count
;
442 int count
= reset_control_get_count(&pdev
->dev
);
444 if (count
!= dom
->num_rstc
)
445 dev_warn(&pdev
->dev
, "Invalid resets count %d for domain %s\n",
446 count
, dom
->desc
.name
);
448 dom
->rstc
= devm_reset_control_array_get_exclusive(&pdev
->dev
);
449 if (IS_ERR(dom
->rstc
))
450 return PTR_ERR(dom
->rstc
);
454 int ret
= devm_clk_bulk_get_all(&pdev
->dev
, &dom
->clks
);
458 if (dom
->num_clks
!= ret
) {
459 dev_warn(&pdev
->dev
, "Invalid clocks count %d for domain %s\n",
460 ret
, dom
->desc
.name
);
465 dom
->base
.name
= dom
->desc
.name
;
466 dom
->base
.power_on
= meson_ee_pwrc_on
;
467 dom
->base
.power_off
= meson_ee_pwrc_off
;
470 * TOFIX: This is a special case for the VPU power domain, which can
471 * be enabled previously by the bootloader. In this case the VPU
472 * pipeline may be functional but no driver maybe never attach
473 * to this power domain, and if the domain is disabled it could
474 * cause system errors. This is why the pm_domain_always_on_gov
476 * For the same reason, the clocks should be enabled in case
477 * we need to power the domain off, otherwise the internal clocks
478 * prepare/enable counters won't be in sync.
480 if (dom
->num_clks
&& dom
->desc
.is_powered_off
&& !dom
->desc
.is_powered_off(dom
)) {
481 ret
= clk_bulk_prepare_enable(dom
->num_clks
, dom
->clks
);
485 dom
->base
.flags
= GENPD_FLAG_ALWAYS_ON
;
486 ret
= pm_genpd_init(&dom
->base
, NULL
, false);
490 ret
= pm_genpd_init(&dom
->base
, NULL
,
491 (dom
->desc
.is_powered_off
?
492 dom
->desc
.is_powered_off(dom
) : true));
500 static int meson_ee_pwrc_probe(struct platform_device
*pdev
)
502 const struct meson_ee_pwrc_domain_data
*match
;
503 struct regmap
*regmap_ao
, *regmap_hhi
;
504 struct device_node
*parent_np
;
505 struct meson_ee_pwrc
*pwrc
;
508 match
= of_device_get_match_data(&pdev
->dev
);
510 dev_err(&pdev
->dev
, "failed to get match data\n");
514 pwrc
= devm_kzalloc(&pdev
->dev
, sizeof(*pwrc
), GFP_KERNEL
);
518 pwrc
->xlate
.domains
= devm_kcalloc(&pdev
->dev
, match
->count
,
519 sizeof(*pwrc
->xlate
.domains
),
521 if (!pwrc
->xlate
.domains
)
524 pwrc
->domains
= devm_kcalloc(&pdev
->dev
, match
->count
,
525 sizeof(*pwrc
->domains
), GFP_KERNEL
);
529 pwrc
->xlate
.num_domains
= match
->count
;
531 parent_np
= of_get_parent(pdev
->dev
.of_node
);
532 regmap_hhi
= syscon_node_to_regmap(parent_np
);
533 of_node_put(parent_np
);
534 if (IS_ERR(regmap_hhi
)) {
535 dev_err(&pdev
->dev
, "failed to get HHI regmap\n");
536 return PTR_ERR(regmap_hhi
);
539 regmap_ao
= syscon_regmap_lookup_by_phandle(pdev
->dev
.of_node
,
540 "amlogic,ao-sysctrl");
541 if (IS_ERR(regmap_ao
)) {
542 dev_err(&pdev
->dev
, "failed to get AO regmap\n");
543 return PTR_ERR(regmap_ao
);
546 pwrc
->regmap_ao
= regmap_ao
;
547 pwrc
->regmap_hhi
= regmap_hhi
;
549 platform_set_drvdata(pdev
, pwrc
);
551 for (i
= 0 ; i
< match
->count
; ++i
) {
552 struct meson_ee_pwrc_domain
*dom
= &pwrc
->domains
[i
];
554 memcpy(&dom
->desc
, &match
->domains
[i
], sizeof(dom
->desc
));
556 ret
= meson_ee_pwrc_init_domain(pdev
, pwrc
, dom
);
560 pwrc
->xlate
.domains
[i
] = &dom
->base
;
563 return of_genpd_add_provider_onecell(pdev
->dev
.of_node
, &pwrc
->xlate
);
566 static void meson_ee_pwrc_shutdown(struct platform_device
*pdev
)
568 struct meson_ee_pwrc
*pwrc
= platform_get_drvdata(pdev
);
571 for (i
= 0 ; i
< pwrc
->xlate
.num_domains
; ++i
) {
572 struct meson_ee_pwrc_domain
*dom
= &pwrc
->domains
[i
];
574 if (dom
->desc
.is_powered_off
&& !dom
->desc
.is_powered_off(dom
))
575 meson_ee_pwrc_off(&dom
->base
);
579 static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data
= {
580 .count
= ARRAY_SIZE(g12a_pwrc_domains
),
581 .domains
= g12a_pwrc_domains
,
584 static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data
= {
585 .count
= ARRAY_SIZE(axg_pwrc_domains
),
586 .domains
= axg_pwrc_domains
,
589 static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data
= {
590 .count
= ARRAY_SIZE(gxbb_pwrc_domains
),
591 .domains
= gxbb_pwrc_domains
,
594 static struct meson_ee_pwrc_domain_data meson_ee_m8_pwrc_data
= {
595 .count
= ARRAY_SIZE(meson8_pwrc_domains
),
596 .domains
= meson8_pwrc_domains
,
599 static struct meson_ee_pwrc_domain_data meson_ee_m8b_pwrc_data
= {
600 .count
= ARRAY_SIZE(meson8b_pwrc_domains
),
601 .domains
= meson8b_pwrc_domains
,
604 static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data
= {
605 .count
= ARRAY_SIZE(sm1_pwrc_domains
),
606 .domains
= sm1_pwrc_domains
,
609 static const struct of_device_id meson_ee_pwrc_match_table
[] = {
611 .compatible
= "amlogic,meson8-pwrc",
612 .data
= &meson_ee_m8_pwrc_data
,
615 .compatible
= "amlogic,meson8b-pwrc",
616 .data
= &meson_ee_m8b_pwrc_data
,
619 .compatible
= "amlogic,meson8m2-pwrc",
620 .data
= &meson_ee_m8b_pwrc_data
,
623 .compatible
= "amlogic,meson-axg-pwrc",
624 .data
= &meson_ee_axg_pwrc_data
,
627 .compatible
= "amlogic,meson-gxbb-pwrc",
628 .data
= &meson_ee_gxbb_pwrc_data
,
631 .compatible
= "amlogic,meson-g12a-pwrc",
632 .data
= &meson_ee_g12a_pwrc_data
,
635 .compatible
= "amlogic,meson-sm1-pwrc",
636 .data
= &meson_ee_sm1_pwrc_data
,
640 MODULE_DEVICE_TABLE(of
, meson_ee_pwrc_match_table
);
642 static struct platform_driver meson_ee_pwrc_driver
= {
643 .probe
= meson_ee_pwrc_probe
,
644 .shutdown
= meson_ee_pwrc_shutdown
,
646 .name
= "meson_ee_pwrc",
647 .of_match_table
= meson_ee_pwrc_match_table
,
650 module_platform_driver(meson_ee_pwrc_driver
);
651 MODULE_DESCRIPTION("Amlogic Meson Everything-Else Power Domains driver");
652 MODULE_LICENSE("GPL v2");