summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2014-01-29 19:59:29 +0530
committerLaxman Dewangan <ldewangan@nvidia.com>2014-01-29 22:56:25 -0800
commite1fb320687c20a45179d32691de6229393d20625 (patch)
tree61393be5987a1aa9ddf086d32ea4b931b793d5dc /drivers/regulator
parentfe90cad939cf979fc2516a96e5911bd8ab6fc457 (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/regulator')
-rw-r--r--drivers/regulator/pwm-regulator.c97
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;