1 /*
2 * Copyright (c) 2024 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/pm/device.h>
9 #include <zephyr/pm/device_runtime.h>
10
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_DECLARE(pm_device, CONFIG_PM_DEVICE_LOG_LEVEL);
13
14 #define DT_PM_DEVICE_ENABLED(node_id) \
15 COND_CODE_1(DT_PROP(node_id, zephyr_pm_device_disabled), \
16 (), (1 +))
17
18 #define DT_PM_DEVICE_NEEDED \
19 (DT_FOREACH_STATUS_OKAY(zephyr_power_state, DT_PM_DEVICE_ENABLED) 0)
20
21 #if DT_PM_DEVICE_NEEDED
22 TYPE_SECTION_START_EXTERN(const struct device *, pm_device_slots);
23
24 /* Number of devices successfully suspended. */
25 static size_t num_susp;
26
pm_suspend_devices(void)27 bool pm_suspend_devices(void)
28 {
29 const struct device *devs;
30 size_t devc;
31
32 devc = z_device_get_all_static(&devs);
33
34 num_susp = 0;
35
36 for (const struct device *dev = devs + devc - 1; dev >= devs; dev--) {
37 int ret;
38
39 /*
40 * Ignore uninitialized devices, busy devices, wake up sources, and
41 * devices with runtime PM enabled.
42 */
43 if (!device_is_ready(dev) || pm_device_is_busy(dev) ||
44 pm_device_wakeup_is_enabled(dev) ||
45 pm_device_runtime_is_enabled(dev)) {
46 continue;
47 }
48
49 ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
50 /* ignore devices not supporting or already at the given state */
51 if ((ret == -ENOSYS) || (ret == -ENOTSUP) || (ret == -EALREADY)) {
52 continue;
53 } else if (ret < 0) {
54 LOG_ERR("Device %s did not enter %s state (%d)",
55 dev->name,
56 pm_device_state_str(PM_DEVICE_STATE_SUSPENDED),
57 ret);
58 return false;
59 }
60
61 TYPE_SECTION_START(pm_device_slots)[num_susp] = dev;
62 num_susp++;
63 }
64
65 return true;
66 }
67
pm_resume_devices(void)68 void pm_resume_devices(void)
69 {
70 for (int i = (num_susp - 1); i >= 0; i--) {
71 pm_device_action_run(TYPE_SECTION_START(pm_device_slots)[i],
72 PM_DEVICE_ACTION_RESUME);
73 }
74
75 num_susp = 0;
76 }
77
78 #else /* !DT_PM_DEVICE_NEEDED */
79
pm_resume_devices(void)80 void pm_resume_devices(void)
81 {
82 }
83
pm_suspend_devices(void)84 bool pm_suspend_devices(void)
85 {
86 return true;
87 }
88
89 #endif
90