]> Git Repo - J-u-boot.git/blobdiff - drivers/power/regulator/regulator-uclass.c
power: regulator: Drop regulators_enable_boot_on/off()
[J-u-boot.git] / drivers / power / regulator / regulator-uclass.c
index 9118b8eb39e34ff4266d2d1f8fc9a9f562565885..decd0802c8489af4196c965baf528a9fc29651a7 100644 (file)
@@ -4,20 +4,23 @@
  * Przemyslaw Marczak <[email protected]>
  */
 
-#include <common.h>
+#define LOG_CATEGORY UCLASS_REGULATOR
+
 #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>
 
 int regulator_mode(struct udevice *dev, struct dm_regulator_mode **modep)
 {
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
 
        *modep = NULL;
 
-       uc_pdata = dev_get_uclass_platdata(dev);
+       uc_pdata = dev_get_uclass_plat(dev);
        if (!uc_pdata)
                return -ENXIO;
 
@@ -49,17 +52,19 @@ static void regulator_set_value_ramp_delay(struct udevice *dev, int old_uV,
 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;
+       struct dm_regulator_uclass_plat *uc_pdata;
        int ret, old_uV = uV, is_enabled = 0;
 
-       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!ops || !ops->set_value)
+               return -ENOSYS;
+
+       uc_pdata = dev_get_uclass_plat(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 || !ops->set_value)
-               return -ENOSYS;
+       if (uV == -ENODATA)
+               return -EINVAL;
 
        if (uc_pdata->ramp_delay) {
                is_enabled = regulator_get_enable(dev);
@@ -77,6 +82,35 @@ 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_plat *uc_pdata;
+
+       if (!ops || !ops->set_suspend_value)
+               return -ENOSYS;
+
+       uc_pdata = dev_get_uclass_plat(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 (uV == -ENODATA)
+               return -EINVAL;
+
+       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 || !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.
@@ -104,16 +138,18 @@ int regulator_get_current(struct udevice *dev)
 int regulator_set_current(struct udevice *dev, int uA)
 {
        const struct dm_regulator_ops *ops = dev_get_driver_ops(dev);
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
 
-       uc_pdata = dev_get_uclass_platdata(dev);
+       if (!ops || !ops->set_current)
+               return -ENOSYS;
+
+       uc_pdata = dev_get_uclass_plat(dev);
        if (uc_pdata->min_uA != -ENODATA && uA < uc_pdata->min_uA)
                return -EINVAL;
        if (uc_pdata->max_uA != -ENODATA && uA > uc_pdata->max_uA)
                return -EINVAL;
-
-       if (!ops || !ops->set_current)
-               return -ENOSYS;
+       if (uA == -ENODATA)
+               return -EINVAL;
 
        return ops->set_current(dev, uA);
 }
@@ -131,13 +167,13 @@ int regulator_get_enable(struct udevice *dev)
 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;
+       struct dm_regulator_uclass_plat *uc_pdata;
        int ret, old_enable = 0;
 
        if (!ops || !ops->set_enable)
                return -ENOSYS;
 
-       uc_pdata = dev_get_uclass_platdata(dev);
+       uc_pdata = dev_get_uclass_plat(dev);
        if (!enable && uc_pdata->always_on)
                return -EACCES;
 
@@ -166,10 +202,36 @@ int regulator_set_enable_if_allowed(struct udevice *dev, bool enable)
        ret = regulator_set_enable(dev, enable);
        if (ret == -ENOSYS || ret == -EACCES)
                return 0;
+       /* if we want to disable but it's in use by someone else */
+       if (!enable && ret == -EBUSY)
+               return 0;
+       /* if it's already enabled/disabled */
+       if (ret == -EALREADY)
+               return 0;
 
        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 || !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 || !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);
@@ -192,7 +254,7 @@ int regulator_set_mode(struct udevice *dev, int mode)
 
 int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
 {
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
        struct udevice *dev;
        int ret;
 
@@ -205,7 +267,7 @@ int regulator_get_by_platname(const char *plat_name, struct udevice **devp)
                        continue;
                }
 
-               uc_pdata = dev_get_uclass_platdata(dev);
+               uc_pdata = dev_get_uclass_plat(dev);
                if (!uc_pdata || strcmp(plat_name, uc_pdata->name))
                        continue;
 
@@ -231,29 +293,63 @@ int device_get_supply_regulator(struct udevice *dev, const char *supply_name,
 
 int regulator_autoset(struct udevice *dev)
 {
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
        int ret = 0;
 
-       uc_pdata = dev_get_uclass_platdata(dev);
-       if (!uc_pdata->always_on && !uc_pdata->boot_on)
-               return -EMEDIUMTYPE;
+       uc_pdata = dev_get_uclass_plat(dev);
+
+       if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_DONE)
+               return -EALREADY;
+
+       ret = regulator_set_suspend_enable(dev, uc_pdata->suspend_on);
+       if (ret == -ENOSYS)
+               ret = 0;
+
+       if (!ret && uc_pdata->suspend_on && uc_pdata->suspend_uV != -ENODATA) {
+               ret = regulator_set_suspend_value(dev, uc_pdata->suspend_uV);
+               if (ret == -ENOSYS)
+                       ret = 0;
+
+               if (ret)
+                       return ret;
+       }
+
+       if (uc_pdata->force_off) {
+               ret = regulator_set_enable(dev, false);
+               goto out;
+       }
+
+       if (!uc_pdata->always_on && !uc_pdata->boot_on) {
+               ret = -EMEDIUMTYPE;
+               goto out;
+       }
+
+       if (uc_pdata->type == REGULATOR_TYPE_FIXED) {
+               ret = regulator_set_enable(dev, true);
+               goto out;
+       }
 
        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);
 
        if (!ret)
                ret = regulator_set_enable(dev, true);
 
+out:
+       uc_pdata->flags |= REGULATOR_FLAG_AUTOSET_DONE;
+
        return ret;
 }
 
 static void regulator_show(struct udevice *dev, int ret)
 {
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
 
-       uc_pdata = dev_get_uclass_platdata(dev);
+       uc_pdata = dev_get_uclass_plat(dev);
 
        printf("%s@%s: ", dev->name, uc_pdata->name);
        if (uc_pdata->flags & REGULATOR_FLAG_AUTOSET_UV)
@@ -308,7 +404,7 @@ int regulator_list_autoset(const char *list_platname[],
 static bool regulator_name_is_unique(struct udevice *check_dev,
                                     const char *check_name)
 {
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
        struct udevice *dev;
        int check_len = strlen(check_name);
        int ret;
@@ -319,7 +415,7 @@ static bool regulator_name_is_unique(struct udevice *check_dev,
                if (ret || dev == check_dev)
                        continue;
 
-               uc_pdata = dev_get_uclass_platdata(dev);
+               uc_pdata = dev_get_uclass_plat(dev);
                len = strlen(uc_pdata->name);
                if (len != check_len)
                        continue;
@@ -333,10 +429,12 @@ static bool regulator_name_is_unique(struct udevice *check_dev,
 
 static int regulator_post_bind(struct udevice *dev)
 {
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
        const char *property = "regulator-name";
 
-       uc_pdata = dev_get_uclass_platdata(dev);
+       uc_pdata = dev_get_uclass_plat(dev);
+       uc_pdata->always_on = dev_read_bool(dev, "regulator-always-on");
+       uc_pdata->boot_on = dev_read_bool(dev, "regulator-boot-on");
 
        /* Regulator's mandatory constraint */
        uc_pdata->name = dev_read_string(dev, property);
@@ -348,20 +446,29 @@ static int regulator_post_bind(struct udevice *dev)
                        return -EINVAL;
        }
 
-       if (regulator_name_is_unique(dev, uc_pdata->name))
-               return 0;
+       if (!regulator_name_is_unique(dev, uc_pdata->name)) {
+               debug("'%s' of dev: '%s', has nonunique value: '%s\n",
+                     property, dev->name, uc_pdata->name);
+               return -EINVAL;
+       }
 
-       debug("'%s' of dev: '%s', has nonunique value: '%s\n",
-             property, dev->name, uc_pdata->name);
+       /*
+        * In case the regulator has regulator-always-on or
+        * regulator-boot-on DT property, trigger probe() to
+        * configure its default state during startup.
+        */
+       if (uc_pdata->always_on || uc_pdata->boot_on)
+               dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
 
-       return -EINVAL;
+       return 0;
 }
 
 static int regulator_pre_probe(struct udevice *dev)
 {
-       struct dm_regulator_uclass_platdata *uc_pdata;
+       struct dm_regulator_uclass_plat *uc_pdata;
+       ofnode node;
 
-       uc_pdata = dev_get_uclass_platdata(dev);
+       uc_pdata = dev_get_uclass_plat(dev);
        if (!uc_pdata)
                return -ENXIO;
 
@@ -370,14 +477,25 @@ 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",
                                                -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);
+       uc_pdata->force_off = dev_read_bool(dev, "regulator-force-boot-off");
+
+       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) &&
@@ -394,30 +512,18 @@ static int regulator_pre_probe(struct udevice *dev)
        return 0;
 }
 
-int regulators_enable_boot_on(bool verbose)
+static int regulator_post_probe(struct udevice *dev)
 {
-       struct udevice *dev;
-       struct uclass *uc;
        int ret;
 
-       ret = uclass_get(UCLASS_REGULATOR, &uc);
-       if (ret)
+       ret = regulator_autoset(dev);
+       if (ret && ret != -EMEDIUMTYPE && ret != -EALREADY && ret != ENOSYS)
                return ret;
-       for (uclass_first_device(UCLASS_REGULATOR, &dev);
-            dev;
-            uclass_next_device(&dev)) {
-               ret = regulator_autoset(dev);
-               if (ret == -EMEDIUMTYPE) {
-                       ret = 0;
-                       continue;
-               }
-               if (verbose)
-                       regulator_show(dev, ret);
-               if (ret == -ENOSYS)
-                       ret = 0;
-       }
 
-       return ret;
+       if (_DEBUG)
+               regulator_show(dev, ret);
+
+       return 0;
 }
 
 UCLASS_DRIVER(regulator) = {
@@ -425,6 +531,6 @@ UCLASS_DRIVER(regulator) = {
        .name           = "regulator",
        .post_bind      = regulator_post_bind,
        .pre_probe      = regulator_pre_probe,
-       .per_device_platdata_auto_alloc_size =
-                               sizeof(struct dm_regulator_uclass_platdata),
+       .post_probe     = regulator_post_probe,
+       .per_device_plat_auto   = sizeof(struct dm_regulator_uclass_plat),
 };
This page took 0.034555 seconds and 4 git commands to generate.