regulator: tps65132: support for active discharge on input pin
Daniel Solomon [Sat, 27 Jun 2015 01:35:37 +0000 (18:35 -0700)]
Some configurations use delay mechanisms on the
tps65132 enable pin, to keep the regulator enabled
for some time after the enable signal goes low.
Add support to actively discharge this delay
mechanism.

Bug 1630935
Bug 200118211

Change-Id: If7a8fd39d862f35924d7799740f01ead0f65bb71
Signed-off-by: Daniel Solomon <daniels@nvidia.com>
Reviewed-on: http://git-master/r/763398
(cherry picked from commit cadc2c292de1fa677b3b52cf2ea72bd58661ddd1)
Reviewed-on: http://git-master/r/771172
Reviewed-by: Jon Mayo <jmayo@nvidia.com>

Documentation/devicetree/bindings/regulator/tps65132.txt
drivers/regulator/tps65132-regulator.c

index d0968d6..b57a816 100644 (file)
@@ -15,7 +15,13 @@ Device supports two regulators OUTP and OUTN. A sub node within the
    it is connected to GPIO through host system then provide the
    gpio number as per gpio.txt.
 -ti,disable-active-discharge: Boolean, presence of this property
-   will disable active discharge.
+   will disable active discharge on the regulator output.
+-ti,active-discharge-gpio: Some configurations use delay mechanisms
+  on the enable pin, to keep the regulator enabled for some time after
+  the enable signal goes low. This GPIO is used to actively discharge
+  the delay mechanism. Requires specification of ti,active-discharge-time
+-ti,active-discharge-time: how long the active discharge gpio should be
+  asserted for during active discharge, in microseconds.
 
 Each regulator is defined using the standard binding for regulators.
 
index 72b32a4..82a976f 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/regulator/machine.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 
 #define tps65132_rails(_name)  "tps65132-"#_name
 
 #define TPS65132_REGULATOR_ID_VNEG     1
 #define TPS65132_MAX_REGULATORS                2
 
+#define TPS65132_ACT_DIS_TIME_SLACK            1000
+
 struct tps65132_regulator_pdata {
        int enable_gpio;
        bool disable_active_discharge;
        struct regulator_init_data *ridata;
+       int active_discharge_gpio;
+       unsigned int active_discharge_time;
 };
 
 struct tps65132_regulator {
@@ -89,8 +94,26 @@ static int tps65132_post_enable(struct regulator_dev *rdev)
        return 0;
 }
 
+static int tps65132_post_disable(struct regulator_dev *rdev)
+{
+       struct tps65132_regulator *tps = rdev_get_drvdata(rdev);
+       int id = rdev_get_id(rdev);
+       int act_dis_gpio = tps->reg_pdata[id].active_discharge_gpio;
+       unsigned int act_dis_time_us = tps->reg_pdata[id].active_discharge_time;
+
+       if (gpio_is_valid(act_dis_gpio)) {
+               gpio_set_value(act_dis_gpio, 1);
+               usleep_range(act_dis_time_us,
+                       act_dis_time_us + TPS65132_ACT_DIS_TIME_SLACK);
+               gpio_set_value(act_dis_gpio, 0);
+       }
+
+       return 0;
+}
+
 static struct regulator_ops tps65132_regulator_ops = {
        .post_enable = tps65132_post_enable,
+       .post_disable = tps65132_post_disable,
        .list_voltage = regulator_list_voltage_linear,
        .map_voltage = regulator_map_voltage_linear,
        .get_voltage_sel = regulator_get_voltage_sel_regmap,
@@ -152,7 +175,23 @@ static int tps65132_get_regulator_dt_data(struct device *dev,
 
                rpdata->disable_active_discharge = of_property_read_bool(rnode,
                                                "ti,disable-active-discharge");
+
+               rpdata->active_discharge_gpio = of_get_named_gpio(rnode,
+                                               "ti,active-discharge-gpio", 0);
+               if (rpdata->active_discharge_gpio == -EPROBE_DEFER) {
+                       return -EPROBE_DEFER;
+               } else if (gpio_is_valid(rpdata->active_discharge_gpio)) {
+                       ret = of_property_read_u32(rnode,
+                               "ti,active-discharge-time",
+                               &rpdata->active_discharge_time);
+                       if (ret < 0) {
+                               dev_err(dev, "Discharge time read failed: %d\n",
+                                       ret);
+                               return ret;
+                       }
+               }
        }
+
        return 0;
 }
 
@@ -196,6 +235,9 @@ static int tps65132_probe(struct i2c_client *client,
        if (ret == -EPROBE_DEFER) {
                dev_err(dev, "Probe deffered\n");
                return ret;
+       } else if (ret < 0) {
+               dev_err(dev, "Reading data from DT failed: %d\n", ret);
+               return ret;
        }
 
        tps->rmap = devm_regmap_init_i2c(client, &tps65132_regmap_config);
@@ -227,6 +269,21 @@ static int tps65132_probe(struct i2c_client *client,
                                config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
                }
 
+               if (gpio_is_valid(rpdata->active_discharge_gpio)) {
+                       ret = devm_gpio_request_one(dev,
+                               rpdata->active_discharge_gpio,
+                               GPIOF_OUT_INIT_LOW, rdesc->name);
+                       if (ret < 0) {
+                               dev_err(dev,
+                                       "act dis gpio req failed for %s: %d\n",
+                                       rdesc->name, ret);
+                               return ret;
+                       }
+               } else {
+                       dev_info(dev, "No active discharge gpio for regulator %s\n",
+                               rdesc->name);
+               }
+
                tps->rdev[id] = devm_regulator_register(dev, rdesc, &config);
                if (IS_ERR(tps->rdev[id])) {
                        ret = PTR_ERR(tps->rdev[id]);