regulator: Add GPIO enable control to fixed voltage regulator driver
PATCH v2 1/1 regulator: Add GPIO enable control to fixed voltage regulator driver
From: Roger Quadros <[email protected]>
Now fixed regulators that have their enable pin connected to a GPIO line can use the fixed regulator driver. The GPIO number and polarity information is passed through platform data. GPIO enable control is acheived using gpiolib.
--- drivers/regulator/fixed.c | 66 +++++++++++++++++++++++++++++++++++++- include/linux/regulator/fixed.h | 17 ++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-)
drivers/regulator/fixed.c +64 -2
@@ -20,20 +20,50 @@#include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/fixed.h> +#include <linux/gpio.h> struct fixed_voltage_data {struct regulator_desc desc;struct regulator_dev *dev;int microvolts; +int gpio; +int enable_high; +int is_enabled; };static int fixed_voltage_is_enabled (struct regulator_dev *dev) { -return 1 ; +struct fixed_voltage_data *data =rdev_get_drvdata (dev); + +if (data->gpio) +return data->is_enabled; +else +return 1 ; }static int fixed_voltage_enable (struct regulator_dev *dev) { +struct fixed_voltage_data *data =rdev_get_drvdata (dev); + +if (data->gpio) { +gpio_set_value (data->gpio, + data->enable_high ?1 :0 ); + data->is_enabled =1 ; + } + +return 0 ; +} + +static int fixed_voltage_disable (struct regulator_dev *dev) +{ +struct fixed_voltage_data *data =rdev_get_drvdata (dev); + +if (data->gpio) { +gpio_set_value (data->gpio, + data->enable_high ?0 :1 ); + data->is_enabled =0 ; + } +return 0 ; }
@@ -58,6 +88,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev,static struct regulator_ops fixed_voltage_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, };
@@ -85,12 +116,37 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.n_voltages =1 ; drvdata->microvolts = config->microvolts; +if (config->gpio) { + drvdata->gpio = config->gpio; + drvdata->enable_high = config->enable_high; + + ret =gpio_request (config->gpio, + config->supply_name); +if (ret) { +dev_err (&pdev->dev,"Could not obtain regulator" +"enable GPIO %d: %d\n" , config->gpio, ret); + goto err_name; + } + +/* set output direction without changing state +* to prevent glitch +*/ + ret =gpio_get_value (config->gpio); + ret =gpio_direction_output (config->gpio, ret); +if (ret) { +dev_err (&pdev->dev,"Could not configure " +"enable GPIO %d direction: %d\n" , + config->gpio, ret); + goto err_gpio; + } + }else +dev_warn (&pdev->dev,"Not using GPIO 0 for enable control\n" ); drvdata->dev =regulator_register (&drvdata->desc, &pdev->dev, config->init_data, drvdata);if (IS_ERR (drvdata->dev)) { ret =PTR_ERR (drvdata->dev); - goto err_name; + goto err_gpio; }platform_set_drvdata (pdev, drvdata);
@@ -100,6 +156,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)return 0 ; +err_gpio: +if (config->gpio) +gpio_free (config->gpio); err_name:kfree (drvdata->desc.name); err:
@@ -115,6 +174,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)kfree (drvdata->desc.name);kfree (drvdata); +if (drvdata->gpio) +gpio_free (drvdata->gpio); +return 0 ; }
include/linux/regulator/fixed.h +17 -0
@@ -16,9 +16,26 @@struct regulator_init_data ; +/** +* struct fixed_voltage_config - fixed_voltage_config structure +* @supply_name: Name of the regulator supply +* @microvolts: Output voltage of regulator +* @use_gpio_control: Use GPIO enable control +* @gpio: GPIO to use for enable control +* @enable_high: Polarity of enable GPIO +* 1 = Active high, 0 = Active low +* @init_data: regulator_init_data +* +* This structure contains fixed voltage regulator configuration +* information that must be passed by platform code to the fixed +* voltage regulator driver. +*/ struct fixed_voltage_config {const char *supply_name;int microvolts; +int use_gpio_control; +int gpio; +int enable_high;struct regulator_init_data *init_data; };
Signature · 1 line
1.6.0.4
Quoted 6 lines · ext Roger Quadros
From: Roger Quadros <[email protected]>
Now fixed regulators that have their enable pin connected to a GPIO line can use the fixed regulator driver. The GPIO number and polarity information is passed through platform data. GPIO enable control is acheived using gpiolib.
little typo here.
Quoted 16 lines
Signed-off-by Roger Quadros <[email protected]>Reviewed-by Mark Brown <[email protected]>Reviewed-by Philipp Zabel <[email protected]>--- drivers/regulator/fixed.c | 66 +++++++++++++++++++++++++++++++++++++- include/linux/regulator/fixed.h | 17 ++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-)drivers/regulator/fixed.c +0
-0@@ -20,20 +20,50 @@#include <linux/platform_device.h> #include <linux/regulator/driver.h>
drivers/regulator/fixed.c line 31
Quoted 10 lines
drivers/regulator/fixed.c +4
-0#include <linux/regulator/fixed.h> +#include <linux/gpio.h> struct fixed_voltage_data {struct regulator_desc desc;struct regulator_dev *dev;int microvolts; +int gpio; +int enable_high; +int is_enabled;
how about making these two:
unsigned enable_high:1;
unsigned is_enabled:1;
Quoted 10 lines
drivers/regulator/fixed.c +5
-1};static int fixed_voltage_is_enabled (struct regulator_dev *dev) { -return 1 ; +struct fixed_voltage_data *data =rdev_get_drvdata (dev); + +if (data->gpio) +return data->is_enabled; +else
drivers/regulator/fixed.c line 50
Quoted 10 lines
drivers/regulator/fixed.c +6
-0+return 1 ; }static int fixed_voltage_enable (struct regulator_dev *dev) { +struct fixed_voltage_data *data =rdev_get_drvdata (dev); + +if (data->gpio) { +gpio_set_value (data->gpio, + data->enable_high ?1 :0 );
gpio_set_value(data->gpio, data->enable_high);
should be enough, no ?
drivers/regulator/fixed.c line 63
Quoted 13 lines
drivers/regulator/fixed.c +13
-0+ data->is_enabled =1 ; + } + +return 0 ; +} + +static int fixed_voltage_disable (struct regulator_dev *dev) +{ +struct fixed_voltage_data *data =rdev_get_drvdata (dev); + +if (data->gpio) { +gpio_set_value (data->gpio, + data->enable_high ?0 :1 );
gpio_set_value(data->gpio, !data->enable_high); ??
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 119
Quoted 5 lines
drivers/regulator/fixed.c +1
-0@@ -85,12 +116,37 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.n_voltages =1 ; drvdata->microvolts = config->microvolts; +if (config->gpio) {
gpio_is_valid() since 0 is a valid gpio number.
Quoted 5 lines
drivers/regulator/fixed.c +5
-0+ drvdata->gpio = config->gpio; + drvdata->enable_high = config->enable_high; + + ret =gpio_request (config->gpio, + config->supply_name);
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 134
Quoted 10 lines
drivers/regulator/fixed.c +10
-0+if (ret) { +dev_err (&pdev->dev,"Could not obtain regulator" +"enable GPIO %d: %d\n" , config->gpio, ret); + goto err_name; + } + +/* set output direction without changing state +* to prevent glitch +*/ + ret =gpio_get_value (config->gpio);
and if this fails ??
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 135
Quoted 1 line
drivers/regulator/fixed.c +1
-0+ ret =gpio_direction_output (config->gpio, ret);
you continue anyways...
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 142
Quoted 7 lines
drivers/regulator/fixed.c +7
-0+if (ret) { +dev_err (&pdev->dev,"Could not configure " +"enable GPIO %d direction: %d\n" , + config->gpio, ret); + goto err_gpio; + } + }else
this should have brackets.
Quoted 12 lines
drivers/regulator/fixed.c +2
-1+dev_warn (&pdev->dev,"Not using GPIO 0 for enable control\n" ); drvdata->dev =regulator_register (&drvdata->desc, &pdev->dev, config->init_data, drvdata);if (IS_ERR (drvdata->dev)) { ret =PTR_ERR (drvdata->dev); - goto err_name; + goto err_gpio; }platform_set_drvdata (pdev, drvdata);
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 160
Quoted 5 lines
drivers/regulator/fixed.c +2
-0@@ -100,6 +156,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)return 0 ; +err_gpio: +if (config->gpio)
0 is a valid gpio number, you should initialize everyone using this to -EINVAL, for example, and use gpio_is_valid()
drivers/regulator/fixed.c static int regulator_fixed_voltage_remove(struct platform_device *pdev) · line 177
Quoted 9 lines
drivers/regulator/fixed.c +2
-0+gpio_free (config->gpio); err_name:kfree (drvdata->desc.name); err:@@ -115,6 +174,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)kfree (drvdata->desc.name);kfree (drvdata); +if (drvdata->gpio)
likewise, use gpio_is_valid()
Quoted 22 lines
drivers/regulator/fixed.c +2
-0+gpio_free (drvdata->gpio); +return 0 ; }include/linux/regulator/fixed.h +9
-0@@ -16,9 +16,26 @@struct regulator_init_data ; +/** +* struct fixed_voltage_config - fixed_voltage_config structure +* @supply_name: Name of the regulator supply +* @microvolts: Output voltage of regulator +* @use_gpio_control: Use GPIO enable control +* @gpio: GPIO to use for enable control +* @enable_high: Polarity of enable GPIO +* 1 = Active high, 0 = Active low +* @init_data: regulator_init_data
include/linux/regulator/fixed.h line 37
Quoted 10 lines
include/linux/regulator/fixed.h +7
-0+* +* This structure contains fixed voltage regulator configuration +* information that must be passed by platform code to the fixed +* voltage regulator driver. +*/ struct fixed_voltage_config {const char *supply_name;int microvolts; +int use_gpio_control; +int gpio;
put a comment for this field asking people to intialized to -EINVAL if they're not gonna use it.
include/linux/regulator/fixed.h line 38
Quoted 1 line
include/linux/regulator/fixed.h +1
-0+int enable_high;
unsigned enable_high:1;
Signature · 1 line
balbi
Quoted 31 lines · Roger Quadros
From: Roger Quadros <[email protected]>
Now fixed regulators that have their enable pin connected to a GPIO line can use the fixed regulator driver. The GPIO number and polarity information is passed through platform data. GPIO enable control is acheived using gpiolib.
Signed-off-by Roger Quadros <[email protected]>Reviewed-by Mark Brown <[email protected]>Reviewed-by Philipp Zabel <[email protected]>---
drivers/regulator/fixed.c | 66 +++++++++++++++++++++++++++++++++++++-include/linux/regulator/fixed.h| 17 ++++++++++2 files changed, 81 insertions(+), 2 deletions(-)drivers/regulator/fixed.c +2
-0@@ -20,20 +20,50 @@ #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/fixed.h> +#include <linux/gpio.h> struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; int microvolts; + int gpio;
drivers/regulator/fixed.c line 38
Quoted 10 lines
drivers/regulator/fixed.c +5
-1+ int enable_high; + int is_enabled; }; static int fixed_voltage_is_enabled(struct regulator_dev *dev) { - return 1; + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + if (data->gpio)
if (gpio_is_valid(data->gpio))
drivers/regulator/fixed.c line 42
Quoted 4 lines
drivers/regulator/fixed.c +3
-0+ return data->is_enabled; + else + return 1; }
Or this function could just unconditionally return data->is_enabled if you set it to 1 in _probe for gpio-less regulators.
drivers/regulator/fixed.c line 48
Quoted 6 lines
drivers/regulator/fixed.c +3
-0static int fixed_voltage_enable(struct regulator_dev *dev) { + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + if (data->gpio) {
if (gpio_is_valid(data->gpio)) {
Quoted 30 lines
drivers/regulator/fixed.c +19
-0+ gpio_set_value(data->gpio, + data->enable_high ? 1 : 0); + data->is_enabled = 1; + } + + return 0; +} + +static int fixed_voltage_disable (struct regulator_dev *dev) +{ + struct fixed_voltage_data *data = rdev_get_drvdata(dev); + + if (data->gpio) { + gpio_set_value(data->gpio, + data->enable_high ? 0 : 1); + data->is_enabled = 0; + } + return 0; }@@ -58,6 +88,7 @@ static int fixed_voltage_list_voltage(struct regulator_dev *dev, static struct regulator_ops fixed_voltage_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, };
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 119
Quoted 4 lines
drivers/regulator/fixed.c +1
-0@@ -85,12 +116,37 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) drvdata->desc.n_voltages = 1; drvdata->microvolts = config->microvolts; + if (config->gpio) {
That should be more like
if (gpio_is_valid(config->gpio) && config->gpio) {People are going to set config->gpio to negative values to disable the gpio. (And I think eventually GPIO0 should be allowed here.)
Quoted 35 lines
drivers/regulator/fixed.c +25
-1+ drvdata->gpio = config->gpio; + drvdata->enable_high = config->enable_high; + + ret = gpio_request(config->gpio, + config->supply_name); + if (ret) { + dev_err(&pdev->dev, "Could not obtain regulator" + "enable GPIO %d: %d\n", config->gpio, ret); + goto err_name; + } + + /* set output direction without changing state + * to prevent glitch + */ + ret = gpio_get_value(config->gpio); + ret = gpio_direction_output(config->gpio, ret); + if (ret) { + dev_err(&pdev->dev, "Could not configure " + "enable GPIO %d direction: %d\n", + config->gpio, ret); + goto err_gpio; + } + } else + dev_warn(&pdev->dev, "Not using GPIO 0 for enable control\n"); drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, config->init_data, drvdata); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); - goto err_name; + goto err_gpio; } platform_set_drvdata(pdev, drvdata);
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 161
Quoted 6 lines
drivers/regulator/fixed.c +3
-0@@ -100,6 +156,9 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev) return 0; +err_gpio: + if (config->gpio) + gpio_free(config->gpio);
gpio_is_valid(config->gpio)
drivers/regulator/fixed.c static int regulator_fixed_voltage_remove(struct platform_device *pdev) · line 179
Quoted 10 lines
err_name:
kfree(drvdata->desc.name);
err:drivers/regulator/fixed.c +3
-0@@ -115,6 +174,9 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev) kfree(drvdata->desc.name); kfree(drvdata); + if (drvdata->gpio) + gpio_free(drvdata->gpio); +
dito
Quoted 19 lines
drivers/regulator/fixed.c +0
-0return 0; }include/linux/regulator/fixed.h +8
-0@@ -16,9 +16,26 @@ struct regulator_init_data; +/** +* struct fixed_voltage_config - fixed_voltage_config structure +* @supply_name: Name of the regulator supply +* @microvolts: Output voltage of regulator +* @use_gpio_control: Use GPIO enable control +* @gpio: GPIO to use for enable control +* @enable_high: Polarity of enable GPIO +* 1 = Active high, 0 = Active low
include/linux/regulator/fixed.h line 36
Quoted 10 lines
include/linux/regulator/fixed.h +7
-0+* @init_data: regulator_init_data +* +* This structure contains fixed voltage regulator configuration +* information that must be passed by platform code to the fixed +* voltage regulator driver. +*/ struct fixed_voltage_config { const char *supply_name; int microvolts; + int use_gpio_control;
You wanted to drop that, it's not used anymore.
Quoted 9 lines
include/linux/regulator/fixed.h +2
-1+ int gpio; + int enable_high; struct regulator_init_data *init_data; }; --1.6.0.4
regards
Philipp
Quoted 2 lines · Roger Quadros
Signed-off-by Roger Quadros <[email protected]>Reviewed-by Mark Brown <[email protected]>
Err... no, it isn't. I reviewed a previous version of the patch but there were some issues that needed fixing. I've not reviewed this version.
drivers/regulator/fixed.c line 39
Quoted 7 lines
static int
fixed_voltage_is_enabled(struct regulator_dev *dev){drivers/regulator/fixed.c +4
-1-return 1 ; +struct fixed_voltage_data *data =rdev_get_drvdata (dev); + +if (data->gpio) +return data->is_enabled;
Please use gpio_is_valid() as Phillip previously suggested. For this particular use you could simplify the code marginally by just setting is_enabled at probe() time if there's no GPIO, not that it really matters.
drivers/regulator/fixed.c line 50
Quoted 3 lines
drivers/regulator/fixed.c +3
-0+if (data->gpio) { +gpio_set_value (data->gpio, + data->enable_high ?1 :0 );
_cansleep(), please, as previously requested.
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 134
Quoted 1 line
drivers/regulator/fixed.c +1
-0+ ret =gpio_get_value (config->gpio);
Can this fail? It returns an int...
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 140
Quoted 6 lines
drivers/regulator/fixed.c +6
-0+ ret =gpio_direction_output (config->gpio, ret); +if (ret) { +dev_err (&pdev->dev,"Could not configure " +"enable GPIO %d direction: %d\n" , + config->gpio, ret); + goto err_gpio;
As previously requested please don't split for log messages text over lines unless you have to. It makes it easier to find the message from a kernel log - grep for 'configure enable GPIO' won't match this source file the way you've written it above.
drivers/regulator/fixed.c static int regulator_fixed_voltage_probe(struct platform_device *pdev) · line 143
Quoted 3 lines
drivers/regulator/fixed.c +3
-0+ } + }else +dev_warn (&pdev->dev,"Not using GPIO 0 for enable control\n" );
Probably better to soldier on and use the GPIO here but either way is fine; the warning is for the benefit of existing out of tree users to help them transition gracefully.
Quoted 26 lines · Mark Brown
Quoted 2 lines · Roger Quadros
Signed-off-by Roger Quadros <[email protected]>Reviewed-by Mark Brown <[email protected]>Err... no, it isn't. I reviewed a previous version of the patch but there were some issues that needed fixing. I've not reviewed this version.
Quoted 7 lines
static int
fixed_voltage_is_enabled(struct regulator_dev *dev){
- return 1;
+ structfixed_voltage_data*data =rdev_get_drvdata(dev); +
+ if (data->gpio)
+ returndata->is_enabled;Please use
gpio_is_valid()as Phillip previously suggested. For this particular use you could simplify the code marginally by just settingis_enabledatprobe()time if there's no GPIO, not that it really matters.Quoted 3 lines
+ if (
data->gpio) {
+ gpio_set_value(data->gpio,
+data->enable_high? 1 : 0);
Quoted 5 lines
_cansleep(), please, as previously requested.Quoted 1 line
+ ret =
gpio_get_value(config->gpio);Can this fail? It returns an int...
No, gpio_get_value(_cansleep) return either zero or non-zero. I think some I2C gpio chips just return zero when the read fails. Also that's the return value if a gpiochip doesn't define the .get method.
Only problem: drivers/gpio/gpiolib.c contains this piece of wisdom:
/* Drivers MUST set GPIO direction before making get/set calls. In
* some cases this is done in early boot, before IRQs are enabled. [...]
*/
Quoted 12 lines
Quoted 6 lines
+ ret =
gpio_direction_output(config->gpio, ret);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not configure "
+ "enable GPIO %d direction: %d\n",
+config->gpio, ret);
+ gotoerr_gpio;As previously requested please don't split for log messages text over lines unless you have to. It makes it easier to find the message from a kernel log - grep for 'configure enable GPIO' won't match this source file the way you've written it above.
Quoted 8 lines
Quoted 3 lines
+ }
+ } else
+dev_warn(&pdev->dev, "Not using GPIO 0 for enable control\n");Probably better to soldier on and use the GPIO here but either way is fine; the warning is for the benefit of existing out of tree users to help them transition gracefully.
regards
Philipp
Quoted 13 lines · pHilipp Zabel
Quoted 6 lines · Mark Brown
Quoted 1 line · Roger Quadros
+ ret =
gpio_get_value(config->gpio);Can this fail? It returns an int...
No,
gpio_get_value(_cansleep)return either zero or non-zero. I think some I2C gpio chips just return zero when the read fails. Also that's the return value if a gpiochip doesn't define the .get method.
Quoted 7 lines
Only problem:
drivers/gpio/gpiolib.ccontains this piece of wisdom:/* Drivers MUST set GPIO direction before making get/set calls. In
* some cases this is done in early boot, before IRQs are enabled. [...]
*/
Not having gpio_get_direction() in gpiolib is a limitation I think. Can we just do the following for now ? (i.e. disable regulator by default) Will there be any glitch? If yes, then how?
ret = gpio_request(config->gpio, config->supply_name);
...- ret = gpio_get_value(config->gpio);
- ret = gpio_direction_output(config->gpio, ret);
+ ret = gpio_direction_output(config->gpio, !config->enable_high);
if (ret) {
dev_err(&pdev->dev, "Could not configure
enable GPIO %d direction: %d\n",
config->gpio, ret);
goto err_gpio;
}Quoted 3 lines · Roger Quadros
Not having
gpio_get_direction()in gpiolib is a limitation I think. Can we just do the following for now ? (i.e. disable regulator by default) Will there be any glitch? If yes, then how?
If you're going to do this then like I say you should make the default state controllable by platform data. If we unconditionally disable the regulator then if, for example, the regulator is controlling the display backlight and it's on when Linux get controls then the user will see the backlight blink off then on during startup.
Quoted 6 lines · Mark Brown
Quoted 3 lines · Roger Quadros
Not having
gpio_get_direction()in gpiolib is a limitation I think. Can we just do the following for now ? (i.e. disable regulator by default) Will there be any glitch? If yes, then how?
Quoted 6 lines
If you're going to do this then like I say you should make the default state controllable by platform data. If we unconditionally disable the regulator then if, for example, the regulator is controlling the display backlight and it's on when Linux get controls then the user will see the backlight blink off then on during startup.
OK I will add another bit for this in fixed_voltage_config.
Do we need to check whether CONFIG_GPIOLIB is available? or do we need to explicitly
select it in Kconfig?
Quoted 3 lines · Roger Quadros
Do we need to check whether
CONFIG_GPIOLIBis available? or do we need to explicitly
select it inKconfig?
Check but I think that all the APIs you are using are stubbed out if gpiolib is not available so you can just ignore it. If not then ifdefs around the code are the way forward.