diff options
author | Bjorn Andersson <bjorn.andersson@sonymobile.com> | 2015-03-24 21:56:05 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-04-01 16:19:44 -0400 |
commit | 6261b06de565baafa590e58a531a1a5522cea0b6 (patch) | |
tree | 4bc6989348daaf4fc2c92c4f1c9976796975f2f7 /drivers/regulator | |
parent | 5c9e719691eab8c5de8b1b68fc3da9f7c4470c38 (diff) |
regulator: Defer lookup of supply to regulator_get
Instead of resolving regulator supplies during registration move this to
the time of a consumer retrieving a handle. The benefit is that it's
possible for one driver to register regulators with internal
dependencies out of order.
Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/core.c | 92 |
1 files changed, 56 insertions, 36 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b899947d839d..a291a6b9cd44 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -1316,6 +1316,54 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, | |||
1316 | return NULL; | 1316 | return NULL; |
1317 | } | 1317 | } |
1318 | 1318 | ||
1319 | static int regulator_resolve_supply(struct regulator_dev *rdev) | ||
1320 | { | ||
1321 | struct regulator_dev *r; | ||
1322 | struct device *dev = rdev->dev.parent; | ||
1323 | int ret; | ||
1324 | |||
1325 | /* No supply to resovle? */ | ||
1326 | if (!rdev->supply_name) | ||
1327 | return 0; | ||
1328 | |||
1329 | /* Supply already resolved? */ | ||
1330 | if (rdev->supply) | ||
1331 | return 0; | ||
1332 | |||
1333 | r = regulator_dev_lookup(dev, rdev->supply_name, &ret); | ||
1334 | if (ret == -ENODEV) { | ||
1335 | /* | ||
1336 | * No supply was specified for this regulator and | ||
1337 | * there will never be one. | ||
1338 | */ | ||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1342 | if (!r) { | ||
1343 | dev_err(dev, "Failed to resolve %s-supply for %s\n", | ||
1344 | rdev->supply_name, rdev->desc->name); | ||
1345 | return -EPROBE_DEFER; | ||
1346 | } | ||
1347 | |||
1348 | /* Recursively resolve the supply of the supply */ | ||
1349 | ret = regulator_resolve_supply(r); | ||
1350 | if (ret < 0) | ||
1351 | return ret; | ||
1352 | |||
1353 | ret = set_supply(rdev, r); | ||
1354 | if (ret < 0) | ||
1355 | return ret; | ||
1356 | |||
1357 | /* Cascade always-on state to supply */ | ||
1358 | if (_regulator_is_enabled(rdev)) { | ||
1359 | ret = regulator_enable(rdev->supply); | ||
1360 | if (ret < 0) | ||
1361 | return ret; | ||
1362 | } | ||
1363 | |||
1364 | return 0; | ||
1365 | } | ||
1366 | |||
1319 | /* Internal regulator request function */ | 1367 | /* Internal regulator request function */ |
1320 | static struct regulator *_regulator_get(struct device *dev, const char *id, | 1368 | static struct regulator *_regulator_get(struct device *dev, const char *id, |
1321 | bool exclusive, bool allow_dummy) | 1369 | bool exclusive, bool allow_dummy) |
@@ -1385,6 +1433,12 @@ found: | |||
1385 | goto out; | 1433 | goto out; |
1386 | } | 1434 | } |
1387 | 1435 | ||
1436 | ret = regulator_resolve_supply(rdev); | ||
1437 | if (ret < 0) { | ||
1438 | regulator = ERR_PTR(ret); | ||
1439 | goto out; | ||
1440 | } | ||
1441 | |||
1388 | if (!try_module_get(rdev->owner)) | 1442 | if (!try_module_get(rdev->owner)) |
1389 | goto out; | 1443 | goto out; |
1390 | 1444 | ||
@@ -3536,7 +3590,6 @@ regulator_register(const struct regulator_desc *regulator_desc, | |||
3536 | struct regulator_dev *rdev; | 3590 | struct regulator_dev *rdev; |
3537 | struct device *dev; | 3591 | struct device *dev; |
3538 | int ret, i; | 3592 | int ret, i; |
3539 | const char *supply = NULL; | ||
3540 | 3593 | ||
3541 | if (regulator_desc == NULL || cfg == NULL) | 3594 | if (regulator_desc == NULL || cfg == NULL) |
3542 | return ERR_PTR(-EINVAL); | 3595 | return ERR_PTR(-EINVAL); |
@@ -3650,41 +3703,10 @@ regulator_register(const struct regulator_desc *regulator_desc, | |||
3650 | goto scrub; | 3703 | goto scrub; |
3651 | 3704 | ||
3652 | if (init_data && init_data->supply_regulator) | 3705 | if (init_data && init_data->supply_regulator) |
3653 | supply = init_data->supply_regulator; | 3706 | rdev->supply_name = init_data->supply_regulator; |
3654 | else if (regulator_desc->supply_name) | 3707 | else if (regulator_desc->supply_name) |
3655 | supply = regulator_desc->supply_name; | 3708 | rdev->supply_name = regulator_desc->supply_name; |
3656 | |||
3657 | if (supply) { | ||
3658 | struct regulator_dev *r; | ||
3659 | |||
3660 | r = regulator_dev_lookup(dev, supply, &ret); | ||
3661 | 3709 | ||
3662 | if (ret == -ENODEV) { | ||
3663 | /* | ||
3664 | * No supply was specified for this regulator and | ||
3665 | * there will never be one. | ||
3666 | */ | ||
3667 | ret = 0; | ||
3668 | goto add_dev; | ||
3669 | } else if (!r) { | ||
3670 | dev_err(dev, "Failed to find supply %s\n", supply); | ||
3671 | ret = -EPROBE_DEFER; | ||
3672 | goto scrub; | ||
3673 | } | ||
3674 | |||
3675 | ret = set_supply(rdev, r); | ||
3676 | if (ret < 0) | ||
3677 | goto scrub; | ||
3678 | |||
3679 | /* Enable supply if rail is enabled */ | ||
3680 | if (_regulator_is_enabled(rdev)) { | ||
3681 | ret = regulator_enable(rdev->supply); | ||
3682 | if (ret < 0) | ||
3683 | goto scrub; | ||
3684 | } | ||
3685 | } | ||
3686 | |||
3687 | add_dev: | ||
3688 | /* add consumers devices */ | 3710 | /* add consumers devices */ |
3689 | if (init_data) { | 3711 | if (init_data) { |
3690 | for (i = 0; i < init_data->num_consumer_supplies; i++) { | 3712 | for (i = 0; i < init_data->num_consumer_supplies; i++) { |
@@ -3711,8 +3733,6 @@ unset_supplies: | |||
3711 | unset_regulator_supplies(rdev); | 3733 | unset_regulator_supplies(rdev); |
3712 | 3734 | ||
3713 | scrub: | 3735 | scrub: |
3714 | if (rdev->supply) | ||
3715 | _regulator_put(rdev->supply); | ||
3716 | regulator_ena_gpio_free(rdev); | 3736 | regulator_ena_gpio_free(rdev); |
3717 | kfree(rdev->constraints); | 3737 | kfree(rdev->constraints); |
3718 | wash: | 3738 | wash: |