mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 17:41:44 +00:00
regulator: implement selector stepping
Some regulators require that the requested voltage be reached gradually by setting all or some of the intermediate values. Implement a new field in the regulator description struct that allows users to specify the number of selectors by which the regulator API should step when ramping the voltage up/down. Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> Link: https://lore.kernel.org/r/20190703161035.31808-2-brgl@bgdev.pl Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
ba2bf340ad
commit
2da8d9473e
@ -3106,6 +3106,66 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _regulator_set_voltage_sel_step(struct regulator_dev *rdev,
|
||||
int uV, int new_selector)
|
||||
{
|
||||
const struct regulator_ops *ops = rdev->desc->ops;
|
||||
int diff, old_sel, curr_sel, ret;
|
||||
|
||||
/* Stepping is only needed if the regulator is enabled. */
|
||||
if (!_regulator_is_enabled(rdev))
|
||||
goto final_set;
|
||||
|
||||
if (!ops->get_voltage_sel)
|
||||
return -EINVAL;
|
||||
|
||||
old_sel = ops->get_voltage_sel(rdev);
|
||||
if (old_sel < 0)
|
||||
return old_sel;
|
||||
|
||||
diff = new_selector - old_sel;
|
||||
if (diff == 0)
|
||||
return 0; /* No change needed. */
|
||||
|
||||
if (diff > 0) {
|
||||
/* Stepping up. */
|
||||
for (curr_sel = old_sel + rdev->desc->vsel_step;
|
||||
curr_sel < new_selector;
|
||||
curr_sel += rdev->desc->vsel_step) {
|
||||
/*
|
||||
* Call the callback directly instead of using
|
||||
* _regulator_call_set_voltage_sel() as we don't
|
||||
* want to notify anyone yet. Same in the branch
|
||||
* below.
|
||||
*/
|
||||
ret = ops->set_voltage_sel(rdev, curr_sel);
|
||||
if (ret)
|
||||
goto try_revert;
|
||||
}
|
||||
} else {
|
||||
/* Stepping down. */
|
||||
for (curr_sel = old_sel - rdev->desc->vsel_step;
|
||||
curr_sel > new_selector;
|
||||
curr_sel -= rdev->desc->vsel_step) {
|
||||
ret = ops->set_voltage_sel(rdev, curr_sel);
|
||||
if (ret)
|
||||
goto try_revert;
|
||||
}
|
||||
}
|
||||
|
||||
final_set:
|
||||
/* The final selector will trigger the notifiers. */
|
||||
return _regulator_call_set_voltage_sel(rdev, uV, new_selector);
|
||||
|
||||
try_revert:
|
||||
/*
|
||||
* At least try to return to the previous voltage if setting a new
|
||||
* one failed.
|
||||
*/
|
||||
(void)ops->set_voltage_sel(rdev, old_sel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _regulator_set_voltage_time(struct regulator_dev *rdev,
|
||||
int old_uV, int new_uV)
|
||||
{
|
||||
@ -3179,6 +3239,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
||||
selector = ret;
|
||||
if (old_selector == selector)
|
||||
ret = 0;
|
||||
else if (rdev->desc->vsel_step)
|
||||
ret = _regulator_set_voltage_sel_step(
|
||||
rdev, best_val, selector);
|
||||
else
|
||||
ret = _regulator_call_set_voltage_sel(
|
||||
rdev, best_val, selector);
|
||||
|
@ -286,6 +286,11 @@ enum regulator_type {
|
||||
* @vsel_range_mask: Mask for register bitfield used for range selector
|
||||
* @vsel_reg: Register for selector when using regulator_regmap_X_voltage_
|
||||
* @vsel_mask: Mask for register bitfield used for selector
|
||||
* @vsel_step: Specify the resolution of selector stepping when setting
|
||||
* voltage. If 0, then no stepping is done (requested selector is
|
||||
* set directly), if >0 then the regulator API will ramp the
|
||||
* voltage up/down gradually each time increasing/decreasing the
|
||||
* selector by the specified step value.
|
||||
* @csel_reg: Register for current limit selector using regmap set_current_limit
|
||||
* @csel_mask: Mask for register bitfield used for current limit selector
|
||||
* @apply_reg: Register for initiate voltage change on the output when
|
||||
@ -360,6 +365,7 @@ struct regulator_desc {
|
||||
unsigned int vsel_range_mask;
|
||||
unsigned int vsel_reg;
|
||||
unsigned int vsel_mask;
|
||||
unsigned int vsel_step;
|
||||
unsigned int csel_reg;
|
||||
unsigned int csel_mask;
|
||||
unsigned int apply_reg;
|
||||
|
Loading…
Reference in New Issue
Block a user