bcm2835-power.c (17776B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Power domain driver for Broadcom BCM2835 4 * 5 * Copyright (C) 2018 Broadcom 6 */ 7 8#include <dt-bindings/soc/bcm2835-pm.h> 9#include <linux/clk.h> 10#include <linux/delay.h> 11#include <linux/io.h> 12#include <linux/mfd/bcm2835-pm.h> 13#include <linux/module.h> 14#include <linux/platform_device.h> 15#include <linux/pm_domain.h> 16#include <linux/reset-controller.h> 17#include <linux/types.h> 18 19#define PM_GNRIC 0x00 20#define PM_AUDIO 0x04 21#define PM_STATUS 0x18 22#define PM_RSTC 0x1c 23#define PM_RSTS 0x20 24#define PM_WDOG 0x24 25#define PM_PADS0 0x28 26#define PM_PADS2 0x2c 27#define PM_PADS3 0x30 28#define PM_PADS4 0x34 29#define PM_PADS5 0x38 30#define PM_PADS6 0x3c 31#define PM_CAM0 0x44 32#define PM_CAM0_LDOHPEN BIT(2) 33#define PM_CAM0_LDOLPEN BIT(1) 34#define PM_CAM0_CTRLEN BIT(0) 35 36#define PM_CAM1 0x48 37#define PM_CAM1_LDOHPEN BIT(2) 38#define PM_CAM1_LDOLPEN BIT(1) 39#define PM_CAM1_CTRLEN BIT(0) 40 41#define PM_CCP2TX 0x4c 42#define PM_CCP2TX_LDOEN BIT(1) 43#define PM_CCP2TX_CTRLEN BIT(0) 44 45#define PM_DSI0 0x50 46#define PM_DSI0_LDOHPEN BIT(2) 47#define PM_DSI0_LDOLPEN BIT(1) 48#define PM_DSI0_CTRLEN BIT(0) 49 50#define PM_DSI1 0x54 51#define PM_DSI1_LDOHPEN BIT(2) 52#define PM_DSI1_LDOLPEN BIT(1) 53#define PM_DSI1_CTRLEN BIT(0) 54 55#define PM_HDMI 0x58 56#define PM_HDMI_RSTDR BIT(19) 57#define PM_HDMI_LDOPD BIT(1) 58#define PM_HDMI_CTRLEN BIT(0) 59 60#define PM_USB 0x5c 61/* The power gates must be enabled with this bit before enabling the LDO in the 62 * USB block. 63 */ 64#define PM_USB_CTRLEN BIT(0) 65 66#define PM_PXLDO 0x60 67#define PM_PXBG 0x64 68#define PM_DFT 0x68 69#define PM_SMPS 0x6c 70#define PM_XOSC 0x70 71#define PM_SPAREW 0x74 72#define PM_SPARER 0x78 73#define PM_AVS_RSTDR 0x7c 74#define PM_AVS_STAT 0x80 75#define PM_AVS_EVENT 0x84 76#define PM_AVS_INTEN 0x88 77#define PM_DUMMY 0xfc 78 79#define PM_IMAGE 0x108 80#define PM_GRAFX 0x10c 81#define PM_PROC 0x110 82#define PM_ENAB BIT(12) 83#define PM_ISPRSTN BIT(8) 84#define PM_H264RSTN BIT(7) 85#define PM_PERIRSTN BIT(6) 86#define PM_V3DRSTN BIT(6) 87#define PM_ISFUNC BIT(5) 88#define PM_MRDONE BIT(4) 89#define PM_MEMREP BIT(3) 90#define PM_ISPOW BIT(2) 91#define PM_POWOK BIT(1) 92#define PM_POWUP BIT(0) 93#define PM_INRUSH_SHIFT 13 94#define PM_INRUSH_3_5_MA 0 95#define PM_INRUSH_5_MA 1 96#define PM_INRUSH_10_MA 2 97#define PM_INRUSH_20_MA 3 98#define PM_INRUSH_MASK (3 << PM_INRUSH_SHIFT) 99 100#define PM_PASSWORD 0x5a000000 101 102#define PM_WDOG_TIME_SET 0x000fffff 103#define PM_RSTC_WRCFG_CLR 0xffffffcf 104#define PM_RSTS_HADWRH_SET 0x00000040 105#define PM_RSTC_WRCFG_SET 0x00000030 106#define PM_RSTC_WRCFG_FULL_RESET 0x00000020 107#define PM_RSTC_RESET 0x00000102 108 109#define PM_READ(reg) readl(power->base + (reg)) 110#define PM_WRITE(reg, val) writel(PM_PASSWORD | (val), power->base + (reg)) 111 112#define ASB_BRDG_VERSION 0x00 113#define ASB_CPR_CTRL 0x04 114 115#define ASB_V3D_S_CTRL 0x08 116#define ASB_V3D_M_CTRL 0x0c 117#define ASB_ISP_S_CTRL 0x10 118#define ASB_ISP_M_CTRL 0x14 119#define ASB_H264_S_CTRL 0x18 120#define ASB_H264_M_CTRL 0x1c 121 122#define ASB_REQ_STOP BIT(0) 123#define ASB_ACK BIT(1) 124#define ASB_EMPTY BIT(2) 125#define ASB_FULL BIT(3) 126 127#define ASB_AXI_BRDG_ID 0x20 128 129#define ASB_READ(reg) readl(power->asb + (reg)) 130#define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg)) 131 132struct bcm2835_power_domain { 133 struct generic_pm_domain base; 134 struct bcm2835_power *power; 135 u32 domain; 136 struct clk *clk; 137}; 138 139struct bcm2835_power { 140 struct device *dev; 141 /* PM registers. */ 142 void __iomem *base; 143 /* AXI Async bridge registers. */ 144 void __iomem *asb; 145 146 struct genpd_onecell_data pd_xlate; 147 struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT]; 148 struct reset_controller_dev reset; 149}; 150 151static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) 152{ 153 u64 start; 154 155 if (!reg) 156 return 0; 157 158 start = ktime_get_ns(); 159 160 /* Enable the module's async AXI bridges. */ 161 ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP); 162 while (ASB_READ(reg) & ASB_ACK) { 163 cpu_relax(); 164 if (ktime_get_ns() - start >= 1000) 165 return -ETIMEDOUT; 166 } 167 168 return 0; 169} 170 171static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg) 172{ 173 u64 start; 174 175 if (!reg) 176 return 0; 177 178 start = ktime_get_ns(); 179 180 /* Enable the module's async AXI bridges. */ 181 ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP); 182 while (!(ASB_READ(reg) & ASB_ACK)) { 183 cpu_relax(); 184 if (ktime_get_ns() - start >= 1000) 185 return -ETIMEDOUT; 186 } 187 188 return 0; 189} 190 191static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg) 192{ 193 struct bcm2835_power *power = pd->power; 194 195 /* Enable functional isolation */ 196 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC); 197 198 /* Enable electrical isolation */ 199 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW); 200 201 /* Open the power switches. */ 202 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_POWUP); 203 204 return 0; 205} 206 207static int bcm2835_power_power_on(struct bcm2835_power_domain *pd, u32 pm_reg) 208{ 209 struct bcm2835_power *power = pd->power; 210 struct device *dev = power->dev; 211 u64 start; 212 int ret; 213 int inrush; 214 bool powok; 215 216 /* If it was already powered on by the fw, leave it that way. */ 217 if (PM_READ(pm_reg) & PM_POWUP) 218 return 0; 219 220 /* Enable power. Allowing too much current at once may result 221 * in POWOK never getting set, so start low and ramp it up as 222 * necessary to succeed. 223 */ 224 powok = false; 225 for (inrush = PM_INRUSH_3_5_MA; inrush <= PM_INRUSH_20_MA; inrush++) { 226 PM_WRITE(pm_reg, 227 (PM_READ(pm_reg) & ~PM_INRUSH_MASK) | 228 (inrush << PM_INRUSH_SHIFT) | 229 PM_POWUP); 230 231 start = ktime_get_ns(); 232 while (!(powok = !!(PM_READ(pm_reg) & PM_POWOK))) { 233 cpu_relax(); 234 if (ktime_get_ns() - start >= 3000) 235 break; 236 } 237 } 238 if (!powok) { 239 dev_err(dev, "Timeout waiting for %s power OK\n", 240 pd->base.name); 241 ret = -ETIMEDOUT; 242 goto err_disable_powup; 243 } 244 245 /* Disable electrical isolation */ 246 PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISPOW); 247 248 /* Repair memory */ 249 PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_MEMREP); 250 start = ktime_get_ns(); 251 while (!(PM_READ(pm_reg) & PM_MRDONE)) { 252 cpu_relax(); 253 if (ktime_get_ns() - start >= 1000) { 254 dev_err(dev, "Timeout waiting for %s memory repair\n", 255 pd->base.name); 256 ret = -ETIMEDOUT; 257 goto err_disable_ispow; 258 } 259 } 260 261 /* Disable functional isolation */ 262 PM_WRITE(pm_reg, PM_READ(pm_reg) | PM_ISFUNC); 263 264 return 0; 265 266err_disable_ispow: 267 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISPOW); 268err_disable_powup: 269 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~(PM_POWUP | PM_INRUSH_MASK)); 270 return ret; 271} 272 273static int bcm2835_asb_power_on(struct bcm2835_power_domain *pd, 274 u32 pm_reg, 275 u32 asb_m_reg, 276 u32 asb_s_reg, 277 u32 reset_flags) 278{ 279 struct bcm2835_power *power = pd->power; 280 int ret; 281 282 ret = clk_prepare_enable(pd->clk); 283 if (ret) { 284 dev_err(power->dev, "Failed to enable clock for %s\n", 285 pd->base.name); 286 return ret; 287 } 288 289 /* Wait 32 clocks for reset to propagate, 1 us will be enough */ 290 udelay(1); 291 292 clk_disable_unprepare(pd->clk); 293 294 /* Deassert the resets. */ 295 PM_WRITE(pm_reg, PM_READ(pm_reg) | reset_flags); 296 297 ret = clk_prepare_enable(pd->clk); 298 if (ret) { 299 dev_err(power->dev, "Failed to enable clock for %s\n", 300 pd->base.name); 301 goto err_enable_resets; 302 } 303 304 ret = bcm2835_asb_enable(power, asb_m_reg); 305 if (ret) { 306 dev_err(power->dev, "Failed to enable ASB master for %s\n", 307 pd->base.name); 308 goto err_disable_clk; 309 } 310 ret = bcm2835_asb_enable(power, asb_s_reg); 311 if (ret) { 312 dev_err(power->dev, "Failed to enable ASB slave for %s\n", 313 pd->base.name); 314 goto err_disable_asb_master; 315 } 316 317 return 0; 318 319err_disable_asb_master: 320 bcm2835_asb_disable(power, asb_m_reg); 321err_disable_clk: 322 clk_disable_unprepare(pd->clk); 323err_enable_resets: 324 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags); 325 return ret; 326} 327 328static int bcm2835_asb_power_off(struct bcm2835_power_domain *pd, 329 u32 pm_reg, 330 u32 asb_m_reg, 331 u32 asb_s_reg, 332 u32 reset_flags) 333{ 334 struct bcm2835_power *power = pd->power; 335 int ret; 336 337 ret = bcm2835_asb_disable(power, asb_s_reg); 338 if (ret) { 339 dev_warn(power->dev, "Failed to disable ASB slave for %s\n", 340 pd->base.name); 341 return ret; 342 } 343 ret = bcm2835_asb_disable(power, asb_m_reg); 344 if (ret) { 345 dev_warn(power->dev, "Failed to disable ASB master for %s\n", 346 pd->base.name); 347 bcm2835_asb_enable(power, asb_s_reg); 348 return ret; 349 } 350 351 clk_disable_unprepare(pd->clk); 352 353 /* Assert the resets. */ 354 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~reset_flags); 355 356 return 0; 357} 358 359static int bcm2835_power_pd_power_on(struct generic_pm_domain *domain) 360{ 361 struct bcm2835_power_domain *pd = 362 container_of(domain, struct bcm2835_power_domain, base); 363 struct bcm2835_power *power = pd->power; 364 365 switch (pd->domain) { 366 case BCM2835_POWER_DOMAIN_GRAFX: 367 return bcm2835_power_power_on(pd, PM_GRAFX); 368 369 case BCM2835_POWER_DOMAIN_GRAFX_V3D: 370 return bcm2835_asb_power_on(pd, PM_GRAFX, 371 ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, 372 PM_V3DRSTN); 373 374 case BCM2835_POWER_DOMAIN_IMAGE: 375 return bcm2835_power_power_on(pd, PM_IMAGE); 376 377 case BCM2835_POWER_DOMAIN_IMAGE_PERI: 378 return bcm2835_asb_power_on(pd, PM_IMAGE, 379 0, 0, 380 PM_PERIRSTN); 381 382 case BCM2835_POWER_DOMAIN_IMAGE_ISP: 383 return bcm2835_asb_power_on(pd, PM_IMAGE, 384 ASB_ISP_M_CTRL, ASB_ISP_S_CTRL, 385 PM_ISPRSTN); 386 387 case BCM2835_POWER_DOMAIN_IMAGE_H264: 388 return bcm2835_asb_power_on(pd, PM_IMAGE, 389 ASB_H264_M_CTRL, ASB_H264_S_CTRL, 390 PM_H264RSTN); 391 392 case BCM2835_POWER_DOMAIN_USB: 393 PM_WRITE(PM_USB, PM_USB_CTRLEN); 394 return 0; 395 396 case BCM2835_POWER_DOMAIN_DSI0: 397 PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN); 398 PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN | PM_DSI0_LDOHPEN); 399 return 0; 400 401 case BCM2835_POWER_DOMAIN_DSI1: 402 PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN); 403 PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN | PM_DSI1_LDOHPEN); 404 return 0; 405 406 case BCM2835_POWER_DOMAIN_CCP2TX: 407 PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN); 408 PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN | PM_CCP2TX_LDOEN); 409 return 0; 410 411 case BCM2835_POWER_DOMAIN_HDMI: 412 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_RSTDR); 413 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_CTRLEN); 414 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_LDOPD); 415 usleep_range(100, 200); 416 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_RSTDR); 417 return 0; 418 419 default: 420 dev_err(power->dev, "Invalid domain %d\n", pd->domain); 421 return -EINVAL; 422 } 423} 424 425static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain) 426{ 427 struct bcm2835_power_domain *pd = 428 container_of(domain, struct bcm2835_power_domain, base); 429 struct bcm2835_power *power = pd->power; 430 431 switch (pd->domain) { 432 case BCM2835_POWER_DOMAIN_GRAFX: 433 return bcm2835_power_power_off(pd, PM_GRAFX); 434 435 case BCM2835_POWER_DOMAIN_GRAFX_V3D: 436 return bcm2835_asb_power_off(pd, PM_GRAFX, 437 ASB_V3D_M_CTRL, ASB_V3D_S_CTRL, 438 PM_V3DRSTN); 439 440 case BCM2835_POWER_DOMAIN_IMAGE: 441 return bcm2835_power_power_off(pd, PM_IMAGE); 442 443 case BCM2835_POWER_DOMAIN_IMAGE_PERI: 444 return bcm2835_asb_power_off(pd, PM_IMAGE, 445 0, 0, 446 PM_PERIRSTN); 447 448 case BCM2835_POWER_DOMAIN_IMAGE_ISP: 449 return bcm2835_asb_power_off(pd, PM_IMAGE, 450 ASB_ISP_M_CTRL, ASB_ISP_S_CTRL, 451 PM_ISPRSTN); 452 453 case BCM2835_POWER_DOMAIN_IMAGE_H264: 454 return bcm2835_asb_power_off(pd, PM_IMAGE, 455 ASB_H264_M_CTRL, ASB_H264_S_CTRL, 456 PM_H264RSTN); 457 458 case BCM2835_POWER_DOMAIN_USB: 459 PM_WRITE(PM_USB, 0); 460 return 0; 461 462 case BCM2835_POWER_DOMAIN_DSI0: 463 PM_WRITE(PM_DSI0, PM_DSI0_CTRLEN); 464 PM_WRITE(PM_DSI0, 0); 465 return 0; 466 467 case BCM2835_POWER_DOMAIN_DSI1: 468 PM_WRITE(PM_DSI1, PM_DSI1_CTRLEN); 469 PM_WRITE(PM_DSI1, 0); 470 return 0; 471 472 case BCM2835_POWER_DOMAIN_CCP2TX: 473 PM_WRITE(PM_CCP2TX, PM_CCP2TX_CTRLEN); 474 PM_WRITE(PM_CCP2TX, 0); 475 return 0; 476 477 case BCM2835_POWER_DOMAIN_HDMI: 478 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) | PM_HDMI_LDOPD); 479 PM_WRITE(PM_HDMI, PM_READ(PM_HDMI) & ~PM_HDMI_CTRLEN); 480 return 0; 481 482 default: 483 dev_err(power->dev, "Invalid domain %d\n", pd->domain); 484 return -EINVAL; 485 } 486} 487 488static int 489bcm2835_init_power_domain(struct bcm2835_power *power, 490 int pd_xlate_index, const char *name) 491{ 492 struct device *dev = power->dev; 493 struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index]; 494 495 dom->clk = devm_clk_get(dev->parent, name); 496 if (IS_ERR(dom->clk)) { 497 int ret = PTR_ERR(dom->clk); 498 499 if (ret == -EPROBE_DEFER) 500 return ret; 501 502 /* Some domains don't have a clk, so make sure that we 503 * don't deref an error pointer later. 504 */ 505 dom->clk = NULL; 506 } 507 508 dom->base.name = name; 509 dom->base.power_on = bcm2835_power_pd_power_on; 510 dom->base.power_off = bcm2835_power_pd_power_off; 511 512 dom->domain = pd_xlate_index; 513 dom->power = power; 514 515 /* XXX: on/off at boot? */ 516 pm_genpd_init(&dom->base, NULL, true); 517 518 power->pd_xlate.domains[pd_xlate_index] = &dom->base; 519 520 return 0; 521} 522 523/** bcm2835_reset_reset - Resets a block that has a reset line in the 524 * PM block. 525 * 526 * The consumer of the reset controller must have the power domain up 527 * -- there's no reset ability with the power domain down. To reset 528 * the sub-block, we just disable its access to memory through the 529 * ASB, reset, and re-enable. 530 */ 531static int bcm2835_reset_reset(struct reset_controller_dev *rcdev, 532 unsigned long id) 533{ 534 struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power, 535 reset); 536 struct bcm2835_power_domain *pd; 537 int ret; 538 539 switch (id) { 540 case BCM2835_RESET_V3D: 541 pd = &power->domains[BCM2835_POWER_DOMAIN_GRAFX_V3D]; 542 break; 543 case BCM2835_RESET_H264: 544 pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_H264]; 545 break; 546 case BCM2835_RESET_ISP: 547 pd = &power->domains[BCM2835_POWER_DOMAIN_IMAGE_ISP]; 548 break; 549 default: 550 dev_err(power->dev, "Bad reset id %ld\n", id); 551 return -EINVAL; 552 } 553 554 ret = bcm2835_power_pd_power_off(&pd->base); 555 if (ret) 556 return ret; 557 558 return bcm2835_power_pd_power_on(&pd->base); 559} 560 561static int bcm2835_reset_status(struct reset_controller_dev *rcdev, 562 unsigned long id) 563{ 564 struct bcm2835_power *power = container_of(rcdev, struct bcm2835_power, 565 reset); 566 567 switch (id) { 568 case BCM2835_RESET_V3D: 569 return !PM_READ(PM_GRAFX & PM_V3DRSTN); 570 case BCM2835_RESET_H264: 571 return !PM_READ(PM_IMAGE & PM_H264RSTN); 572 case BCM2835_RESET_ISP: 573 return !PM_READ(PM_IMAGE & PM_ISPRSTN); 574 default: 575 return -EINVAL; 576 } 577} 578 579static const struct reset_control_ops bcm2835_reset_ops = { 580 .reset = bcm2835_reset_reset, 581 .status = bcm2835_reset_status, 582}; 583 584static const char *const power_domain_names[] = { 585 [BCM2835_POWER_DOMAIN_GRAFX] = "grafx", 586 [BCM2835_POWER_DOMAIN_GRAFX_V3D] = "v3d", 587 588 [BCM2835_POWER_DOMAIN_IMAGE] = "image", 589 [BCM2835_POWER_DOMAIN_IMAGE_PERI] = "peri_image", 590 [BCM2835_POWER_DOMAIN_IMAGE_H264] = "h264", 591 [BCM2835_POWER_DOMAIN_IMAGE_ISP] = "isp", 592 593 [BCM2835_POWER_DOMAIN_USB] = "usb", 594 [BCM2835_POWER_DOMAIN_DSI0] = "dsi0", 595 [BCM2835_POWER_DOMAIN_DSI1] = "dsi1", 596 [BCM2835_POWER_DOMAIN_CAM0] = "cam0", 597 [BCM2835_POWER_DOMAIN_CAM1] = "cam1", 598 [BCM2835_POWER_DOMAIN_CCP2TX] = "ccp2tx", 599 [BCM2835_POWER_DOMAIN_HDMI] = "hdmi", 600}; 601 602static int bcm2835_power_probe(struct platform_device *pdev) 603{ 604 struct bcm2835_pm *pm = dev_get_drvdata(pdev->dev.parent); 605 struct device *dev = &pdev->dev; 606 struct bcm2835_power *power; 607 static const struct { 608 int parent, child; 609 } domain_deps[] = { 610 { BCM2835_POWER_DOMAIN_GRAFX, BCM2835_POWER_DOMAIN_GRAFX_V3D }, 611 { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_PERI }, 612 { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_H264 }, 613 { BCM2835_POWER_DOMAIN_IMAGE, BCM2835_POWER_DOMAIN_IMAGE_ISP }, 614 { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_USB }, 615 { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 }, 616 { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 }, 617 }; 618 int ret = 0, i; 619 u32 id; 620 621 power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); 622 if (!power) 623 return -ENOMEM; 624 platform_set_drvdata(pdev, power); 625 626 power->dev = dev; 627 power->base = pm->base; 628 power->asb = pm->asb; 629 630 id = ASB_READ(ASB_AXI_BRDG_ID); 631 if (id != 0x62726467 /* "BRDG" */) { 632 dev_err(dev, "ASB register ID returned 0x%08x\n", id); 633 return -ENODEV; 634 } 635 636 power->pd_xlate.domains = devm_kcalloc(dev, 637 ARRAY_SIZE(power_domain_names), 638 sizeof(*power->pd_xlate.domains), 639 GFP_KERNEL); 640 if (!power->pd_xlate.domains) 641 return -ENOMEM; 642 643 power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names); 644 645 for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) { 646 ret = bcm2835_init_power_domain(power, i, power_domain_names[i]); 647 if (ret) 648 goto fail; 649 } 650 651 for (i = 0; i < ARRAY_SIZE(domain_deps); i++) { 652 pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base, 653 &power->domains[domain_deps[i].child].base); 654 } 655 656 power->reset.owner = THIS_MODULE; 657 power->reset.nr_resets = BCM2835_RESET_COUNT; 658 power->reset.ops = &bcm2835_reset_ops; 659 power->reset.of_node = dev->parent->of_node; 660 661 ret = devm_reset_controller_register(dev, &power->reset); 662 if (ret) 663 goto fail; 664 665 of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate); 666 667 dev_info(dev, "Broadcom BCM2835 power domains driver"); 668 return 0; 669 670fail: 671 for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) { 672 struct generic_pm_domain *dom = &power->domains[i].base; 673 674 if (dom->name) 675 pm_genpd_remove(dom); 676 } 677 return ret; 678} 679 680static int bcm2835_power_remove(struct platform_device *pdev) 681{ 682 return 0; 683} 684 685static struct platform_driver bcm2835_power_driver = { 686 .probe = bcm2835_power_probe, 687 .remove = bcm2835_power_remove, 688 .driver = { 689 .name = "bcm2835-power", 690 }, 691}; 692module_platform_driver(bcm2835_power_driver); 693 694MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); 695MODULE_DESCRIPTION("Driver for Broadcom BCM2835 PM power domains and reset"); 696MODULE_LICENSE("GPL");