Skip to content

Commit

Permalink
regulator: Allow regulators to verify enabled during enable()
Browse files Browse the repository at this point in the history
Some regulators might need to verify that they have indeed been enabled
after the enable() call is made and enable_time delay has passed.

This is implemented by repeatedly checking is_enabled() upto
poll_enabled_time, waiting for the already calculated enable delay in
each iteration.

Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Link: https://lore.kernel.org/r/20200622124110.20971-2-sumit.semwal@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Sumit Semwal authored and Mark Brown committed Jul 15, 2020
1 parent 308e65a commit f7d7ad4
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
63 changes: 62 additions & 1 deletion drivers/regulator/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2347,6 +2347,37 @@ static void _regulator_enable_delay(unsigned int delay)
udelay(us);
}

/**
* _regulator_check_status_enabled
*
* A helper function to check if the regulator status can be interpreted
* as 'regulator is enabled'.
* @rdev: the regulator device to check
*
* Return:
* * 1 - if status shows regulator is in enabled state
* * 0 - if not enabled state
* * Error Value - as received from ops->get_status()
*/
static inline int _regulator_check_status_enabled(struct regulator_dev *rdev)
{
int ret = rdev->desc->ops->get_status(rdev);

if (ret < 0) {
rdev_info(rdev, "get_status returned error: %d\n", ret);
return ret;
}

switch (ret) {
case REGULATOR_STATUS_OFF:
case REGULATOR_STATUS_ERROR:
case REGULATOR_STATUS_UNDEFINED:
return 0;
default:
return 1;
}
}

static int _regulator_do_enable(struct regulator_dev *rdev)
{
int ret, delay;
Expand Down Expand Up @@ -2407,7 +2438,37 @@ static int _regulator_do_enable(struct regulator_dev *rdev)
* together. */
trace_regulator_enable_delay(rdev_get_name(rdev));

_regulator_enable_delay(delay);
/* If poll_enabled_time is set, poll upto the delay calculated
* above, delaying poll_enabled_time uS to check if the regulator
* actually got enabled.
* If the regulator isn't enabled after enable_delay has
* expired, return -ETIMEDOUT.
*/
if (rdev->desc->poll_enabled_time) {
unsigned int time_remaining = delay;

while (time_remaining > 0) {
_regulator_enable_delay(rdev->desc->poll_enabled_time);

if (rdev->desc->ops->get_status) {
ret = _regulator_check_status_enabled(rdev);
if (ret < 0)
return ret;
else if (ret)
break;
} else if (rdev->desc->ops->is_enabled(rdev))
break;

time_remaining -= rdev->desc->poll_enabled_time;
}

if (time_remaining <= 0) {
rdev_err(rdev, "Enabled check timed out\n");
return -ETIMEDOUT;
}
} else {
_regulator_enable_delay(delay);
}

trace_regulator_enable_complete(rdev_get_name(rdev));

Expand Down
5 changes: 5 additions & 0 deletions include/linux/regulator/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ enum regulator_type {
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
*
* @poll_enabled_time: The polling interval (in uS) to use while checking that
* the regulator was actually enabled. Max upto enable_time.
*
* @of_map_mode: Maps a hardware mode defined in a DeviceTree to a standard mode
*/
struct regulator_desc {
Expand Down Expand Up @@ -372,6 +375,8 @@ struct regulator_desc {

unsigned int off_on_delay;

unsigned int poll_enabled_time;

unsigned int (*of_map_mode)(unsigned int mode);
};

Expand Down

0 comments on commit f7d7ad4

Please sign in to comment.