Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: amlogic: Add support for Everything-Else power domains controller

Add support for the General Purpose Amlogic Everything-Else Power controller,
with the first support for G12A and SM1 SoCs dedicated to the VPU, PCIe,
USB, NNA, GE2D and Ethernet Power Domains.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Kevin Hilman <khilman@baylibre.com>
Tested-by: Kevin Hilman <khilman@baylibre.com>
Signed-off-by: Kevin Hilman <khilman@baylibre.com>

authored by

Neil Armstrong and committed by
Kevin Hilman
eef3c2ba 49ed86f5

+504
+11
drivers/soc/amlogic/Kconfig
··· 37 37 Say yes to expose Amlogic Meson GX Power Domains as 38 38 Generic Power Domains. 39 39 40 + config MESON_EE_PM_DOMAINS 41 + bool "Amlogic Meson Everything-Else Power Domains driver" 42 + depends on ARCH_MESON || COMPILE_TEST 43 + depends on PM && OF 44 + default ARCH_MESON 45 + select PM_GENERIC_DOMAINS 46 + select PM_GENERIC_DOMAINS_OF 47 + help 48 + Say yes to expose Amlogic Meson Everything-Else Power Domains as 49 + Generic Power Domains. 50 + 40 51 config MESON_MX_SOCINFO 41 52 bool "Amlogic Meson MX SoC Information driver" 42 53 depends on ARCH_MESON || COMPILE_TEST
+1
drivers/soc/amlogic/Makefile
··· 4 4 obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o 5 5 obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o 6 6 obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o 7 + obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o
+492
drivers/soc/amlogic/meson-ee-pwrc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Copyright (c) 2019 BayLibre, SAS 4 + * Author: Neil Armstrong <narmstrong@baylibre.com> 5 + */ 6 + 7 + #include <linux/of_address.h> 8 + #include <linux/platform_device.h> 9 + #include <linux/pm_domain.h> 10 + #include <linux/bitfield.h> 11 + #include <linux/regmap.h> 12 + #include <linux/mfd/syscon.h> 13 + #include <linux/of_device.h> 14 + #include <linux/reset-controller.h> 15 + #include <linux/reset.h> 16 + #include <linux/clk.h> 17 + #include <dt-bindings/power/meson-g12a-power.h> 18 + #include <dt-bindings/power/meson-sm1-power.h> 19 + 20 + /* AO Offsets */ 21 + 22 + #define AO_RTI_GEN_PWR_SLEEP0 (0x3a << 2) 23 + #define AO_RTI_GEN_PWR_ISO0 (0x3b << 2) 24 + 25 + /* HHI Offsets */ 26 + 27 + #define HHI_MEM_PD_REG0 (0x40 << 2) 28 + #define HHI_VPU_MEM_PD_REG0 (0x41 << 2) 29 + #define HHI_VPU_MEM_PD_REG1 (0x42 << 2) 30 + #define HHI_VPU_MEM_PD_REG3 (0x43 << 2) 31 + #define HHI_VPU_MEM_PD_REG4 (0x44 << 2) 32 + #define HHI_AUDIO_MEM_PD_REG0 (0x45 << 2) 33 + #define HHI_NANOQ_MEM_PD_REG0 (0x46 << 2) 34 + #define HHI_NANOQ_MEM_PD_REG1 (0x47 << 2) 35 + #define HHI_VPU_MEM_PD_REG2 (0x4d << 2) 36 + 37 + struct meson_ee_pwrc; 38 + struct meson_ee_pwrc_domain; 39 + 40 + struct meson_ee_pwrc_mem_domain { 41 + unsigned int reg; 42 + unsigned int mask; 43 + }; 44 + 45 + struct meson_ee_pwrc_top_domain { 46 + unsigned int sleep_reg; 47 + unsigned int sleep_mask; 48 + unsigned int iso_reg; 49 + unsigned int iso_mask; 50 + }; 51 + 52 + struct meson_ee_pwrc_domain_desc { 53 + char *name; 54 + unsigned int reset_names_count; 55 + unsigned int clk_names_count; 56 + struct meson_ee_pwrc_top_domain *top_pd; 57 + unsigned int mem_pd_count; 58 + struct meson_ee_pwrc_mem_domain *mem_pd; 59 + bool (*get_power)(struct meson_ee_pwrc_domain *pwrc_domain); 60 + }; 61 + 62 + struct meson_ee_pwrc_domain_data { 63 + unsigned int count; 64 + struct meson_ee_pwrc_domain_desc *domains; 65 + }; 66 + 67 + /* TOP Power Domains */ 68 + 69 + static struct meson_ee_pwrc_top_domain g12a_pwrc_vpu = { 70 + .sleep_reg = AO_RTI_GEN_PWR_SLEEP0, 71 + .sleep_mask = BIT(8), 72 + .iso_reg = AO_RTI_GEN_PWR_SLEEP0, 73 + .iso_mask = BIT(9), 74 + }; 75 + 76 + #define SM1_EE_PD(__bit) \ 77 + { \ 78 + .sleep_reg = AO_RTI_GEN_PWR_SLEEP0, \ 79 + .sleep_mask = BIT(__bit), \ 80 + .iso_reg = AO_RTI_GEN_PWR_ISO0, \ 81 + .iso_mask = BIT(__bit), \ 82 + } 83 + 84 + static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8); 85 + static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16); 86 + static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17); 87 + static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18); 88 + static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19); 89 + 90 + /* Memory PD Domains */ 91 + 92 + #define VPU_MEMPD(__reg) \ 93 + { __reg, GENMASK(1, 0) }, \ 94 + { __reg, GENMASK(3, 2) }, \ 95 + { __reg, GENMASK(5, 4) }, \ 96 + { __reg, GENMASK(7, 6) }, \ 97 + { __reg, GENMASK(9, 8) }, \ 98 + { __reg, GENMASK(11, 10) }, \ 99 + { __reg, GENMASK(13, 12) }, \ 100 + { __reg, GENMASK(15, 14) }, \ 101 + { __reg, GENMASK(17, 16) }, \ 102 + { __reg, GENMASK(19, 18) }, \ 103 + { __reg, GENMASK(21, 20) }, \ 104 + { __reg, GENMASK(23, 22) }, \ 105 + { __reg, GENMASK(25, 24) }, \ 106 + { __reg, GENMASK(27, 26) }, \ 107 + { __reg, GENMASK(29, 28) }, \ 108 + { __reg, GENMASK(31, 30) } 109 + 110 + #define VPU_HHI_MEMPD(__reg) \ 111 + { __reg, BIT(8) }, \ 112 + { __reg, BIT(9) }, \ 113 + { __reg, BIT(10) }, \ 114 + { __reg, BIT(11) }, \ 115 + { __reg, BIT(12) }, \ 116 + { __reg, BIT(13) }, \ 117 + { __reg, BIT(14) }, \ 118 + { __reg, BIT(15) } 119 + 120 + static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = { 121 + VPU_MEMPD(HHI_VPU_MEM_PD_REG0), 122 + VPU_MEMPD(HHI_VPU_MEM_PD_REG1), 123 + VPU_MEMPD(HHI_VPU_MEM_PD_REG2), 124 + VPU_HHI_MEMPD(HHI_MEM_PD_REG0), 125 + }; 126 + 127 + static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_eth[] = { 128 + { HHI_MEM_PD_REG0, GENMASK(3, 2) }, 129 + }; 130 + 131 + static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = { 132 + VPU_MEMPD(HHI_VPU_MEM_PD_REG0), 133 + VPU_MEMPD(HHI_VPU_MEM_PD_REG1), 134 + VPU_MEMPD(HHI_VPU_MEM_PD_REG2), 135 + VPU_MEMPD(HHI_VPU_MEM_PD_REG3), 136 + { HHI_VPU_MEM_PD_REG4, GENMASK(1, 0) }, 137 + { HHI_VPU_MEM_PD_REG4, GENMASK(3, 2) }, 138 + { HHI_VPU_MEM_PD_REG4, GENMASK(5, 4) }, 139 + { HHI_VPU_MEM_PD_REG4, GENMASK(7, 6) }, 140 + VPU_HHI_MEMPD(HHI_MEM_PD_REG0), 141 + }; 142 + 143 + static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = { 144 + { HHI_NANOQ_MEM_PD_REG0, 0xff }, 145 + { HHI_NANOQ_MEM_PD_REG1, 0xff }, 146 + }; 147 + 148 + static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = { 149 + { HHI_MEM_PD_REG0, GENMASK(31, 30) }, 150 + }; 151 + 152 + static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = { 153 + { HHI_MEM_PD_REG0, GENMASK(29, 26) }, 154 + }; 155 + 156 + static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = { 157 + { HHI_MEM_PD_REG0, GENMASK(25, 18) }, 158 + }; 159 + 160 + static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = { 161 + { HHI_MEM_PD_REG0, GENMASK(5, 4) }, 162 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) }, 163 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) }, 164 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(5, 4) }, 165 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(7, 6) }, 166 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(13, 12) }, 167 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(15, 14) }, 168 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(17, 16) }, 169 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(19, 18) }, 170 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(21, 20) }, 171 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(23, 22) }, 172 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(25, 24) }, 173 + { HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) }, 174 + }; 175 + 176 + #define VPU_PD(__name, __top_pd, __mem, __get_power, __resets, __clks) \ 177 + { \ 178 + .name = __name, \ 179 + .reset_names_count = __resets, \ 180 + .clk_names_count = __clks, \ 181 + .top_pd = __top_pd, \ 182 + .mem_pd_count = ARRAY_SIZE(__mem), \ 183 + .mem_pd = __mem, \ 184 + .get_power = __get_power, \ 185 + } 186 + 187 + #define TOP_PD(__name, __top_pd, __mem, __get_power) \ 188 + { \ 189 + .name = __name, \ 190 + .top_pd = __top_pd, \ 191 + .mem_pd_count = ARRAY_SIZE(__mem), \ 192 + .mem_pd = __mem, \ 193 + .get_power = __get_power, \ 194 + } 195 + 196 + #define MEM_PD(__name, __mem) \ 197 + TOP_PD(__name, NULL, __mem, NULL) 198 + 199 + static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain); 200 + 201 + static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = { 202 + [PWRC_G12A_VPU_ID] = VPU_PD("VPU", &g12a_pwrc_vpu, g12a_pwrc_mem_vpu, 203 + pwrc_ee_get_power, 11, 2), 204 + [PWRC_G12A_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth), 205 + }; 206 + 207 + static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = { 208 + [PWRC_SM1_VPU_ID] = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu, 209 + pwrc_ee_get_power, 11, 2), 210 + [PWRC_SM1_NNA_ID] = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna, 211 + pwrc_ee_get_power), 212 + [PWRC_SM1_USB_ID] = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb, 213 + pwrc_ee_get_power), 214 + [PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie, 215 + pwrc_ee_get_power), 216 + [PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d, 217 + pwrc_ee_get_power), 218 + [PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio), 219 + [PWRC_SM1_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth), 220 + }; 221 + 222 + struct meson_ee_pwrc_domain { 223 + struct generic_pm_domain base; 224 + bool enabled; 225 + struct meson_ee_pwrc *pwrc; 226 + struct meson_ee_pwrc_domain_desc desc; 227 + struct clk_bulk_data *clks; 228 + int num_clks; 229 + struct reset_control *rstc; 230 + int num_rstc; 231 + }; 232 + 233 + struct meson_ee_pwrc { 234 + struct regmap *regmap_ao; 235 + struct regmap *regmap_hhi; 236 + struct meson_ee_pwrc_domain *domains; 237 + struct genpd_onecell_data xlate; 238 + }; 239 + 240 + static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain) 241 + { 242 + u32 reg; 243 + 244 + regmap_read(pwrc_domain->pwrc->regmap_ao, 245 + pwrc_domain->desc.top_pd->sleep_reg, &reg); 246 + 247 + return (reg & pwrc_domain->desc.top_pd->sleep_mask); 248 + } 249 + 250 + static int meson_ee_pwrc_off(struct generic_pm_domain *domain) 251 + { 252 + struct meson_ee_pwrc_domain *pwrc_domain = 253 + container_of(domain, struct meson_ee_pwrc_domain, base); 254 + int i; 255 + 256 + if (pwrc_domain->desc.top_pd) 257 + regmap_update_bits(pwrc_domain->pwrc->regmap_ao, 258 + pwrc_domain->desc.top_pd->sleep_reg, 259 + pwrc_domain->desc.top_pd->sleep_mask, 260 + pwrc_domain->desc.top_pd->sleep_mask); 261 + udelay(20); 262 + 263 + for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i) 264 + regmap_update_bits(pwrc_domain->pwrc->regmap_hhi, 265 + pwrc_domain->desc.mem_pd[i].reg, 266 + pwrc_domain->desc.mem_pd[i].mask, 267 + pwrc_domain->desc.mem_pd[i].mask); 268 + 269 + udelay(20); 270 + 271 + if (pwrc_domain->desc.top_pd) 272 + regmap_update_bits(pwrc_domain->pwrc->regmap_ao, 273 + pwrc_domain->desc.top_pd->iso_reg, 274 + pwrc_domain->desc.top_pd->iso_mask, 275 + pwrc_domain->desc.top_pd->iso_mask); 276 + 277 + if (pwrc_domain->num_clks) { 278 + msleep(20); 279 + clk_bulk_disable_unprepare(pwrc_domain->num_clks, 280 + pwrc_domain->clks); 281 + } 282 + 283 + return 0; 284 + } 285 + 286 + static int meson_ee_pwrc_on(struct generic_pm_domain *domain) 287 + { 288 + struct meson_ee_pwrc_domain *pwrc_domain = 289 + container_of(domain, struct meson_ee_pwrc_domain, base); 290 + int i, ret; 291 + 292 + if (pwrc_domain->desc.top_pd) 293 + regmap_update_bits(pwrc_domain->pwrc->regmap_ao, 294 + pwrc_domain->desc.top_pd->sleep_reg, 295 + pwrc_domain->desc.top_pd->sleep_mask, 0); 296 + udelay(20); 297 + 298 + for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i) 299 + regmap_update_bits(pwrc_domain->pwrc->regmap_hhi, 300 + pwrc_domain->desc.mem_pd[i].reg, 301 + pwrc_domain->desc.mem_pd[i].mask, 0); 302 + 303 + udelay(20); 304 + 305 + ret = reset_control_assert(pwrc_domain->rstc); 306 + if (ret) 307 + return ret; 308 + 309 + if (pwrc_domain->desc.top_pd) 310 + regmap_update_bits(pwrc_domain->pwrc->regmap_ao, 311 + pwrc_domain->desc.top_pd->iso_reg, 312 + pwrc_domain->desc.top_pd->iso_mask, 0); 313 + 314 + ret = reset_control_deassert(pwrc_domain->rstc); 315 + if (ret) 316 + return ret; 317 + 318 + return clk_bulk_prepare_enable(pwrc_domain->num_clks, 319 + pwrc_domain->clks); 320 + } 321 + 322 + static int meson_ee_pwrc_init_domain(struct platform_device *pdev, 323 + struct meson_ee_pwrc *pwrc, 324 + struct meson_ee_pwrc_domain *dom) 325 + { 326 + dom->pwrc = pwrc; 327 + dom->num_rstc = dom->desc.reset_names_count; 328 + dom->num_clks = dom->desc.clk_names_count; 329 + 330 + if (dom->num_rstc) { 331 + int count = reset_control_get_count(&pdev->dev); 332 + 333 + if (count != dom->num_rstc) 334 + dev_warn(&pdev->dev, "Invalid resets count %d for domain %s\n", 335 + count, dom->desc.name); 336 + 337 + dom->rstc = devm_reset_control_array_get(&pdev->dev, false, 338 + false); 339 + if (IS_ERR(dom->rstc)) 340 + return PTR_ERR(dom->rstc); 341 + } 342 + 343 + if (dom->num_clks) { 344 + int ret = devm_clk_bulk_get_all(&pdev->dev, &dom->clks); 345 + if (ret < 0) 346 + return ret; 347 + 348 + if (dom->num_clks != ret) { 349 + dev_warn(&pdev->dev, "Invalid clocks count %d for domain %s\n", 350 + ret, dom->desc.name); 351 + dom->num_clks = ret; 352 + } 353 + } 354 + 355 + dom->base.name = dom->desc.name; 356 + dom->base.power_on = meson_ee_pwrc_on; 357 + dom->base.power_off = meson_ee_pwrc_off; 358 + 359 + /* 360 + * TOFIX: This is a special case for the VPU power domain, which can 361 + * be enabled previously by the bootloader. In this case the VPU 362 + * pipeline may be functional but no driver maybe never attach 363 + * to this power domain, and if the domain is disabled it could 364 + * cause system errors. This is why the pm_domain_always_on_gov 365 + * is used here. 366 + * For the same reason, the clocks should be enabled in case 367 + * we need to power the domain off, otherwise the internal clocks 368 + * prepare/enable counters won't be in sync. 369 + */ 370 + if (dom->num_clks && dom->desc.get_power && !dom->desc.get_power(dom)) { 371 + int ret = clk_bulk_prepare_enable(dom->num_clks, dom->clks); 372 + if (ret) 373 + return ret; 374 + 375 + pm_genpd_init(&dom->base, &pm_domain_always_on_gov, false); 376 + } else 377 + pm_genpd_init(&dom->base, NULL, 378 + (dom->desc.get_power ? 379 + dom->desc.get_power(dom) : true)); 380 + 381 + return 0; 382 + } 383 + 384 + static int meson_ee_pwrc_probe(struct platform_device *pdev) 385 + { 386 + const struct meson_ee_pwrc_domain_data *match; 387 + struct regmap *regmap_ao, *regmap_hhi; 388 + struct meson_ee_pwrc *pwrc; 389 + int i, ret; 390 + 391 + match = of_device_get_match_data(&pdev->dev); 392 + if (!match) { 393 + dev_err(&pdev->dev, "failed to get match data\n"); 394 + return -ENODEV; 395 + } 396 + 397 + pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL); 398 + if (!pwrc) 399 + return -ENOMEM; 400 + 401 + pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count, 402 + sizeof(*pwrc->xlate.domains), 403 + GFP_KERNEL); 404 + if (!pwrc->xlate.domains) 405 + return -ENOMEM; 406 + 407 + pwrc->domains = devm_kcalloc(&pdev->dev, match->count, 408 + sizeof(*pwrc->domains), GFP_KERNEL); 409 + if (!pwrc->domains) 410 + return -ENOMEM; 411 + 412 + pwrc->xlate.num_domains = match->count; 413 + 414 + regmap_hhi = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node)); 415 + if (IS_ERR(regmap_hhi)) { 416 + dev_err(&pdev->dev, "failed to get HHI regmap\n"); 417 + return PTR_ERR(regmap_hhi); 418 + } 419 + 420 + regmap_ao = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 421 + "amlogic,ao-sysctrl"); 422 + if (IS_ERR(regmap_ao)) { 423 + dev_err(&pdev->dev, "failed to get AO regmap\n"); 424 + return PTR_ERR(regmap_ao); 425 + } 426 + 427 + pwrc->regmap_ao = regmap_ao; 428 + pwrc->regmap_hhi = regmap_hhi; 429 + 430 + platform_set_drvdata(pdev, pwrc); 431 + 432 + for (i = 0 ; i < match->count ; ++i) { 433 + struct meson_ee_pwrc_domain *dom = &pwrc->domains[i]; 434 + 435 + memcpy(&dom->desc, &match->domains[i], sizeof(dom->desc)); 436 + 437 + ret = meson_ee_pwrc_init_domain(pdev, pwrc, dom); 438 + if (ret) 439 + return ret; 440 + 441 + pwrc->xlate.domains[i] = &dom->base; 442 + } 443 + 444 + of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate); 445 + 446 + return 0; 447 + } 448 + 449 + static void meson_ee_pwrc_shutdown(struct platform_device *pdev) 450 + { 451 + struct meson_ee_pwrc *pwrc = platform_get_drvdata(pdev); 452 + int i; 453 + 454 + for (i = 0 ; i < pwrc->xlate.num_domains ; ++i) { 455 + struct meson_ee_pwrc_domain *dom = &pwrc->domains[i]; 456 + 457 + if (dom->desc.get_power && !dom->desc.get_power(dom)) 458 + meson_ee_pwrc_off(&dom->base); 459 + } 460 + } 461 + 462 + static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = { 463 + .count = ARRAY_SIZE(g12a_pwrc_domains), 464 + .domains = g12a_pwrc_domains, 465 + }; 466 + 467 + static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = { 468 + .count = ARRAY_SIZE(sm1_pwrc_domains), 469 + .domains = sm1_pwrc_domains, 470 + }; 471 + 472 + static const struct of_device_id meson_ee_pwrc_match_table[] = { 473 + { 474 + .compatible = "amlogic,meson-g12a-pwrc", 475 + .data = &meson_ee_g12a_pwrc_data, 476 + }, 477 + { 478 + .compatible = "amlogic,meson-sm1-pwrc", 479 + .data = &meson_ee_sm1_pwrc_data, 480 + }, 481 + { /* sentinel */ } 482 + }; 483 + 484 + static struct platform_driver meson_ee_pwrc_driver = { 485 + .probe = meson_ee_pwrc_probe, 486 + .shutdown = meson_ee_pwrc_shutdown, 487 + .driver = { 488 + .name = "meson_ee_pwrc", 489 + .of_match_table = meson_ee_pwrc_match_table, 490 + }, 491 + }; 492 + builtin_platform_driver(meson_ee_pwrc_driver);