summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/regulator/core.c50
1 files changed, 44 insertions, 6 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 71d6adc4eeab..57d434d3145a 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1529,6 +1529,42 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev)
}
}
+/**
+ * Balance enable_count of each GPIO and actual GPIO pin control.
+ * GPIO is enabled in case of initial use. (enable_count is 0)
+ * GPIO is disabled when it is not shared any more. (enable_count <= 1)
+ */
+static int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable)
+{
+ struct regulator_enable_gpio *pin = rdev->ena_pin;
+
+ if (!pin)
+ return -EINVAL;
+
+ if (enable) {
+ /* Enable GPIO at initial use */
+ if (pin->enable_count == 0)
+ gpio_set_value_cansleep(pin->gpio,
+ !pin->ena_gpio_invert);
+
+ pin->enable_count++;
+ } else {
+ if (pin->enable_count > 1) {
+ pin->enable_count--;
+ return 0;
+ }
+
+ /* Disable GPIO if not used */
+ if (pin->enable_count <= 1) {
+ gpio_set_value_cansleep(pin->gpio,
+ pin->ena_gpio_invert);
+ pin->enable_count = 0;
+ }
+ }
+
+ return 0;
+}
+
static int _regulator_do_enable(struct regulator_dev *rdev)
{
int ret, delay;
@@ -1544,9 +1580,10 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
trace_regulator_enable(rdev_get_name(rdev));
- if (rdev->ena_gpio) {
- gpio_set_value_cansleep(rdev->ena_gpio,
- !rdev->ena_gpio_invert);
+ if (rdev->ena_pin) {
+ ret = regulator_ena_gpio_ctrl(rdev, true);
+ if (ret < 0)
+ return ret;
rdev->ena_gpio_state = 1;
} else if (rdev->desc->ops->enable) {
ret = rdev->desc->ops->enable(rdev);
@@ -1648,9 +1685,10 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
trace_regulator_disable(rdev_get_name(rdev));
- if (rdev->ena_gpio) {
- gpio_set_value_cansleep(rdev->ena_gpio,
- rdev->ena_gpio_invert);
+ if (rdev->ena_pin) {
+ ret = regulator_ena_gpio_ctrl(rdev, false);
+ if (ret < 0)
+ return ret;
rdev->ena_gpio_state = 0;
} else if (rdev->desc->ops->disable) {