Merge branch '2020-05-18-reduce-size-of-common.h'
[oweals/u-boot.git] / drivers / power / regulator / regulator-uclass.c
index 9118b8eb39e34ff4266d2d1f8fc9a9f562565885..7dcb3171928c4d6b515f005e38f029848a73ac83 100644 (file)
@@ -7,7 +7,9 @@
 #include <common.h>
 #include <errno.h>
 #include <dm.h>
+#include <log.h>
 #include <dm/uclass-internal.h>
+#include <linux/delay.h>
 #include <power/pmic.h>
 #include <power/regulator.h>
 
@@ -77,6 +79,33 @@ int regulator_set_value(struct udevice *dev, int uV)
        return ret;
 }
 
+int regulator_set_suspend_value(struct udevice *dev, int uV)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+       struct dm_regulator_uclass_platdata *uc_pdata;
+
+       uc_pdata = dev_get_uclass_platdata(dev);
+       if (uc_pdata->min_uV != -ENODATA && uV < uc_pdata->min_uV)
+               return -EINVAL;
+       if (uc_pdata->max_uV != -ENODATA && uV > uc_pdata->max_uV)
+               return -EINVAL;
+
+       if (!ops->set_suspend_value)
+               return -ENOSYS;
+
+       return ops->set_suspend_value(dev, uV);
+}
+
+int regulator_get_suspend_value(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops->get_suspend_value)
+               return -ENOSYS;
+
+       return ops->get_suspend_value(dev);
+}
+
 /*
  * To be called with at most caution as there is no check
  * before setting the actual voltage value.
@@ -170,6 +199,26 @@ int regulator_set_enable_if_allowed(struct udevice *dev, bool enable)
        return ret;
 }
 
+int regulator_set_suspend_enable(struct udevice *dev, bool enable)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops->set_suspend_enable)
+               return -ENOSYS;
+
+       return ops->set_suspend_enable(dev, enable);
+}
+
+int regulator_get_suspend_enable(struct udevice *dev)
+{
+       const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
+
+       if (!ops->get_suspend_enable)
+               return -ENOSYS;
+
+       return ops->get_suspend_enable(dev);
+}
+
 int regulator_get_mode(struct udevice *dev)
 {
        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
@@ -235,11 +284,24 @@ int regulator_autoset(struct udevice *dev)
        int ret = 0;
 
        uc_pdata = dev_get_uclass_platdata(dev);
+
+       ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
+       if (!ret && uc_pdata->suspend_on) {
+               ret = regulator_set_suspend_value(dev, uc_pdata->suspend_uV);
+               if (!ret)
+                       return ret;
+       }
+
        if (!uc_pdata->always_on && !uc_pdata->boot_on)
                return -EMEDIUMTYPE;
 
+       if (uc_pdata->type == REGULATOR_TYPE_FIXED)
+               return regulator_set_enable(dev, true);
+
        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
                ret = regulator_set_value(dev, uc_pdata->min_uV);
+       if (uc_pdata->init_uV > 0)
+               ret = regulator_set_value(dev, uc_pdata->init_uV);
        if (!ret && (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UA))
                ret = regulator_set_current(dev, uc_pdata->min_uA);
 
@@ -360,6 +422,7 @@ static int regulator_post_bind(struct udevice *dev)
 static int regulator_pre_probe(struct udevice *dev)
 {
        struct dm_regulator_uclass_platdata *uc_pdata;
+       ofnode node;
 
        uc_pdata = dev_get_uclass_platdata(dev);
        if (!uc_pdata)
@@ -370,6 +433,8 @@ static int regulator_pre_probe(struct udevice *dev)
                                                -ENODATA);
        uc_pdata->max_uV = dev_read_u32_default(dev, "regulator-max-microvolt",
                                                -ENODATA);
+       uc_pdata->init_uV = dev_read_u32_default(dev, "regulator-init-microvolt",
+                                                -ENODATA);
        uc_pdata->min_uA = dev_read_u32_default(dev, "regulator-min-microamp",
                                                -ENODATA);
        uc_pdata->max_uA = dev_read_u32_default(dev, "regulator-max-microamp",
@@ -379,6 +444,16 @@ static int regulator_pre_probe(struct udevice *dev)
        uc_pdata->ramp_delay = dev_read_u32_default(dev, "regulator-ramp-delay",
                                                    0);
 
+       node = dev_read_subnode(dev, "regulator-state-mem");
+       if (ofnode_valid(node)) {
+               uc_pdata->suspend_on = !ofnode_read_bool(node, "regulator-off-in-suspend");
+               if (ofnode_read_u32(node, "regulator-suspend-microvolt", &uc_pdata->suspend_uV))
+                       uc_pdata->suspend_uV = uc_pdata->max_uV;
+       } else {
+               uc_pdata->suspend_on = true;
+               uc_pdata->suspend_uV = uc_pdata->max_uV;
+       }
+
        /* Those values are optional (-ENODATA if unset) */
        if ((uc_pdata->min_uV != -ENODATA) &&
            (uc_pdata->max_uV != -ENODATA) &&
@@ -391,6 +466,9 @@ static int regulator_pre_probe(struct udevice *dev)
            (uc_pdata->min_uA == uc_pdata->max_uA))
                uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_UA;
 
+       if (uc_pdata->boot_on)
+               regulator_set_enable(dev, uc_pdata->boot_on);
+
        return 0;
 }