regulator: Allow regulators to verify enabled during enable()

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>
This commit is contained in:
Sumit Semwal 2020-06-22 18:11:07 +05:30 committed by Mark Brown
parent 308e65ad06
commit f7d7ad42a9
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 67 additions and 1 deletions

View File

@ -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;
@ -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));

View File

@ -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 {
@ -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);
};