diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2014-01-29 19:59:29 +0530 |
---|---|---|
committer | Laxman Dewangan <ldewangan@nvidia.com> | 2014-01-29 22:56:25 -0800 |
commit | e1fb320687c20a45179d32691de6229393d20625 (patch) | |
tree | 61393be5987a1aa9ddf086d32ea4b931b793d5dc /drivers | |
parent | fe90cad939cf979fc2516a96e5911bd8ab6fc457 (diff) |
regulator: pwm: add support for enable and mode gpio
Add supports for:
- enable gpio which enable/disable the regulator.
- idle gpio which is require to set the regulator mode.
Change-Id: I9b31514542462bf2a3dd024cf799fbbe18ef86f4
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/361549
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/regulator/pwm-regulator.c | 97 |
1 files changed, 93 insertions, 4 deletions
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 4192114f0cac..416a158a162a 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -21,6 +21,9 @@ #include <linux/module.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/pwm.h> #include <linux/regulator/driver.h> @@ -40,6 +43,9 @@ struct pwm_regulator { unsigned int uV_step; unsigned int n_voltages; unsigned int curr_selector; + int enable_gpio; + int idle_gpio; + int standby_gpio; }; static int pwm_regulator_set_voltage_sel( @@ -77,12 +83,49 @@ static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) return preg->curr_selector; } +static int pwm_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct pwm_regulator *preg = rdev_get_drvdata(rdev); + + if (!gpio_is_valid(preg->idle_gpio)) + return -EINVAL; + + switch (mode) { + case REGULATOR_MODE_IDLE: + gpio_set_value(preg->idle_gpio, 0); + break; + case REGULATOR_MODE_NORMAL: + gpio_set_value(preg->idle_gpio, 1); + break; + default: + return -EINVAL; + } + + return 0; +} + +static unsigned int pwm_regulator_get_mode(struct regulator_dev *rdev) +{ + struct pwm_regulator *preg = rdev_get_drvdata(rdev); + + if (!gpio_is_valid(preg->idle_gpio)) + return 0; + + if (gpio_get_value(preg->idle_gpio)) + return REGULATOR_MODE_NORMAL; + else + return REGULATOR_MODE_IDLE; +} + static struct regulator_ops pwm_regulator_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_mode = pwm_regulator_set_mode, + .get_mode = pwm_regulator_get_mode, }; static int pwm_regulator_parse_dt(struct device *dev, @@ -106,6 +149,26 @@ static int pwm_regulator_parse_dt(struct device *dev, return ret; } + preg->enable_gpio = of_get_named_gpio(node, "enable-gpio", 0); + if ((preg->enable_gpio < 0) && (preg->enable_gpio != -ENOENT)) { + dev_err(dev, "Enable gpio not available, %d\n", + preg->enable_gpio); + return preg->enable_gpio; + } + + preg->idle_gpio = of_get_named_gpio(node, "idle-gpio", 0); + if ((preg->idle_gpio < 0) && (preg->idle_gpio != -ENOENT)) { + dev_err(dev, "Idle gpio not available, %d\n", preg->idle_gpio); + return preg->idle_gpio; + } + + preg->standby_gpio = of_get_named_gpio(node, "standby-gpio", 0); + if ((preg->standby_gpio < 0) && (preg->standby_gpio != -ENOENT)) { + dev_err(dev, "Standby gpio not available, %d\n", + preg->standby_gpio); + return preg->standby_gpio; + } + preg->min_uV = preg->rinit_data->constraints.min_uV; preg->max_uV = preg->rinit_data->constraints.max_uV; return 0; @@ -119,21 +182,26 @@ static int pwm_regulator_verify_patform_data(struct pwm_regulator *preg) if (!preg->period) return -EINVAL; - if (preg->period % preg->n_voltages) { + if (preg->n_voltages < 2) { + dev_err(dev, "Number of volatges is not correct\n"); + return -EINVAL; + } + + if (preg->period % (preg->n_voltages - 1)) { dev_err(dev, "PWM Period must multiple of n_voltages\n"); return -EINVAL; } - preg->pulse_time = preg->period / preg->n_voltages; + preg->pulse_time = preg->period / (preg->n_voltages - 1); if (!preg->pulse_time) { dev_err(dev, "Pulse time is invalid\n"); return -EINVAL; } - if ((preg->max_uV - preg->min_uV) % preg->n_voltages) { + if ((preg->max_uV - preg->min_uV) % (preg->n_voltages - 1)) { dev_err(dev, "Min/Max is not proper to get step voltage\n"); return -EINVAL; } - preg->uV_step = (preg->max_uV - preg->min_uV) / preg->n_voltages; + preg->uV_step = (preg->max_uV - preg->min_uV) / (preg->n_voltages - 1); return 0; } static int pwm_regulator_probe(struct platform_device *pdev) @@ -174,6 +242,20 @@ static int pwm_regulator_probe(struct platform_device *pdev) return ret; } + if (gpio_is_valid(preg->idle_gpio)) { + ret = devm_gpio_request_one(&pdev->dev, preg->idle_gpio, + GPIOF_OUT_INIT_HIGH, "pwm-reg-idle-gpio"); + if (ret < 0) { + dev_err(&pdev->dev, "Idle gpio request failed\n"); + return ret; + } + preg->rinit_data->constraints.valid_modes_mask |= + REGULATOR_MODE_IDLE | + REGULATOR_MODE_NORMAL; + preg->rinit_data->constraints.valid_ops_mask |= + REGULATOR_CHANGE_MODE; + } + preg->desc.name = "regulator-pwm"; preg->desc.id = -1; preg->desc.ops = &pwm_regulator_ops; @@ -185,6 +267,13 @@ static int pwm_regulator_probe(struct platform_device *pdev) preg->desc.linear_min_sel = 0; preg->desc.n_voltages = preg->n_voltages; + if (gpio_is_valid(preg->enable_gpio)) { + config.ena_gpio = preg->enable_gpio; + if (preg->rinit_data->constraints.always_on || + preg->rinit_data->constraints.boot_on) + config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH; + } + config.dev = &pdev->dev; config.init_data = preg->rinit_data; config.driver_data = preg; |