Skip to content

Commit 45389c4

Browse files
jonhunterbroonie
authored andcommitted
regulator: core: Add early supply resolution for regulators
The call to set_machine_constraints() in regulator_register(), will attempt to get the voltage for the regulator. If a regulator is in bypass will fail to get the voltage (ie. it's bypass voltage) and hence register the regulator, because the supply for the regulator has not been resolved yet. To fix this, add a call to regulator_resolve_supply() before we call set_machine_constraints(). If the call to regulator_resolve_supply() fails, rather than returning an error at this point, allow the registration of the regulator to continue because for some regulators resolving the supply at this point may not be necessary and it will be resolved later as more regulators are added. Furthermore, if the supply is still not resolved for a bypassed regulator, this will be detected when we attempt to get the voltage for the regulator and an error will be propagated at this point. If a bypassed regulator does not have a supply when we attempt to get the voltage, rather than returing -EINVAL, return -EPROBE_DEFER instead to allow the registration of the regulator to be deferred and tried again later. Please note that regulator_resolve_supply() will call regulator_dev_lookup() which may acquire the regulator_list_mutex. To avoid any deadlocks we cannot hold the regulator_list_mutex when calling regulator_resolve_supply(). Therefore, rather than holding the lock around a large portion of the registration code, just hold the lock when aquiring any GPIOs and setting up supplies because these sections may add entries to the regulator_map_list and regulator_ena_gpio_list, respectively. Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent cbc13a6 commit 45389c4

File tree

1 file changed

+26
-11
lines changed

1 file changed

+26
-11
lines changed

drivers/regulator/core.c

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3118,8 +3118,11 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
31183118
return ret;
31193119
if (bypassed) {
31203120
/* if bypassed the regulator must have a supply */
3121-
if (!rdev->supply)
3122-
return -EINVAL;
3121+
if (!rdev->supply) {
3122+
rdev_err(rdev,
3123+
"bypassed regulator has no supply!\n");
3124+
return -EPROBE_DEFER;
3125+
}
31233126

31243127
return _regulator_get_voltage(rdev->supply->rdev);
31253128
}
@@ -3936,8 +3939,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
39363939
rdev->dev.of_node = of_node_get(config->of_node);
39373940
}
39383941

3939-
mutex_lock(&regulator_list_mutex);
3940-
39413942
mutex_init(&rdev->mutex);
39423943
rdev->reg_data = config->driver_data;
39433944
rdev->owner = regulator_desc->owner;
@@ -3962,7 +3963,9 @@ regulator_register(const struct regulator_desc *regulator_desc,
39623963

39633964
if ((config->ena_gpio || config->ena_gpio_initialized) &&
39643965
gpio_is_valid(config->ena_gpio)) {
3966+
mutex_lock(&regulator_list_mutex);
39653967
ret = regulator_ena_gpio_request(rdev, config);
3968+
mutex_unlock(&regulator_list_mutex);
39663969
if (ret != 0) {
39673970
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
39683971
config->ena_gpio, ret);
@@ -3980,31 +3983,40 @@ regulator_register(const struct regulator_desc *regulator_desc,
39803983
if (init_data)
39813984
constraints = &init_data->constraints;
39823985

3983-
ret = set_machine_constraints(rdev, constraints);
3984-
if (ret < 0)
3985-
goto wash;
3986-
39873986
if (init_data && init_data->supply_regulator)
39883987
rdev->supply_name = init_data->supply_regulator;
39893988
else if (regulator_desc->supply_name)
39903989
rdev->supply_name = regulator_desc->supply_name;
39913990

3991+
/*
3992+
* Attempt to resolve the regulator supply, if specified,
3993+
* but don't return an error if we fail because we will try
3994+
* to resolve it again later as more regulators are added.
3995+
*/
3996+
if (regulator_resolve_supply(rdev))
3997+
rdev_dbg(rdev, "unable to resolve supply\n");
3998+
3999+
ret = set_machine_constraints(rdev, constraints);
4000+
if (ret < 0)
4001+
goto wash;
4002+
39924003
/* add consumers devices */
39934004
if (init_data) {
4005+
mutex_lock(&regulator_list_mutex);
39944006
for (i = 0; i < init_data->num_consumer_supplies; i++) {
39954007
ret = set_consumer_device_supply(rdev,
39964008
init_data->consumer_supplies[i].dev_name,
39974009
init_data->consumer_supplies[i].supply);
39984010
if (ret < 0) {
4011+
mutex_unlock(&regulator_list_mutex);
39994012
dev_err(dev, "Failed to set supply %s\n",
40004013
init_data->consumer_supplies[i].supply);
40014014
goto unset_supplies;
40024015
}
40034016
}
4017+
mutex_unlock(&regulator_list_mutex);
40044018
}
40054019

4006-
mutex_unlock(&regulator_list_mutex);
4007-
40084020
ret = device_register(&rdev->dev);
40094021
if (ret != 0) {
40104022
put_device(&rdev->dev);
@@ -4021,13 +4033,16 @@ regulator_register(const struct regulator_desc *regulator_desc,
40214033
return rdev;
40224034

40234035
unset_supplies:
4036+
mutex_lock(&regulator_list_mutex);
40244037
unset_regulator_supplies(rdev);
4038+
mutex_unlock(&regulator_list_mutex);
40254039
wash:
40264040
kfree(rdev->constraints);
4041+
mutex_lock(&regulator_list_mutex);
40274042
regulator_ena_gpio_free(rdev);
4043+
mutex_unlock(&regulator_list_mutex);
40284044
clean:
40294045
kfree(rdev);
4030-
mutex_unlock(&regulator_list_mutex);
40314046
kfree(config);
40324047
return ERR_PTR(ret);
40334048
}

0 commit comments

Comments
 (0)