diff options
author | Eric Anholt <eric@anholt.net> | 2019-02-20 13:19:51 -0500 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2019-03-04 18:33:14 -0500 |
commit | 4deabfae643d8852c643664d9088a647abfaa5d0 (patch) | |
tree | f4664e7c2b35df513a3019745bd6c23aff606ce7 | |
parent | 7f3d6c8e8f5f041c86c0a9f64e4b4ab7c6373ac2 (diff) |
soc: bcm: bcm2835-pm: Fix error paths of initialization.
The clock driver may probe after ours and so we need to pass the
-EPROBE_DEFER out. Fix the other error path while we're here.
v2: Use dom->name instead of dom->gov as the flag for initialized
domains, since we aren't setting up a governor. Make sure to
clear ->clk when no clk is present in the DT.
Signed-off-by: Eric Anholt <eric@anholt.net>
Fixes: 670c672608a1 ("soc: bcm: bcm2835-pm: Add support for power domains under a new binding.")
-rw-r--r-- | drivers/soc/bcm/bcm2835-power.c | 35 |
1 files changed, 30 insertions, 5 deletions
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c index 4a1b99b773c0..241c4ed80899 100644 --- a/drivers/soc/bcm/bcm2835-power.c +++ b/drivers/soc/bcm/bcm2835-power.c | |||
@@ -485,7 +485,7 @@ static int bcm2835_power_pd_power_off(struct generic_pm_domain *domain) | |||
485 | } | 485 | } |
486 | } | 486 | } |
487 | 487 | ||
488 | static void | 488 | static int |
489 | bcm2835_init_power_domain(struct bcm2835_power *power, | 489 | bcm2835_init_power_domain(struct bcm2835_power *power, |
490 | int pd_xlate_index, const char *name) | 490 | int pd_xlate_index, const char *name) |
491 | { | 491 | { |
@@ -493,6 +493,17 @@ bcm2835_init_power_domain(struct bcm2835_power *power, | |||
493 | struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index]; | 493 | struct bcm2835_power_domain *dom = &power->domains[pd_xlate_index]; |
494 | 494 | ||
495 | 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 | } | ||
496 | 507 | ||
497 | dom->base.name = name; | 508 | dom->base.name = name; |
498 | dom->base.power_on = bcm2835_power_pd_power_on; | 509 | dom->base.power_on = bcm2835_power_pd_power_on; |
@@ -505,6 +516,8 @@ bcm2835_init_power_domain(struct bcm2835_power *power, | |||
505 | pm_genpd_init(&dom->base, NULL, true); | 516 | pm_genpd_init(&dom->base, NULL, true); |
506 | 517 | ||
507 | power->pd_xlate.domains[pd_xlate_index] = &dom->base; | 518 | power->pd_xlate.domains[pd_xlate_index] = &dom->base; |
519 | |||
520 | return 0; | ||
508 | } | 521 | } |
509 | 522 | ||
510 | /** 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 |
@@ -602,7 +615,7 @@ static int bcm2835_power_probe(struct platform_device *pdev) | |||
602 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 }, | 615 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM0 }, |
603 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 }, | 616 | { BCM2835_POWER_DOMAIN_IMAGE_PERI, BCM2835_POWER_DOMAIN_CAM1 }, |
604 | }; | 617 | }; |
605 | int ret, i; | 618 | int ret = 0, i; |
606 | u32 id; | 619 | u32 id; |
607 | 620 | ||
608 | power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); | 621 | power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); |
@@ -629,8 +642,11 @@ static int bcm2835_power_probe(struct platform_device *pdev) | |||
629 | 642 | ||
630 | power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names); | 643 | power->pd_xlate.num_domains = ARRAY_SIZE(power_domain_names); |
631 | 644 | ||
632 | for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) | 645 | for (i = 0; i < ARRAY_SIZE(power_domain_names); i++) { |
633 | 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 | } | ||
634 | 650 | ||
635 | for (i = 0; i < ARRAY_SIZE(domain_deps); i++) { | 651 | for (i = 0; i < ARRAY_SIZE(domain_deps); i++) { |
636 | pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base, | 652 | pm_genpd_add_subdomain(&power->domains[domain_deps[i].parent].base, |
@@ -644,12 +660,21 @@ static int bcm2835_power_probe(struct platform_device *pdev) | |||
644 | 660 | ||
645 | ret = devm_reset_controller_register(dev, &power->reset); | 661 | ret = devm_reset_controller_register(dev, &power->reset); |
646 | if (ret) | 662 | if (ret) |
647 | return ret; | 663 | goto fail; |
648 | 664 | ||
649 | 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); |
650 | 666 | ||
651 | dev_info(dev, "Broadcom BCM2835 power domains driver"); | 667 | dev_info(dev, "Broadcom BCM2835 power domains driver"); |
652 | 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; | ||
653 | } | 678 | } |
654 | 679 | ||
655 | static int bcm2835_power_remove(struct platform_device *pdev) | 680 | static int bcm2835_power_remove(struct platform_device *pdev) |