regulator: core: Ensure we are at least in bounds for our constraints
authorMark Brown <broonie@kernel.org>
Mon, 21 Mar 2016 18:12:52 +0000 (18:12 +0000)
committerMark Brown <broonie@kernel.org>
Sun, 27 Mar 2016 09:02:43 +0000 (10:02 +0100)
Currently we only attempt to set the voltage during constraints
application if an exact voltage is specified.  Extend this so that if
the currently set voltage for the regulator is outside the bounds set in
constraints we will move the voltage to the nearest constraint, raising
to the minimum or lowering to the maximum as needed.  This ensures that
drivers can probe without the hardware being driven out of spec.

Reported-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
Tested-by: Ivaylo Dimitrov <ivo.g.dimitrov.75@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/regulator/core.c
drivers/regulator/of_regulator.c

index e0b7642847731390ed44bbc3e8718fd5dd9e7116..881c37e61f7547120b0a07e07b4dce3ce459181d 100644 (file)
@@ -906,7 +906,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
 
        /* do we need to apply the constraint voltage */
        if (rdev->constraints->apply_uV &&
-           rdev->constraints->min_uV == rdev->constraints->max_uV) {
+           rdev->constraints->min_uV && rdev->constraints->max_uV) {
+               int target_min, target_max;
                int current_uV = _regulator_get_voltage(rdev);
                if (current_uV < 0) {
                        rdev_err(rdev,
@@ -914,15 +915,32 @@ static int machine_constraints_voltage(struct regulator_dev *rdev,
                                 current_uV);
                        return current_uV;
                }
-               if (current_uV < rdev->constraints->min_uV ||
-                   current_uV > rdev->constraints->max_uV) {
+
+               /*
+                * If we're below the minimum voltage move up to the
+                * minimum voltage, if we're above the maximum voltage
+                * then move down to the maximum.
+                */
+               target_min = current_uV;
+               target_max = current_uV;
+
+               if (current_uV < rdev->constraints->min_uV) {
+                       target_min = rdev->constraints->min_uV;
+                       target_max = rdev->constraints->min_uV;
+               }
+
+               if (current_uV > rdev->constraints->max_uV) {
+                       target_min = rdev->constraints->max_uV;
+                       target_max = rdev->constraints->max_uV;
+               }
+
+               if (target_min != current_uV || target_max != current_uV) {
                        ret = _regulator_do_set_voltage(
-                               rdev, rdev->constraints->min_uV,
-                               rdev->constraints->max_uV);
+                               rdev, target_min, target_max);
                        if (ret < 0) {
                                rdev_err(rdev,
-                                       "failed to apply %duV constraint(%d)\n",
-                                       rdev->constraints->min_uV, ret);
+                                       "failed to apply %d-%duV constraint(%d)\n",
+                                       target_min, target_max, ret);
                                return ret;
                        }
                }
index d2ddefaaddaff5941e1c32ee6e1e9b1df4b5686a..f45106a44635c414451dee7e3b0b1b00df7f54ee 100644 (file)
@@ -43,7 +43,7 @@ static void of_get_regulation_constraints(struct device_node *np,
                constraints->max_uV = pval;
 
        /* Voltage change possible? */
-       if (constraints->min_uV != constraints->max_uV) {
+       if (constraints->min_uV && constraints->max_uV) {
                constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
                constraints->apply_uV = true;
        }