Skip to content

Commit d511206

Browse files
rgantoisbroonie
authored andcommitted
regulator: core: repeat voltage setting request for stepped regulators
The regulator_set_voltage() function may exhibit unexpected behavior if the target regulator has a maximum voltage step constraint. With such a constraint, the regulator core may clamp the requested voltage to a lesser value, to ensure that the voltage delta stays under the specified limit. This means that the resulting regulator voltage depends on the current voltage, as well as the requested range, which invalidates the assumption that a repeated request for a specific voltage range will amount to a noop. Considering the case of a regulator with a maximum voltage step constraint of 1V: initial voltage: 2.5V consumer requests 4V expected result: 3.5V resulting voltage: 3.5V consumer requests 4V again expected result: 4V actual result: 3.5V Correct this by repeating attempts to balance the regulator voltage until the result converges. Signed-off-by: Romain Gantois <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent ef616b9 commit d511206

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

drivers/regulator/core.c

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3797,15 +3797,25 @@ static int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev,
37973797
return 0;
37983798
}
37993799

3800+
static int regulator_get_voltage_delta(struct regulator_dev *rdev, int uV)
3801+
{
3802+
int current_uV = regulator_get_voltage_rdev(rdev);
3803+
3804+
if (current_uV < 0)
3805+
return current_uV;
3806+
3807+
return abs(current_uV - uV);
3808+
}
3809+
38003810
static int regulator_set_voltage_unlocked(struct regulator *regulator,
38013811
int min_uV, int max_uV,
38023812
suspend_state_t state)
38033813
{
38043814
struct regulator_dev *rdev = regulator->rdev;
38053815
struct regulator_voltage *voltage = &regulator->voltage[state];
38063816
int ret = 0;
3817+
int current_uV, delta, new_delta;
38073818
int old_min_uV, old_max_uV;
3808-
int current_uV;
38093819

38103820
/* If we're setting the same range as last time the change
38113821
* should be a noop (some cpufreq implementations use the same
@@ -3852,6 +3862,37 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
38523862
voltage->max_uV = old_max_uV;
38533863
}
38543864

3865+
if (rdev->constraints->max_uV_step > 0) {
3866+
/* For regulators with a maximum voltage step, reaching the desired
3867+
* voltage might take a few retries.
3868+
*/
3869+
ret = regulator_get_voltage_delta(rdev, min_uV);
3870+
if (ret < 0)
3871+
goto out;
3872+
3873+
delta = ret;
3874+
3875+
while (delta > 0) {
3876+
ret = regulator_balance_voltage(rdev, state);
3877+
if (ret < 0)
3878+
goto out;
3879+
3880+
ret = regulator_get_voltage_delta(rdev, min_uV);
3881+
if (ret < 0)
3882+
goto out;
3883+
3884+
new_delta = ret;
3885+
3886+
/* check that voltage is converging quickly enough */
3887+
if (new_delta - delta > rdev->constraints->max_uV_step) {
3888+
ret = -EWOULDBLOCK;
3889+
goto out;
3890+
}
3891+
3892+
delta = new_delta;
3893+
}
3894+
}
3895+
38553896
out:
38563897
return ret;
38573898
}

0 commit comments

Comments
 (0)