aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/core.c
diff options
context:
space:
mode:
authorDmitry Osipenko <digetx@gmail.com>2018-10-05 18:36:35 +0300
committerMark Brown <broonie@kernel.org>2018-11-08 16:20:49 +0000
commit85254bcf394f93a8955814da1eef4d477b63eb84 (patch)
tree9e179e84773d64398d9cc93262b9fe85ac789c17 /drivers/regulator/core.c
parentregulator: Document new regulator-max-step-microvolt property (diff)
downloadlinux-dev-85254bcf394f93a8955814da1eef4d477b63eb84.tar.xz
linux-dev-85254bcf394f93a8955814da1eef4d477b63eb84.zip
regulator: core: Add new max_uV_step constraint
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>
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r--drivers/regulator/core.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 089e8ad8ef57..ba03bdf3716f 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3191,6 +3191,36 @@ out:
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,
@@ -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) {