blob: 6507267d6a6d7f6b4ed8fc13cef53c41712f25c1 [file] [log] [blame]
/*
* Copyright (c) 2024 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(pm_device, CONFIG_PM_DEVICE_LOG_LEVEL);
#define DT_PM_DEVICE_ENABLED(node_id) \
COND_CODE_1(DT_PROP(node_id, zephyr_pm_device_disabled), \
(), (1 +))
#define DT_PM_DEVICE_NEEDED \
(DT_FOREACH_STATUS_OKAY(zephyr_power_state, DT_PM_DEVICE_ENABLED) 0)
#if DT_PM_DEVICE_NEEDED
TYPE_SECTION_START_EXTERN(const struct device *, pm_device_slots);
/* Number of devices successfully suspended. */
static size_t num_susp;
bool pm_suspend_devices(void)
{
const struct device *devs;
size_t devc;
devc = z_device_get_all_static(&devs);
num_susp = 0;
for (const struct device *dev = devs + devc - 1; dev >= devs; dev--) {
int ret;
/*
* Ignore uninitialized devices, busy devices, wake up sources, and
* devices with runtime PM enabled.
*/
if (!device_is_ready(dev) || pm_device_is_busy(dev) ||
pm_device_wakeup_is_enabled(dev) ||
pm_device_runtime_is_enabled(dev)) {
continue;
}
ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
/* ignore devices not supporting or already at the given state */
if ((ret == -ENOSYS) || (ret == -ENOTSUP) || (ret == -EALREADY)) {
continue;
} else if (ret < 0) {
LOG_ERR("Device %s did not enter %s state (%d)",
dev->name,
pm_device_state_str(PM_DEVICE_STATE_SUSPENDED),
ret);
return false;
}
TYPE_SECTION_START(pm_device_slots)[num_susp] = dev;
num_susp++;
}
return true;
}
void pm_resume_devices(void)
{
for (int i = (num_susp - 1); i >= 0; i--) {
pm_device_action_run(TYPE_SECTION_START(pm_device_slots)[i],
PM_DEVICE_ACTION_RESUME);
}
num_susp = 0;
}
#else /* !DT_PM_DEVICE_NEEDED */
void pm_resume_devices(void)
{
}
bool pm_suspend_devices(void)
{
return true;
}
#endif