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>
This commit is contained in:
parent
79fd114161
commit
871f565055
2 changed files with 37 additions and 0 deletions
|
@ -1813,6 +1813,31 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
|
||||||
|
|
||||||
trace_regulator_enable(rdev_get_name(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) {
|
if (rdev->ena_pin) {
|
||||||
ret = regulator_ena_gpio_ctrl(rdev, true);
|
ret = regulator_ena_gpio_ctrl(rdev, true);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -1925,6 +1950,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev)
|
||||||
return ret;
|
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));
|
trace_regulator_disable_complete(rdev_get_name(rdev));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -238,6 +238,7 @@ enum regulator_type {
|
||||||
* @bypass_val_off: Disabling value for control when using regmap set_bypass
|
* @bypass_val_off: Disabling value for control when using regmap set_bypass
|
||||||
*
|
*
|
||||||
* @enable_time: Time taken for initial enable of regulator (in uS).
|
* @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 {
|
struct regulator_desc {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -276,6 +277,8 @@ struct regulator_desc {
|
||||||
unsigned int bypass_val_off;
|
unsigned int bypass_val_off;
|
||||||
|
|
||||||
unsigned int enable_time;
|
unsigned int enable_time;
|
||||||
|
|
||||||
|
unsigned int off_on_delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -348,6 +351,9 @@ struct regulator_dev {
|
||||||
|
|
||||||
struct regulator_enable_gpio *ena_pin;
|
struct regulator_enable_gpio *ena_pin;
|
||||||
unsigned int ena_gpio_state:1;
|
unsigned int ena_gpio_state:1;
|
||||||
|
|
||||||
|
/* time when this regulator was disabled last time */
|
||||||
|
unsigned long last_off_jiffy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct regulator_dev *
|
struct regulator_dev *
|
||||||
|
|
Loading…
Add table
Reference in a new issue