Skip to content

Commit

Permalink
regulator: core: Add new max_uV_step constraint
Browse files Browse the repository at this point in the history
On NVIDIA Tegra30 there is a requirement for regulator "A" to have voltage
higher than voltage of regulator "B" by N microvolts, the N value changes
depending on the voltage of regulator "B". This is similar to min-spread
between voltages of regulators, the difference is that the spread value
isn't fixed. This means that extra carefulness is required for regulator
"A" to drop its voltage without violating the requirement, hence its
voltage should be changed in steps so that its couple "B" could follow
(there is also max-spread requirement).

Add new "max_uV_step" constraint that breaks voltage change into several
steps, each step is limited by the max_uV_step value.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Dmitry Osipenko authored and Mark Brown committed Nov 8, 2018
1 parent a2dfe7c commit 85254bc
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 0 deletions.
41 changes: 41 additions & 0 deletions drivers/regulator/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -3191,6 +3191,36 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
return ret;
}

static int regulator_limit_voltage_step(struct regulator_dev *rdev,
int *current_uV, int *min_uV)
{
struct regulation_constraints *constraints = rdev->constraints;

/* Limit voltage change only if necessary */
if (!constraints->max_uV_step || !_regulator_is_enabled(rdev))
return 1;

if (*current_uV < 0) {
*current_uV = _regulator_get_voltage(rdev);

if (*current_uV < 0)
return *current_uV;
}

if (abs(*current_uV - *min_uV) <= constraints->max_uV_step)
return 1;

/* Clamp target voltage within the given step */
if (*current_uV < *min_uV)
*min_uV = min(*current_uV + constraints->max_uV_step,
*min_uV);
else
*min_uV = max(*current_uV - constraints->max_uV_step,
*min_uV);

return 0;
}

static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
int *current_uV,
int *min_uV, int *max_uV,
Expand Down Expand Up @@ -3302,6 +3332,17 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
desired_min_uV = possible_uV;

finish:
/* Apply max_uV_step constraint if necessary */
if (state == PM_SUSPEND_ON) {
ret = regulator_limit_voltage_step(rdev, current_uV,
&desired_min_uV);
if (ret < 0)
return ret;

if (ret == 0)
done = false;
}

/* Set current_uV if wasn't done earlier in the code and if necessary */
if (n_coupled > 1 && *current_uV == -1) {

Expand Down
4 changes: 4 additions & 0 deletions drivers/regulator/of_regulator.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ static void of_get_regulation_constraints(struct device_node *np,
&pval))
constraints->max_spread = pval;

if (!of_property_read_u32(np, "regulator-max-step-microvolt",
&pval))
constraints->max_uV_step = pval;

constraints->over_current_protection = of_property_read_bool(np,
"regulator-over-current-protection");

Expand Down
3 changes: 3 additions & 0 deletions include/linux/regulator/machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ struct regulation_constraints {
/* used for coupled regulators */
int max_spread;

/* used for changing voltage in steps */
int max_uV_step;

/* valid regulator operating modes for this machine */
unsigned int valid_modes_mask;

Expand Down

0 comments on commit 85254bc

Please sign in to comment.