1 /*
2 * Copyright (c) 2015 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #ifndef ZEPHYR_INCLUDE_PM_DEVICE_H_
8 #define ZEPHYR_INCLUDE_PM_DEVICE_H_
9
10 #include <kernel.h>
11 #include <sys/atomic.h>
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 /**
18 * @brief Device Power Management API
19 *
20 * @defgroup device_power_management_api Device Power Management API
21 * @ingroup power_management_api
22 * @{
23 */
24
25 struct device;
26
27 /** @brief Device power states. */
28 enum pm_device_state {
29 /** Device is in active or regular state. */
30 PM_DEVICE_STATE_ACTIVE,
31 /**
32 * Device is in low power state.
33 *
34 * @note
35 * Device context is preserved.
36 */
37 PM_DEVICE_STATE_LOW_POWER,
38 /**
39 * Device is suspended.
40 *
41 * @note
42 * Device context may be lost.
43 */
44 PM_DEVICE_STATE_SUSPENDED,
45 /**
46 * Device is turned off (power removed).
47 *
48 * @note
49 * Device context is lost.
50 */
51 PM_DEVICE_STATE_OFF
52 };
53
54 /** @brief Device PM flags. */
55 enum pm_device_flag {
56 /** Indicate if the device is busy or not. */
57 PM_DEVICE_FLAG_BUSY,
58 /**
59 * Indicates whether or not the device is capable of waking the system
60 * up.
61 */
62 PM_DEVICE_FLAGS_WS_CAPABLE,
63 /** Indicates if the device is being used as wakeup source. */
64 PM_DEVICE_FLAGS_WS_ENABLED,
65 /** Indicates that the device is changing its state */
66 PM_DEVICE_FLAG_TRANSITIONING,
67 /** Number of flags (internal use only). */
68 PM_DEVICE_FLAG_COUNT
69 };
70
71 /** @brief Device PM actions. */
72 enum pm_device_action {
73 /** Suspend. */
74 PM_DEVICE_ACTION_SUSPEND,
75 /** Resume. */
76 PM_DEVICE_ACTION_RESUME,
77 /** Turn off. */
78 PM_DEVICE_ACTION_TURN_OFF,
79 /** Force suspend. */
80 PM_DEVICE_ACTION_FORCE_SUSPEND,
81 /** Low power. */
82 PM_DEVICE_ACTION_LOW_POWER,
83 };
84
85 /**
86 * @brief Device PM info
87 */
88 struct pm_device {
89 #ifdef CONFIG_PM_DEVICE_RUNTIME
90 /** Pointer to the device */
91 const struct device *dev;
92 /** Lock to synchronize the get/put operations */
93 struct k_mutex lock;
94 /* Following are packed fields protected by #lock. */
95 /** Device pm enable flag */
96 bool enable : 1;
97 /** Device usage count */
98 uint32_t usage;
99 /** Work object for asynchronous calls */
100 struct k_work_delayable work;
101 /** Event conditional var to listen to the sync request events */
102 struct k_condvar condvar;
103 #endif /* CONFIG_PM_DEVICE_RUNTIME */
104 /* Device PM status flags. */
105 atomic_t flags;
106 /** Device power state */
107 enum pm_device_state state;
108 };
109
110 #ifdef CONFIG_PM_DEVICE_RUNTIME
111 #define INIT_PM_DEVICE_RUNTIME(obj) \
112 .usage = 0U, \
113 .lock = Z_MUTEX_INITIALIZER(obj.lock), \
114 .condvar = Z_CONDVAR_INITIALIZER(obj.condvar),
115 #else
116 #define INIT_PM_DEVICE_RUNTIME(obj)
117 #endif /* CONFIG_PM_DEVICE_RUNTIME */
118
119 /**
120 * @brief Utility macro to initialize #pm_device.
121 *
122 * @note DT_PROP_OR is used to retrieve the wakeup_source property because
123 * it may not be defined on all devices.
124 *
125 * @param obj Name of the #pm_device structure being initialized.
126 * @param node_id Devicetree node for the initialized device (can be invalid).
127 */
128 #define Z_PM_DEVICE_INIT(obj, node_id) \
129 { \
130 INIT_PM_DEVICE_RUNTIME(obj) \
131 .state = PM_DEVICE_STATE_ACTIVE, \
132 .flags = ATOMIC_INIT(COND_CODE_1( \
133 DT_NODE_EXISTS(node_id), \
134 (DT_PROP_OR(node_id, wakeup_source, 0)),\
135 (0)) << PM_DEVICE_FLAGS_WS_CAPABLE), \
136 }
137
138 /**
139 * @brief Device power management control function callback.
140 *
141 * @param dev Device instance.
142 * @param action Requested action.
143 *
144 * @retval 0 If successful.
145 * @retval -ENOTSUP If the requested action is not supported.
146 * @retval Errno Other negative errno on failure.
147 */
148 typedef int (*pm_device_control_callback_t)(const struct device *dev,
149 enum pm_device_action action);
150
151 /**
152 * @brief Get name of device PM state
153 *
154 * @param state State id which name should be returned
155 */
156 const char *pm_device_state_str(enum pm_device_state state);
157
158 /**
159 * @brief Set the power state of a device.
160 *
161 * This function calls the device PM control callback so that the device does
162 * the necessary operations to put the device into the given state.
163 *
164 * @note Some devices may not support all device power states.
165 *
166 * @param dev Device instance.
167 * @param state Device power state to be set.
168 *
169 * @retval 0 If successful.
170 * @retval -ENOTSUP If requested state is not supported.
171 * @retval -EALREADY If device is already at the requested state.
172 * @retval -EBUSY If device is changing its state.
173
174 * @retval Errno Other negative errno on failure.
175 */
176 int pm_device_state_set(const struct device *dev,
177 enum pm_device_state state);
178
179 /**
180 * @brief Obtain the power state of a device.
181 *
182 * @param dev Device instance.
183 * @param state Pointer where device power state will be stored.
184 *
185 * @retval 0 If successful.
186 * @retval -ENOSYS If device does not implement power management.
187 */
188 int pm_device_state_get(const struct device *dev,
189 enum pm_device_state *state);
190
191 #ifdef CONFIG_PM_DEVICE
192 /**
193 * @brief Indicate that the device is in the middle of a transaction
194 *
195 * Called by a device driver to indicate that it is in the middle of a
196 * transaction.
197 *
198 * @param dev Pointer to device structure of the driver instance.
199 */
200 void pm_device_busy_set(const struct device *dev);
201
202 /**
203 * @brief Indicate that the device has completed its transaction
204 *
205 * Called by a device driver to indicate the end of a transaction.
206 *
207 * @param dev Pointer to device structure of the driver instance.
208 */
209 void pm_device_busy_clear(const struct device *dev);
210
211 /**
212 * @brief Check if any device is in the middle of a transaction
213 *
214 * Called by an application to see if any device is in the middle
215 * of a critical transaction that cannot be interrupted.
216 *
217 * @retval false if no device is busy
218 * @retval true if any device is busy
219 */
220 bool pm_device_is_any_busy(void);
221
222 /**
223 * @brief Check if a specific device is in the middle of a transaction
224 *
225 * Called by an application to see if a particular device is in the
226 * middle of a critical transaction that cannot be interrupted.
227 *
228 * @param dev Pointer to device structure of the specific device driver
229 * the caller is interested in.
230 * @retval false if the device is not busy
231 * @retval true if the device is busy
232 */
233 bool pm_device_is_busy(const struct device *dev);
234 #else
pm_device_busy_set(const struct device * dev)235 static inline void pm_device_busy_set(const struct device *dev) {}
pm_device_busy_clear(const struct device * dev)236 static inline void pm_device_busy_clear(const struct device *dev) {}
pm_device_is_any_busy(void)237 static inline bool pm_device_is_any_busy(void) { return false; }
pm_device_is_busy(const struct device * dev)238 static inline bool pm_device_is_busy(const struct device *dev) { return false; }
239 #endif
240
device_busy_set(const struct device * dev)241 __deprecated static inline void device_busy_set(const struct device *dev)
242 {
243 pm_device_busy_set(dev);
244 }
245
device_busy_clear(const struct device * dev)246 __deprecated static inline void device_busy_clear(const struct device *dev)
247 {
248 pm_device_busy_clear(dev);
249 }
250
device_any_busy_check(void)251 __deprecated static inline int device_any_busy_check(void)
252 {
253 return pm_device_is_any_busy() ? -EBUSY : 0;
254 }
255
device_busy_check(const struct device * dev)256 __deprecated static inline int device_busy_check(const struct device *dev)
257 {
258 return pm_device_is_busy(dev) ? -EBUSY : 0;
259 }
260
261 /** Alias for legacy use of device_pm_control_nop */
262 #define device_pm_control_nop __DEPRECATED_MACRO NULL
263
264 /**
265 * @brief Enable a power management wakeup source
266 *
267 * Enable a wakeup source. This will keep the current device active when the
268 * system is suspended, allowing it to be used to wake up the system.
269 *
270 * @param dev device object to enable.
271 * @param enable @c true to enable or @c false to disable
272 *
273 * @retval true if the wakeup source was successfully enabled.
274 * @retval false if the wakeup source was not successfully enabled.
275 */
276 bool pm_device_wakeup_enable(struct device *dev, bool enable);
277
278 /**
279 * @brief Check if a power management wakeup source is enabled
280 *
281 * Checks if a wake up source is enabled.
282 *
283 * @param dev device object to check.
284 *
285 * @retval true if the wakeup source is enabled.
286 * @retval false if the wakeup source is not enabled.
287 */
288 bool pm_device_wakeup_is_enabled(const struct device *dev);
289
290 /**
291 * @brief Check if a device is wake up capable
292 *
293 * @param dev device object to check.
294 *
295 * @retval true if the device is wake up capable.
296 * @retval false if the device is not wake up capable.
297 */
298 bool pm_device_wakeup_is_capable(const struct device *dev);
299
300 /** @} */
301
302 #ifdef __cplusplus
303 }
304 #endif
305
306 #endif
307