Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 871f5650 authored by Guodong Xu's avatar Guodong Xu Committed by Mark Brown
Browse files

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: default avatarGuodong Xu <guodong.xu@linaro.org>
Signed-off-by: default avatarMark Brown <broonie@linaro.org>
parent 79fd1141
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -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;
+6 −0
Original line number Diff line number Diff line
@@ -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 *