aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-06-27 14:14:38 +0100
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-07-03 20:29:27 +0100
commit65f735082de35aa4d44e8d0afe862798d0e09e29 (patch)
tree9ffdc83c3a0971fb853685503243cdd4dfd752a7 /drivers/regulator
parentregulator: core: Factor out enable and disable operations some more (diff)
downloadlinux-dev-65f735082de35aa4d44e8d0afe862798d0e09e29.tar.xz
linux-dev-65f735082de35aa4d44e8d0afe862798d0e09e29.zip
regulator: core: Add core support for GPIO controlled enable lines
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>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/core.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 82650a16a975..8d81bafcb721 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -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);
}