Skip to content

Commit 0a56928

Browse files
committed
fix(pm): Restore sleep suspension of devices.
* After the move to `sys_poweroff`, restore the behavior of suspending devices before entering sleep state.
1 parent 4254df8 commit 0a56928

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

app/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ set(ZEPHYR_EXTRA_MODULES "${ZMK_EXTRA_MODULES};${CMAKE_CURRENT_SOURCE_DIR}/modul
88
find_package(Zephyr REQUIRED HINTS ../zephyr)
99
project(zmk)
1010

11+
if(CONFIG_ZMK_SLEEP)
12+
zephyr_linker_sources(SECTIONS include/linker/zmk-pm-devices.ld)
13+
endif()
14+
1115
zephyr_linker_sources(SECTIONS include/linker/zmk-behaviors.ld)
1216
zephyr_linker_sources(RODATA include/linker/zmk-events.ld)
1317

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
* Copyright (c) 2023 The ZMK Contributors
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
7+
#include <zephyr/linker/linker-defs.h>
8+
9+
ITERABLE_SECTION_RAM(zmk_pm_device_slots, 4)

app/src/activity.c

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <zephyr/device.h>
88
#include <zephyr/init.h>
99
#include <zephyr/kernel.h>
10+
#include <zephyr/pm/device.h>
11+
#include <zephyr/pm/device_runtime.h>
1012
#include <zephyr/sys/poweroff.h>
1113

1214
#include <zephyr/logging/log.h>
@@ -24,6 +26,63 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
2426
#include <zmk/usb.h>
2527
#endif
2628

29+
// Reimplement some of the device work from Zephyr PM to work with the new `sys_poweroff` API.
30+
// TODO: Tweak this to smarter runtime PM of subsystems on sleep.
31+
32+
#ifdef CONFIG_PM_DEVICE
33+
TYPE_SECTION_START_EXTERN(const struct device *, zmk_pm_device_slots);
34+
35+
#if !defined(CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE)
36+
/* Number of devices successfully suspended. */
37+
static size_t zmk_num_susp;
38+
39+
static int zmk_pm_suspend_devices(void) {
40+
const struct device *devs;
41+
size_t devc;
42+
43+
devc = z_device_get_all_static(&devs);
44+
45+
zmk_num_susp = 0;
46+
47+
for (const struct device *dev = devs + devc - 1; dev >= devs; dev--) {
48+
int ret;
49+
50+
/*
51+
* Ignore uninitialized devices, busy devices, wake up sources, and
52+
* devices with runtime PM enabled.
53+
*/
54+
if (!device_is_ready(dev) || pm_device_is_busy(dev) || pm_device_state_is_locked(dev) ||
55+
pm_device_wakeup_is_enabled(dev) || pm_device_runtime_is_enabled(dev)) {
56+
continue;
57+
}
58+
59+
ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
60+
/* ignore devices not supporting or already at the given state */
61+
if ((ret == -ENOSYS) || (ret == -ENOTSUP) || (ret == -EALREADY)) {
62+
continue;
63+
} else if (ret < 0) {
64+
LOG_ERR("Device %s did not enter %s state (%d)", dev->name,
65+
pm_device_state_str(PM_DEVICE_STATE_SUSPENDED), ret);
66+
return ret;
67+
}
68+
69+
TYPE_SECTION_START(zmk_pm_device_slots)[zmk_num_susp] = dev;
70+
zmk_num_susp++;
71+
}
72+
73+
return 0;
74+
}
75+
76+
static void zmk_pm_resume_devices(void) {
77+
for (int i = (zmk_num_susp - 1); i >= 0; i--) {
78+
pm_device_action_run(TYPE_SECTION_START(zmk_pm_device_slots)[i], PM_DEVICE_ACTION_RESUME);
79+
}
80+
81+
zmk_num_susp = 0;
82+
}
83+
#endif /* !CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE */
84+
#endif /* CONFIG_PM_DEVICE */
85+
2786
bool is_usb_power_present(void) {
2887
#if IS_ENABLED(CONFIG_USB_DEVICE_STACK)
2988
return zmk_usb_is_powered();
@@ -70,12 +129,19 @@ void activity_work_handler(struct k_work *work) {
70129
if (inactive_time > MAX_SLEEP_MS && !is_usb_power_present()) {
71130
// Put devices in suspend power mode before sleeping
72131
set_state(ZMK_ACTIVITY_SLEEP);
132+
133+
if (zmk_pm_suspend_devices() < 0) {
134+
LOG_ERR("Failed to suspend all the devices");
135+
zmk_pm_resume_devices();
136+
return;
137+
}
138+
73139
sys_poweroff();
74140
} else
75141
#endif /* IS_ENABLED(CONFIG_ZMK_SLEEP) */
76142
if (inactive_time > MAX_IDLE_MS) {
77-
set_state(ZMK_ACTIVITY_IDLE);
78-
}
143+
set_state(ZMK_ACTIVITY_IDLE);
144+
}
79145
}
80146

81147
K_WORK_DEFINE(activity_work, activity_work_handler);

0 commit comments

Comments
 (0)