Changing voltage and enabling regulator might require delays so the
regulator stabilizes at expected level.

Add support for "regulator-ramp-delay" binding which can introduce
required time to both enabling the regulator and to changing the
voltage.

Signed-off-by: Krzysztof Kozlowski <k...@kernel.org>
---
 drivers/power/regulator/regulator-uclass.c | 45 +++++++++++++++++++++-
 include/power/regulator.h                  |  2 +
 2 files changed, 45 insertions(+), 2 deletions(-)

diff --git a/drivers/power/regulator/regulator-uclass.c 
b/drivers/power/regulator/regulator-uclass.c
index 39e46279d533..4119f244c74b 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -35,10 +35,22 @@ int regulator_get_value(struct udevice *dev)
        return ops->get_value(dev);
 }
 
+static void regulator_set_value_delay(struct udevice *dev, int old_uV,
+                                     int new_uV, unsigned int ramp_delay)
+{
+       int delay = DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay);
+
+       debug("regulator %s: delay %u us (%d uV -> %d uV)\n", dev->name,
+             delay, old_uV, new_uV);
+
+       udelay(delay);
+}
+
 int regulator_set_value(struct udevice *dev, int uV)
 {
        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
        struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret, old_uV = uV;
 
        uc_pdata = dev_get_uclass_platdata(dev);
        if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
@@ -49,7 +61,18 @@ int regulator_set_value(struct udevice *dev, int uV)
        if (!ops || !ops->set_value)
                return -ENOSYS;
 
-       return ops->set_value(dev, uV);
+       if (uc_pdata->ramp_delay)
+               old_uV = regulator_get_value(dev);
+
+       ret = ops->set_value(dev, uV);
+
+       if (!ret) {
+               if (uc_pdata->ramp_delay && old_uV > 0)
+                       regulator_set_value_delay(dev, old_uV, uV,
+                                                 uc_pdata->ramp_delay);
+       }
+
+       return ret;
 }
 
 /*
@@ -107,6 +130,7 @@ int regulator_set_enable(struct udevice *dev, bool enable)
 {
        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
        struct dm_regulator_uclass_platdata *uc_pdata;
+       int ret, old_enable = 0;
 
        if (!ops || !ops->set_enable)
                return -ENOSYS;
@@ -115,7 +139,22 @@ int regulator_set_enable(struct udevice *dev, bool enable)
        if (!enable && uc_pdata->always_on)
                return 0;
 
-       return ops->set_enable(dev, enable);
+       if (uc_pdata->ramp_delay)
+               old_enable = regulator_get_enable(dev);
+
+       ret = ops->set_enable(dev, enable);
+       if (!ret) {
+               if (uc_pdata->ramp_delay && !old_enable) {
+                       int uV = regulator_get_value(dev);
+
+                       if (uV > 0) {
+                               regulator_set_value_delay(dev, 0, uV,
+                                                         uc_pdata->ramp_delay);
+                       }
+               }
+       }
+
+       return ret;
 }
 
 int regulator_get_mode(struct udevice *dev)
@@ -324,6 +363,8 @@ static int regulator_pre_probe(struct udevice *dev)
                                                -ENODATA);
        uc_pdata->always_on = dev_read_bool(dev, "regulator-always-on");
        uc_pdata->boot_on = dev_read_bool(dev, "regulator-boot-on");
+       uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay",
+                                                   0);
 
        /* Those values are optional (-ENODATA if unset) */
        if ((uc_pdata->min_uV != -ENODATA) &&
diff --git a/include/power/regulator.h b/include/power/regulator.h
index 5318ab3acece..c13fa1f336e5 100644
--- a/include/power/regulator.h
+++ b/include/power/regulator.h
@@ -149,6 +149,7 @@ enum regulator_flag {
  * @max_uA*    - maximum amperage (micro Amps)
  * @always_on* - bool type, true or false
  * @boot_on*   - bool type, true or false
+ * @ramp_delay - Time to settle down after voltage change (unit: uV/us)
  * TODO(s...@chromium.org): Consider putting the above two into @flags
  * @flags:     - flags value (see REGULATOR_FLAG_...)
  * @name**     - fdt regulator name - should be taken from the device tree
@@ -169,6 +170,7 @@ struct dm_regulator_uclass_platdata {
        int max_uV;
        int min_uA;
        int max_uA;
+       unsigned int ramp_delay;
        bool always_on;
        bool boot_on;
        const char *name;
-- 
2.17.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to