pm: device: do not call device if already on the given state

If the device is already at the given state, do not call the device PM
control function. This makes sure that devices are only called to change
from one state to another.

Even though asynchronous device PM is completely broken, transitional
states are considered too.

Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
Gerard Marull-Paretas 2021-07-02 12:52:18 +02:00 committed by Anas Nashif
commit bc2990f82d
3 changed files with 30 additions and 3 deletions

View file

@ -112,7 +112,9 @@ const char *pm_device_state_str(enum pm_device_state state);
* @param state Device power state to be set.
*
* @retval 0 If successful.
* @retval Errno Negative errno code in case of failure.
* @retval -ENOTSUP If requested state is not supported.
* @retval -EALREADY If device is already at (or transitioning to) the requested
* state.
*/
int pm_device_state_set(const struct device *dev,
enum pm_device_state state);

View file

@ -137,6 +137,32 @@ int pm_device_state_set(const struct device *dev,
return -ENOSYS;
}
switch (state) {
case PM_DEVICE_STATE_SUSPEND:
if ((dev->pm->state == PM_DEVICE_STATE_SUSPEND) ||
(dev->pm->state == PM_DEVICE_STATE_SUSPENDING)) {
return -EALREADY;
}
break;
case PM_DEVICE_STATE_ACTIVE:
if ((dev->pm->state == PM_DEVICE_STATE_ACTIVE) ||
(dev->pm->state == PM_DEVICE_STATE_RESUMING)) {
return -EALREADY;
}
break;
case PM_DEVICE_STATE_FORCE_SUSPEND:
__fallthrough;
case PM_DEVICE_STATE_LOW_POWER:
__fallthrough;
case PM_DEVICE_STATE_OFF:
if (dev->pm->state == state) {
return -EALREADY;
}
break;
default:
return -ENOTSUP;
}
ret = dev->pm_control(dev, state);
if (ret < 0) {
return ret;

View file

@ -27,7 +27,6 @@ static void pm_device_runtime_state_set(struct pm_device *pm)
switch (dev->pm->state) {
case PM_DEVICE_STATE_ACTIVE:
if ((dev->pm->usage == 0) && dev->pm->enable) {
dev->pm->state = PM_DEVICE_STATE_SUSPENDING;
ret = pm_device_state_set(dev, PM_DEVICE_STATE_SUSPEND);
if (ret == 0) {
dev->pm->state = PM_DEVICE_STATE_SUSPEND;
@ -36,7 +35,6 @@ static void pm_device_runtime_state_set(struct pm_device *pm)
break;
case PM_DEVICE_STATE_SUSPEND:
if ((dev->pm->usage > 0) || !dev->pm->enable) {
dev->pm->state = PM_DEVICE_STATE_RESUMING;
ret = pm_device_state_set(dev, PM_DEVICE_STATE_ACTIVE);
if (ret == 0) {
dev->pm->state = PM_DEVICE_STATE_ACTIVE;
@ -77,6 +75,7 @@ static int pm_device_request(const struct device *dev,
int ret = 0;
SYS_PORT_TRACING_FUNC_ENTER(pm, device_request, dev, target_state);
__ASSERT((target_state == PM_DEVICE_STATE_ACTIVE) ||
(target_state == PM_DEVICE_STATE_SUSPEND),
"Invalid device PM state requested");