1 /*
2 * Copyright 2024 Google LLC
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdio.h>
8 #include <zephyr/shell/shell.h>
9 #include <zephyr/pm/device.h>
10 #include <zephyr/pm/device_runtime.h>
11
pm_device_filter(const struct device * dev)12 static bool pm_device_filter(const struct device *dev)
13 {
14 return dev->pm != NULL;
15 }
16
device_name_get(size_t idx,struct shell_static_entry * entry)17 static void device_name_get(size_t idx, struct shell_static_entry *entry)
18 {
19 const struct device *dev = shell_device_filter(idx, pm_device_filter);
20
21 entry->syntax = (dev != NULL) ? dev->name : NULL;
22 entry->handler = NULL;
23 entry->help = NULL;
24 entry->subcmd = NULL;
25 }
26
27 SHELL_DYNAMIC_CMD_CREATE(dsub_device_name, device_name_get);
28
pm_cmd_suspend(const struct shell * sh,size_t argc,char * argv[])29 static int pm_cmd_suspend(const struct shell *sh, size_t argc, char *argv[])
30 {
31 const struct device *dev;
32 int ret;
33
34 dev = shell_device_get_binding(argv[1]);
35 if (dev == NULL) {
36 shell_error(sh, "Invalid device: %s", argv[1]);
37 return -ENODEV;
38 }
39
40 if (pm_device_runtime_is_enabled(dev)) {
41 shell_error(sh, "Device %s uses runtime PM, use the runtime functions instead",
42 dev->name);
43 return -EINVAL;
44 }
45
46 ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
47 if (ret < 0) {
48 shell_error(sh, "Device %s error: %d", "suspend", ret);
49 return ret;
50 }
51
52 return 0;
53 }
54
pm_cmd_resume(const struct shell * sh,size_t argc,char * argv[])55 static int pm_cmd_resume(const struct shell *sh, size_t argc, char *argv[])
56 {
57 const struct device *dev;
58 int ret;
59
60 dev = shell_device_get_binding(argv[1]);
61 if (dev == NULL) {
62 shell_error(sh, "Invalid device: %s", argv[1]);
63 return -ENODEV;
64 }
65
66 if (pm_device_runtime_is_enabled(dev)) {
67 shell_error(sh, "Device %s uses runtime PM, use the runtime functions instead",
68 dev->name);
69 return -EINVAL;
70 }
71
72 ret = pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME);
73 if (ret < 0) {
74 shell_error(sh, "Device %s error: %d", "resume", ret);
75 return ret;
76 }
77
78 return 0;
79 }
80
81 #if defined(CONFIG_PM_DEVICE_RUNTIME)
pm_cmd_runtime_get(const struct shell * sh,size_t argc,char * argv[])82 static int pm_cmd_runtime_get(const struct shell *sh, size_t argc, char *argv[])
83 {
84 const struct device *dev;
85 int ret;
86
87 dev = shell_device_get_binding(argv[1]);
88 if (dev == NULL) {
89 shell_error(sh, "Invalid device: %s", argv[1]);
90 return -ENODEV;
91 }
92
93 if (!pm_device_runtime_is_enabled(dev)) {
94 shell_error(sh, "Device %s is not using runtime PM", dev->name);
95 return -EINVAL;
96 }
97
98 ret = pm_device_runtime_get(dev);
99 if (ret < 0) {
100 shell_error(sh, "Device %s error: %d", "runtime get", ret);
101 return ret;
102 }
103
104 return 0;
105 }
106
pm_cmd_runtime_put(const struct shell * sh,size_t argc,char * argv[])107 static int pm_cmd_runtime_put(const struct shell *sh, size_t argc, char *argv[])
108 {
109 const struct device *dev;
110 int ret;
111
112 dev = shell_device_get_binding(argv[1]);
113 if (dev == NULL) {
114 shell_error(sh, "Invalid device: %s", argv[1]);
115 return -ENODEV;
116 }
117
118 if (!pm_device_runtime_is_enabled(dev)) {
119 shell_error(sh, "Device %s is not using runtime PM", dev->name);
120 return -EINVAL;
121 }
122
123 ret = pm_device_runtime_put(dev);
124 if (ret < 0) {
125 shell_error(sh, "Device %s error: %d", "runtime put", ret);
126 return ret;
127 }
128
129 return 0;
130 }
131
pm_cmd_runtime_put_async(const struct shell * sh,size_t argc,char * argv[])132 static int pm_cmd_runtime_put_async(const struct shell *sh, size_t argc, char *argv[])
133 {
134 const struct device *dev;
135 int ret;
136
137 dev = shell_device_get_binding(argv[1]);
138 if (dev == NULL) {
139 shell_error(sh, "Invalid device: %s", argv[1]);
140 return -ENODEV;
141 }
142
143 if (!pm_device_runtime_is_enabled(dev)) {
144 shell_error(sh, "Device %s is not using runtime PM", dev->name);
145 return -EINVAL;
146 }
147
148 ret = pm_device_runtime_put_async(dev, K_NO_WAIT);
149 if (ret < 0) {
150 shell_error(sh, "Device %s error: %d", "runtime put async", ret);
151 return ret;
152 }
153
154 return 0;
155 }
156 #endif /* CONFIG_PM_DEVICE_RUNTIME */
157
158 SHELL_STATIC_SUBCMD_SET_CREATE(
159 sub_pm_cmds,
160 SHELL_CMD_ARG(suspend, &dsub_device_name,
161 "Call the PM suspend action on a device",
162 pm_cmd_suspend, 2, 0),
163 SHELL_CMD_ARG(resume, &dsub_device_name,
164 "Call the PM resume action on a device",
165 pm_cmd_resume, 2, 0),
166 #if defined(CONFIG_PM_DEVICE_RUNTIME)
167 SHELL_CMD_ARG(runtime-get, &dsub_device_name,
168 "Call the PM runtime get on a device",
169 pm_cmd_runtime_get, 2, 0),
170 SHELL_CMD_ARG(runtime-put, &dsub_device_name,
171 "Call the PM runtime put on a device",
172 pm_cmd_runtime_put, 2, 0),
173 SHELL_CMD_ARG(runtime-put-async, &dsub_device_name,
174 "Call the PM runtime put async on a device",
175 pm_cmd_runtime_put_async, 2, 0),
176 #endif /* CONFIG_PM_DEVICE_RUNTIME */
177 SHELL_SUBCMD_SET_END);
178
179 SHELL_CMD_REGISTER(pm, &sub_pm_cmds, "PM commands", NULL);
180