Commit 0955f5be authored by Stephen Boyd's avatar Stephen Boyd Committed by Mark Brown

regulator: Avoid grabbing regulator lock during suspend/resume

I see it takes about 5us per regulator to grab the lock, check that this
regulator isn't going to do anything for suspend, and then release the
lock. When that is combined with PMICs that have dozens of regulators we
get into a state where we spend a few miliseconds doing a bunch of
locking operations synchronously to figure out that there's nothing to
do. Let's reorganize the code here a bit so that we don't grab the lock
until we're actually going to do something so that suspend is a little
faster.
Signed-off-by: default avatarStephen Boyd <swboyd@chromium.org>
Reviewed-by: default avatarDouglas Anderson <dianders@chromium.org>
Cc: Matthias Kaehlcke <mka@chromium.org>
Cc: Douglas Anderson <dianders@chromium.org>
Link: https://lore.kernel.org/r/20200804070837.1084024-1-swboyd@chromium.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent a16138a3
......@@ -565,6 +565,30 @@ regulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state)
}
}
static const struct regulator_state *
regulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t state)
{
const struct regulator_state *rstate;
rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return NULL;
/* If we have no suspend mode configuration don't set anything;
* only warn if the driver implements set_suspend_voltage or
* set_suspend_mode callback.
*/
if (rstate->enabled != ENABLE_IN_SUSPEND &&
rstate->enabled != DISABLE_IN_SUSPEND) {
if (rdev->desc->ops->set_suspend_voltage ||
rdev->desc->ops->set_suspend_mode)
rdev_warn(rdev, "No configuration\n");
return NULL;
}
return rstate;
}
static ssize_t regulator_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -982,27 +1006,10 @@ static int drms_uA_update(struct regulator_dev *rdev)
return err;
}
static int suspend_set_state(struct regulator_dev *rdev,
suspend_state_t state)
static int __suspend_set_state(struct regulator_dev *rdev,
const struct regulator_state *rstate)
{
int ret = 0;
struct regulator_state *rstate;
rstate = regulator_get_suspend_state(rdev, state);
if (rstate == NULL)
return 0;
/* If we have no suspend mode configuration don't set anything;
* only warn if the driver implements set_suspend_voltage or
* set_suspend_mode callback.
*/
if (rstate->enabled != ENABLE_IN_SUSPEND &&
rstate->enabled != DISABLE_IN_SUSPEND) {
if (rdev->desc->ops->set_suspend_voltage ||
rdev->desc->ops->set_suspend_mode)
rdev_warn(rdev, "No configuration\n");
return 0;
}
if (rstate->enabled == ENABLE_IN_SUSPEND &&
rdev->desc->ops->set_suspend_enable)
......@@ -1037,6 +1044,18 @@ static int suspend_set_state(struct regulator_dev *rdev,
return ret;
}
static int suspend_set_initial_state(struct regulator_dev *rdev)
{
const struct regulator_state *rstate;
rstate = regulator_get_suspend_state_check(rdev,
rdev->constraints->initial_state);
if (!rstate)
return 0;
return __suspend_set_state(rdev, rstate);
}
static void print_constraints(struct regulator_dev *rdev)
{
struct regulation_constraints *constraints = rdev->constraints;
......@@ -1319,7 +1338,7 @@ static int set_machine_constraints(struct regulator_dev *rdev,
/* do we need to setup our suspend state */
if (rdev->constraints->initial_state) {
ret = suspend_set_state(rdev, rdev->constraints->initial_state);
ret = suspend_set_initial_state(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to set suspend state\n");
return ret;
......@@ -5362,9 +5381,14 @@ static int regulator_suspend(struct device *dev)
struct regulator_dev *rdev = dev_to_rdev(dev);
suspend_state_t state = pm_suspend_target_state;
int ret;
const struct regulator_state *rstate;
rstate = regulator_get_suspend_state_check(rdev, state);
if (!rstate)
return 0;
regulator_lock(rdev);
ret = suspend_set_state(rdev, state);
ret = __suspend_set_state(rdev, rstate);
regulator_unlock(rdev);
return ret;
......@@ -5381,11 +5405,14 @@ static int regulator_resume(struct device *dev)
if (rstate == NULL)
return 0;
/* Avoid grabbing the lock if we don't need to */
if (!rdev->desc->ops->resume)
return 0;
regulator_lock(rdev);
if (rdev->desc->ops->resume &&
(rstate->enabled == ENABLE_IN_SUSPEND ||
rstate->enabled == DISABLE_IN_SUSPEND))
if (rstate->enabled == ENABLE_IN_SUSPEND ||
rstate->enabled == DISABLE_IN_SUSPEND)
ret = rdev->desc->ops->resume(rdev);
regulator_unlock(rdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment