diff options
| -rw-r--r-- | arch/arm64/Kconfig.platforms | 1 | ||||
| -rw-r--r-- | drivers/soc/bcm/bcm2835-power.c | 49 |
2 files changed, 43 insertions, 7 deletions
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 70498a033cf5..b5ca9c50876d 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms | |||
| @@ -27,6 +27,7 @@ config ARCH_BCM2835 | |||
| 27 | bool "Broadcom BCM2835 family" | 27 | bool "Broadcom BCM2835 family" |
| 28 | select TIMER_OF | 28 | select TIMER_OF |
| 29 | select GPIOLIB | 29 | select GPIOLIB |
| 30 | select MFD_CORE | ||
| 30 | select PINCTRL | 31 | select PINCTRL |
| 31 | select PINCTRL_BCM2835 | 32 | select PINCTRL_BCM2835 |
| 32 | select ARM_AMBA | 33 | select ARM_AMBA |
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c index 9351349cf0a9..1e0041ec8132 100644 --- a/drivers/soc/bcm/bcm2835-power.c +++ b/drivers/soc/bcm/bcm2835-power.c | |||
| @@ -150,7 +150,12 @@ struct bcm2835_power { | |||
| 150 | 150 | ||
| 151 | static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) | 151 | static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) |
| 152 | { | 152 | { |
| 153 | u64 start = ktime_get_ns(); | 153 | u64 start; |
| 154 | |||
| 155 | if (!reg) | ||
| 156 | return 0; | ||
| 157 | |||
| 158 | start = ktime_get_ns(); | ||
| 154 | 159 | ||
| 155 | /* Enable the module's async AXI bridges. */ | 160 | /* Enable the module's async AXI bridges. */ |
| 156 | ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP); | 161 | ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP); |
| @@ -165,7 +170,12 @@ static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) | |||
| 165 | 170 | ||
| 166 | static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg) | 171 | static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg) |
| 167 | { | 172 | { |
| 168 | u64 start = ktime_get_ns(); | 173 | u64 start; |
| 174 | |||
| 175 | if (!reg) | ||
| 176 | return 0; | ||
| 177 | |||
| 178 | start = ktime_get_ns(); | ||
| 169 | 179 | ||
| 170 | /* Enable the module's async AXI bridges. */ | 180 | /* Enable the module's async AXI bridges. */ |
| 171 | ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP); | 181 | ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP); |
| @@ -475,7 +485,7 @@ static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain) | |||
| 475 | } | 485 | } |
| 476 | } | 486 | } |
| 477 | 487 | ||
| 478 | static void | 488 | static int |
| 479 | bcm2835_init_power_domain(struct bcm2835_power *power, | 489 | bcm2835_init_power_domain(struct bcm2835_power *power, |
| 480 | int pd_xlate_index, const char *name) | 490 | int pd_xlate_index, const char *name) |
| 481 | { | 491 | { |
| @@ -483,6 +493,17 @@ bcm2835_init_power_domain(struct bcm2835_power *power, | |||
| 483 | struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index]; | 493 | struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index]; |
| 484 | 494 | ||
| 485 | dom->clk = devm_clk_get(dev->parent, name); | 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 | } | ||
| 486 | 507 | ||
| 487 | dom->base.name = name; | 508 | dom->base.name = name; |
| 488 | dom->base.power_on = bcm2835_power_pd_power_on; | 509 | dom->base.power_on = bcm2835_power_pd_power_on; |
| @@ -495,6 +516,8 @@ bcm2835_init_power_domain(struct bcm2835_power *power, | |||
| 495 | pm_genpd_init(&dom->base, NULL, true); | 516 | pm_genpd_init(&dom->base, NULL, true); |
| 496 | 517 | ||
| 497 | power->pd_xlate.domains[pd_xlate_index] = &dom->base; | 518 | power->pd_xlate.domains[pd_xlate_index] = &dom->base; |
| 519 | |||
| 520 | return 0; | ||
| 498 | } | 521 | } |
| 499 | 522 | ||
| 500 | /** bcm2835_reset_reset - Resets a block that has a reset line in the | 523 | /** bcm2835_reset_reset - Resets a block that has a reset line in the |
| @@ -592,7 +615,7 @@ static int bcm2835_power_probe(struct platform_device *pdev) | |||
| 592 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 }, | 615 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 }, |
| 593 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 }, | 616 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 }, |
| 594 | }; | 617 | }; |
| 595 | int ret, i; | 618 | int ret = 0, i; |
| 596 | u32 id; | 619 | u32 id; |
| 597 | 620 | ||
| 598 | power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); | 621 | power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); |
| @@ -619,8 +642,11 @@ static int bcm2835_power_probe(struct platform_device *pdev) | |||
| 619 | 642 | ||
| 620 | power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names); | 643 | power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names); |
| 621 | 644 | ||
| 622 | for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) | 645 | for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) { |
| 623 | bcm2835_init_power_domain(power, i, power_domain_names[i]); | 646 | ret = bcm2835_init_power_domain(power, i, power_domain_names[i]); |
| 647 | if (ret) | ||
| 648 | goto fail; | ||
| 649 | } | ||
| 624 | 650 | ||
| 625 | for (i = 0; i < ARRAY_SIZE(domain_deps); i++) { | 651 | for (i = 0; i < ARRAY_SIZE(domain_deps); i++) { |
| 626 | pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base, | 652 | pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base, |
| @@ -634,12 +660,21 @@ static int bcm2835_power_probe(struct platform_device *pdev) | |||
| 634 | 660 | ||
| 635 | ret = devm_reset_controller_register(dev, &power->reset); | 661 | ret = devm_reset_controller_register(dev, &power->reset); |
| 636 | if (ret) | 662 | if (ret) |
| 637 | return ret; | 663 | goto fail; |
| 638 | 664 | ||
| 639 | of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate); | 665 | of_genpd_add_provider_onecell(dev->parent->of_node, &power->pd_xlate); |
| 640 | 666 | ||
| 641 | dev_info(dev, "Broadcom BCM2835 power domains driver"); | 667 | dev_info(dev, "Broadcom BCM2835 power domains driver"); |
| 642 | return 0; | 668 | return 0; |
| 669 | |||
| 670 | fail: | ||
| 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; | ||
| 643 | } | 678 | } |
| 644 | 679 | ||
| 645 | static int bcm2835_power_remove(struct platform_device *pdev) | 680 | static int bcm2835_power_remove(struct platform_device *pdev) |
