]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
regulator: core: Add core support for GPIO controlled enable lines
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 27 Jun 2012 13:14:38 +0000 (14:14 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 3 Jul 2012 19:29:27 +0000 (20:29 +0100)
It is very common for regulators to support having their enable signal
controlled by a GPIO. Since there are a bunch of fiddly things to get
right like handling the operations when the enable signal is tied to
a rail and it's just replicated code add support for this to the core.

Drivers should set ena_gpio in their config if they have a GPIO control,
using ena_gpio_flags to specify any flags (including GPIOF_OUT_INIT_ for
the initial state) and ena_gpio_invert if the GPIO is active low. The
core will then override any enable and disable operations the driver has
and instead control the specified GPIO.

This will in the future also allow us to further extend the core by
identifying when several enable signals have been tied together and
handling this properly.

Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
drivers/regulator/core.c
include/linux/regulator/driver.h

index 82650a16a975096543665840af5e01d6804f542d..8d81bafcb721b087048e2c0095871ea90ad8bf7d 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mutex.h>
 #include <linux/suspend.h>
 #include <linux/delay.h>
+#include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
@@ -1491,7 +1492,11 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
 
        trace_regulator_enable(rdev_get_name(rdev));
 
-       if (rdev->desc->ops->enable) {
+       if (rdev->ena_gpio) {
+               gpio_set_value_cansleep(rdev->ena_gpio,
+                                       !rdev->ena_gpio_invert);
+               rdev->ena_gpio_state = 1;
+       } else if (rdev->desc->ops->enable) {
                ret = rdev->desc->ops->enable(rdev);
                if (ret < 0)
                        return ret;
@@ -1846,6 +1851,10 @@ EXPORT_SYMBOL_GPL(regulator_disable_regmap);
 
 static int _regulator_is_enabled(struct regulator_dev *rdev)
 {
+       /* A GPIO control always takes precedence */
+       if (rdev->ena_gpio)
+               return rdev->ena_gpio_state;
+
        /* If we don't know then assume that the regulator is always on */
        if (!rdev->desc->ops->is_enabled)
                return 1;
@@ -3243,6 +3252,26 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        dev_set_drvdata(&rdev->dev, rdev);
 
+       if (config->ena_gpio) {
+               ret = gpio_request_one(config->ena_gpio,
+                                      GPIOF_DIR_OUT | config->ena_gpio_flags,
+                                      rdev_get_name(rdev));
+               if (ret != 0) {
+                       rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
+                                config->ena_gpio, ret);
+                       goto clean;
+               }
+
+               rdev->ena_gpio = config->ena_gpio;
+               rdev->ena_gpio_invert = config->ena_gpio_invert;
+
+               if (config->ena_gpio_flags & GPIOF_OUT_INIT_HIGH)
+                       rdev->ena_gpio_state = 1;
+
+               if (rdev->ena_gpio_invert)
+                       rdev->ena_gpio_state = !rdev->ena_gpio_state;
+       }
+
        /* set regulator constraints */
        if (init_data)
                constraints = &init_data->constraints;
@@ -3311,6 +3340,8 @@ unset_supplies:
 scrub:
        if (rdev->supply)
                regulator_put(rdev->supply);
+       if (rdev->ena_gpio)
+               gpio_free(rdev->ena_gpio);
        kfree(rdev->constraints);
        device_unregister(&rdev->dev);
        /* device core frees rdev */
@@ -3344,6 +3375,8 @@ void regulator_unregister(struct regulator_dev *rdev)
        unset_regulator_supplies(rdev);
        list_del(&rdev->list);
        kfree(rdev->constraints);
+       if (rdev->ena_gpio)
+               gpio_free(rdev->ena_gpio);
        device_unregister(&rdev->dev);
        mutex_unlock(&regulator_list_mutex);
 }
index 176bd4335581701ab73c0d0d8403b0d5d47026c5..b1b7b8b43ece12b29a8e915ff8fa00a2769ebf77 100644 (file)
@@ -220,6 +220,9 @@ struct regulator_desc {
  * @of_node: OpenFirmware node to parse for device tree bindings (may be
  *           NULL).
  * @regmap: regmap to use for core regmap helpers
+ * @ena_gpio: GPIO controlling regulator enable.
+ * @ena_gpio_invert: Sense for GPIO enable control.
+ * @ena_gpio_flags: Flags to use when calling gpio_request_one()
  */
 struct regulator_config {
        struct device *dev;
@@ -227,6 +230,10 @@ struct regulator_config {
        void *driver_data;
        struct device_node *of_node;
        struct regmap *regmap;
+
+       int ena_gpio;
+       unsigned int ena_gpio_invert:1;
+       unsigned int ena_gpio_flags;
 };
 
 /*
@@ -265,6 +272,10 @@ struct regulator_dev {
        void *reg_data;         /* regulator_dev data */
 
        struct dentry *debugfs;
+
+       int ena_gpio;
+       unsigned int ena_gpio_invert:1;
+       unsigned int ena_gpio_state:1;
 };
 
 struct regulator_dev *