diff options
Diffstat (limited to 'drivers')
| -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) |
