* [PATCH 2/5] regulator: core: Add core support for GPIO controlled enable lines
2012-06-27 14:12 [PATCH 1/5] regulator: core: Factor out enable and disable operations some more Mark Brown
@ 2012-06-27 14:12 ` Mark Brown
2012-06-27 14:12 ` [PATCH 3/5] regulator: fixed: Use core GPIO enable support Mark Brown
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2012-06-27 14:12 UTC (permalink / raw)
To: Liam Girdwood; +Cc: linux-kernel, Mark Brown
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 | 35 ++++++++++++++++++++++++++++++++++-
include/linux/regulator/driver.h | 11 +++++++++++
2 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 60329fe..2a3d438 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>
@@ -1450,7 +1451,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;
@@ -1805,6 +1810,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;
@@ -3218,6 +3227,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\n",
+ 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;
@@ -3286,6 +3315,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 */
@@ -3319,6 +3350,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(®ulator_list_mutex);
}
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 176bd43..b1b7b8b 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -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 *
--
1.7.10
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 3/5] regulator: fixed: Use core GPIO enable support
2012-06-27 14:12 [PATCH 1/5] regulator: core: Factor out enable and disable operations some more Mark Brown
2012-06-27 14:12 ` [PATCH 2/5] regulator: core: Add core support for GPIO controlled enable lines Mark Brown
@ 2012-06-27 14:12 ` Mark Brown
2012-06-27 14:12 ` [PATCH 4/5] regulator: wm8994: " Mark Brown
2012-06-27 14:12 ` [PATCH 5/5] regulator: arizona-ldo1: Implement " Mark Brown
3 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2012-06-27 14:12 UTC (permalink / raw)
To: Liam Girdwood; +Cc: linux-kernel, Mark Brown
This is essentially the code that was factored out into the core when the
feature was implemented.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/regulator/fixed.c | 98 ++++-----------------------------------------
1 file changed, 8 insertions(+), 90 deletions(-)
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index f7b2642..4d12b62 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -35,9 +35,6 @@ struct fixed_voltage_data {
struct regulator_desc desc;
struct regulator_dev *dev;
int microvolts;
- int gpio;
- bool enable_high;
- bool is_enabled;
};
@@ -95,33 +92,6 @@ of_get_fixed_voltage_config(struct device *dev)
return config;
}
-static int fixed_voltage_is_enabled(struct regulator_dev *dev)
-{
- struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
- return data->is_enabled;
-}
-
-static int fixed_voltage_enable(struct regulator_dev *dev)
-{
- struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
- gpio_set_value_cansleep(data->gpio, data->enable_high);
- data->is_enabled = true;
-
- return 0;
-}
-
-static int fixed_voltage_disable(struct regulator_dev *dev)
-{
- struct fixed_voltage_data *data = rdev_get_drvdata(dev);
-
- gpio_set_value_cansleep(data->gpio, !data->enable_high);
- data->is_enabled = false;
-
- return 0;
-}
-
static int fixed_voltage_get_voltage(struct regulator_dev *dev)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
@@ -143,14 +113,6 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev,
return data->microvolts;
}
-static struct regulator_ops fixed_voltage_gpio_ops = {
- .is_enabled = fixed_voltage_is_enabled,
- .enable = fixed_voltage_enable,
- .disable = fixed_voltage_disable,
- .get_voltage = fixed_voltage_get_voltage,
- .list_voltage = fixed_voltage_list_voltage,
-};
-
static struct regulator_ops fixed_voltage_ops = {
.get_voltage = fixed_voltage_get_voltage,
.list_voltage = fixed_voltage_list_voltage,
@@ -187,6 +149,7 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
}
drvdata->desc.type = REGULATOR_VOLTAGE;
drvdata->desc.owner = THIS_MODULE;
+ drvdata->desc.ops = &fixed_voltage_ops;
drvdata->desc.enable_time = config->startup_delay;
@@ -194,53 +157,13 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.n_voltages = 1;
drvdata->microvolts = config->microvolts;
- drvdata->gpio = config->gpio;
-
- if (gpio_is_valid(config->gpio)) {
- int gpio_flag;
- drvdata->enable_high = config->enable_high;
-
- /* FIXME: Remove below print warning
- *
- * config->gpio must be set to -EINVAL by platform code if
- * GPIO control is not required. However, early adopters
- * not requiring GPIO control may forget to initialize
- * config->gpio to -EINVAL. This will cause GPIO 0 to be used
- * for GPIO control.
- *
- * This warning will be removed once there are a couple of users
- * for this driver.
- */
- if (!config->gpio)
- dev_warn(&pdev->dev,
- "using GPIO 0 for regulator enable control\n");
-
- /*
- * set output direction without changing state
- * to prevent glitch
- */
- drvdata->is_enabled = config->enabled_at_boot;
- ret = drvdata->is_enabled ?
- config->enable_high : !config->enable_high;
- gpio_flag = ret ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-
- if (config->gpio_is_open_drain)
- gpio_flag |= GPIOF_OPEN_DRAIN;
-
- ret = gpio_request_one(config->gpio, gpio_flag,
- config->supply_name);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not obtain regulator enable GPIO %d: %d\n",
- config->gpio, ret);
- goto err_name;
- }
-
- drvdata->desc.ops = &fixed_voltage_gpio_ops;
- } else {
- drvdata->desc.ops = &fixed_voltage_ops;
- }
+ cfg.ena_gpio = config->gpio;
+ cfg.ena_gpio_invert = !config->enable_high;
+ if (config->enabled_at_boot)
+ cfg.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
+ if (config->gpio_is_open_drain)
+ cfg.ena_gpio_flags |= GPIOF_OPEN_DRAIN;
cfg.dev = &pdev->dev;
cfg.init_data = config->init_data;
@@ -251,7 +174,7 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
- goto err_gpio;
+ goto err_name;
}
platform_set_drvdata(pdev, drvdata);
@@ -261,9 +184,6 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
return 0;
-err_gpio:
- if (gpio_is_valid(config->gpio))
- gpio_free(config->gpio);
err_name:
kfree(drvdata->desc.name);
err:
@@ -275,8 +195,6 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)
struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
regulator_unregister(drvdata->dev);
- if (gpio_is_valid(drvdata->gpio))
- gpio_free(drvdata->gpio);
kfree(drvdata->desc.name);
return 0;
--
1.7.10
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 4/5] regulator: wm8994: Use core GPIO enable support
2012-06-27 14:12 [PATCH 1/5] regulator: core: Factor out enable and disable operations some more Mark Brown
2012-06-27 14:12 ` [PATCH 2/5] regulator: core: Add core support for GPIO controlled enable lines Mark Brown
2012-06-27 14:12 ` [PATCH 3/5] regulator: fixed: Use core GPIO enable support Mark Brown
@ 2012-06-27 14:12 ` Mark Brown
2012-06-27 14:12 ` [PATCH 5/5] regulator: arizona-ldo1: Implement " Mark Brown
3 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2012-06-27 14:12 UTC (permalink / raw)
To: Liam Girdwood; +Cc: linux-kernel, Mark Brown
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/regulator/wm8994-regulator.c | 67 ++--------------------------------
1 file changed, 4 insertions(+), 63 deletions(-)
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index 7a1fd77..f68abd1 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -26,8 +26,6 @@
#include <linux/mfd/wm8994/pdata.h>
struct wm8994_ldo {
- int enable;
- bool is_enabled;
struct regulator_dev *regulator;
struct wm8994 *wm8994;
};
@@ -35,46 +33,7 @@ struct wm8994_ldo {
#define WM8994_LDO1_MAX_SELECTOR 0x7
#define WM8994_LDO2_MAX_SELECTOR 0x3
-static int wm8994_ldo_enable(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
- /* If we have no soft control assume that the LDO is always enabled. */
- if (!ldo->enable)
- return 0;
-
- gpio_set_value_cansleep(ldo->enable, 1);
- ldo->is_enabled = true;
-
- return 0;
-}
-
-static int wm8994_ldo_disable(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
- /* If we have no soft control assume that the LDO is always enabled. */
- if (!ldo->enable)
- return -EINVAL;
-
- gpio_set_value_cansleep(ldo->enable, 0);
- ldo->is_enabled = false;
-
- return 0;
-}
-
-static int wm8994_ldo_is_enabled(struct regulator_dev *rdev)
-{
- struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
-
- return ldo->is_enabled;
-}
-
static struct regulator_ops wm8994_ldo1_ops = {
- .enable = wm8994_ldo_enable,
- .disable = wm8994_ldo_disable,
- .is_enabled = wm8994_ldo_is_enabled,
-
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -108,9 +67,6 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
}
static struct regulator_ops wm8994_ldo2_ops = {
- .enable = wm8994_ldo_enable,
- .disable = wm8994_ldo_disable,
- .is_enabled = wm8994_ldo_is_enabled,
.enable_time = wm8994_ldo_enable_time,
.list_voltage = wm8994_ldo2_list_voltage,
@@ -164,39 +120,26 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
ldo->wm8994 = wm8994;
- if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
- ldo->enable = pdata->ldo[id].enable;
-
- ret = gpio_request_one(ldo->enable, 0, "WM8994 LDO enable");
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n",
- ret);
- goto err;
- }
- } else
- ldo->is_enabled = true;
-
config.dev = wm8994->dev;
config.driver_data = ldo;
config.regmap = wm8994->regmap;
- if (pdata)
+ if (pdata) {
config.init_data = pdata->ldo[id].init_data;
+ config.ena_gpio = pdata->ldo[id].enable;
+ }
ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &config);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
id + 1, ret);
- goto err_gpio;
+ goto err;
}
platform_set_drvdata(pdev, ldo);
return 0;
-err_gpio:
- if (gpio_is_valid(ldo->enable))
- gpio_free(ldo->enable);
err:
return ret;
}
@@ -208,8 +151,6 @@ static __devexit int wm8994_ldo_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
regulator_unregister(ldo->regulator);
- if (gpio_is_valid(ldo->enable))
- gpio_free(ldo->enable);
return 0;
}
--
1.7.10
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 5/5] regulator: arizona-ldo1: Implement GPIO enable support
2012-06-27 14:12 [PATCH 1/5] regulator: core: Factor out enable and disable operations some more Mark Brown
` (2 preceding siblings ...)
2012-06-27 14:12 ` [PATCH 4/5] regulator: wm8994: " Mark Brown
@ 2012-06-27 14:12 ` Mark Brown
3 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2012-06-27 14:12 UTC (permalink / raw)
To: Liam Girdwood; +Cc: linux-kernel, Mark Brown
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
drivers/regulator/arizona-ldo1.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index 51f02ca..c8f95c0 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -57,6 +57,9 @@ static const struct regulator_desc arizona_ldo1 = {
};
static const struct regulator_init_data arizona_ldo1_default = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
.num_consumer_supplies = 1,
};
@@ -88,6 +91,7 @@ static __devinit int arizona_ldo1_probe(struct platform_device *pdev)
config.dev = arizona->dev;
config.driver_data = ldo1;
config.regmap = arizona->regmap;
+ config.ena_gpio = arizona->pdata.ldoena;
if (arizona->pdata.ldo1)
config.init_data = arizona->pdata.ldo1;
--
1.7.10
^ permalink raw reply [flat|nested] 5+ messages in thread