Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 2da8d947 authored by Bartosz Golaszewski's avatar Bartosz Golaszewski Committed by Mark Brown
Browse files

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: default avatarBartosz Golaszewski <bgolaszewski@baylibre.com>
Link: https://lore.kernel.org/r/20190703161035.31808-2-brgl@bgdev.pl


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent ba2bf340
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
@@ -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);
+6 −0
Original line number Diff line number Diff line
@@ -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;