summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuodong Xu <guodong.xu@linaro.org>2014-08-13 19:33:40 +0800
committerMark Brown <broonie@linaro.org>2014-08-16 16:55:42 -0500
commit871f565055ed232e5751da18a331b73e8254adaf (patch)
tree8aa03c6a83d1c5a675c64935b213c1c18035e49c
parent79fd114161a764dfa456191af89358b3f5201c87 (diff)
downloadblackbird-op-linux-871f565055ed232e5751da18a331b73e8254adaf.tar.gz
blackbird-op-linux-871f565055ed232e5751da18a331b73e8254adaf.zip
regulator: core: add guard delay between calling regulator_disable and _enable
Some regulator require a minimum delay between its disable and next enable. This is to avoid damages when out-of-range frequent disable/enable of a single regulator can bring to the regulator chip. Add @off_on_delay to struct regulator_desc. Device drivers' can use this field to set this guard time. Add @last_off_jiffy to struct regulator_dev. When @off_on_delay is set by driver, regulator core can store its last off (disable) time into this field. Signed-off-by: Guodong Xu <guodong.xu@linaro.org> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--drivers/regulator/core.c31
-rw-r--r--include/linux/regulator/driver.h6
2 files changed, 37 insertions, 0 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index dc0e9813b62d..1e976b6320a2 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1813,6 +1813,31 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
trace_regulator_enable(rdev_get_name(rdev));
+ if (rdev->desc->off_on_delay) {
+ /* if needed, keep a distance of off_on_delay from last time
+ * this regulator was disabled.
+ */
+ unsigned long start_jiffy = jiffies;
+ unsigned long intended, max_delay, remaining;
+
+ max_delay = usecs_to_jiffies(rdev->desc->off_on_delay);
+ intended = rdev->last_off_jiffy + max_delay;
+
+ if (time_before(start_jiffy, intended)) {
+ /* calc remaining jiffies to deal with one-time
+ * timer wrapping.
+ * in case of multiple timer wrapping, either it can be
+ * detected by out-of-range remaining, or it cannot be
+ * detected and we gets a panelty of
+ * _regulator_enable_delay().
+ */
+ remaining = intended - start_jiffy;
+ if (remaining <= max_delay)
+ _regulator_enable_delay(
+ jiffies_to_usecs(remaining));
+ }
+ }
+
if (rdev->ena_pin) {
ret = regulator_ena_gpio_ctrl(rdev, true);
if (ret < 0)
@@ -1925,6 +1950,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
return ret;
}
+ /* cares about last_off_jiffy only if off_on_delay is required by
+ * device.
+ */
+ if (rdev->desc->off_on_delay)
+ rdev->last_off_jiffy = jiffies;
+
trace_regulator_disable_complete(rdev_get_name(rdev));
return 0;
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 4b628139a9cb..efe058f8f746 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -238,6 +238,7 @@ enum regulator_type {
* @bypass_val_off: Disabling value for control when using regmap set_bypass
*
* @enable_time: Time taken for initial enable of regulator (in uS).
+ * @off_on_delay: guard time (in uS), before re-enabling a regulator
*/
struct regulator_desc {
const char *name;
@@ -276,6 +277,8 @@ struct regulator_desc {
unsigned int bypass_val_off;
unsigned int enable_time;
+
+ unsigned int off_on_delay;
};
/**
@@ -348,6 +351,9 @@ struct regulator_dev {
struct regulator_enable_gpio *ena_pin;
unsigned int ena_gpio_state:1;
+
+ /* time when this regulator was disabled last time */
+ unsigned long last_off_jiffy;
};
struct regulator_dev *
OpenPOWER on IntegriCloud