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 <zephyr/device.h>
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/atomic.h>
13 #include <zephyr/sys/iterable_sections.h>
14
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18
19 /**
20 * @brief Device Power Management API
21 * @defgroup subsys_pm_device Device
22 * @ingroup subsys_pm
23 * @{
24 */
25
26 /** @cond INTERNAL_HIDDEN */
27
28 struct device;
29
30 /** @brief Device PM flags. */
31 enum pm_device_flag {
32 /** Indicate if the device is busy or not. */
33 PM_DEVICE_FLAG_BUSY,
34 /** Indicate if the device failed to power up. */
35 PM_DEVICE_FLAG_TURN_ON_FAILED,
36 /** Indicate if the device has claimed a power domain */
37 PM_DEVICE_FLAG_PD_CLAIMED,
38 /**
39 * Indicates whether or not the device is capable of waking the system
40 * up.
41 */
42 PM_DEVICE_FLAG_WS_CAPABLE,
43 /** Indicates if the device is being used as wakeup source. */
44 PM_DEVICE_FLAG_WS_ENABLED,
45 /** Indicates if device runtime is enabled */
46 PM_DEVICE_FLAG_RUNTIME_ENABLED,
47 /** Indicates if the device pm is locked. */
48 PM_DEVICE_FLAG_STATE_LOCKED,
49 /** Indicates if the device is used as a power domain */
50 PM_DEVICE_FLAG_PD,
51 /** Indicates if device runtime PM should be automatically enabled */
52 PM_DEVICE_FLAG_RUNTIME_AUTO,
53 };
54
55 /** @endcond */
56
57 /** @brief Device power states. */
58 enum pm_device_state {
59 /** Device is in active or regular state. */
60 PM_DEVICE_STATE_ACTIVE,
61 /**
62 * Device is suspended.
63 *
64 * @note
65 * Device context may be lost.
66 */
67 PM_DEVICE_STATE_SUSPENDED,
68 /** Device is being suspended. */
69 PM_DEVICE_STATE_SUSPENDING,
70 /**
71 * Device is turned off (power removed).
72 *
73 * @note
74 * Device context is lost.
75 */
76 PM_DEVICE_STATE_OFF
77 };
78
79 /** @brief Device PM actions. */
80 enum pm_device_action {
81 /** Suspend. */
82 PM_DEVICE_ACTION_SUSPEND,
83 /** Resume. */
84 PM_DEVICE_ACTION_RESUME,
85 /**
86 * Turn off.
87 * @note
88 * Action triggered only by a power domain.
89 */
90 PM_DEVICE_ACTION_TURN_OFF,
91 /**
92 * Turn on.
93 * @note
94 * Action triggered only by a power domain.
95 */
96 PM_DEVICE_ACTION_TURN_ON,
97 };
98
99 /**
100 * @brief Device PM action callback.
101 *
102 * @param dev Device instance.
103 * @param action Requested action.
104 *
105 * @retval 0 If successful.
106 * @retval -ENOTSUP If the requested action is not supported.
107 * @retval Errno Other negative errno on failure.
108 */
109 typedef int (*pm_device_action_cb_t)(const struct device *dev,
110 enum pm_device_action action);
111
112 /**
113 * @brief Device PM action failed callback
114 *
115 * @param dev Device that failed the action.
116 * @param err Return code of action failure.
117 *
118 * @return True to continue iteration, false to halt iteration.
119 */
120 typedef bool (*pm_device_action_failed_cb_t)(const struct device *dev,
121 int err);
122
123 /**
124 * @brief Device PM info
125 */
126 struct pm_device {
127 #if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__)
128 /** Pointer to the device */
129 const struct device *dev;
130 /** Lock to synchronize the get/put operations */
131 struct k_sem lock;
132 /** Event var to listen to the sync request events */
133 struct k_event event;
134 /** Device usage count */
135 uint32_t usage;
136 /** Work object for asynchronous calls */
137 struct k_work_delayable work;
138 #endif /* CONFIG_PM_DEVICE_RUNTIME */
139 #ifdef CONFIG_PM_DEVICE_POWER_DOMAIN
140 /** Power Domain it belongs */
141 const struct device *domain;
142 #endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */
143 /* Device PM status flags. */
144 atomic_t flags;
145 /** Device power state */
146 enum pm_device_state state;
147 /** Device PM action callback */
148 pm_device_action_cb_t action_cb;
149 };
150
151 /** @cond INTERNAL_HIDDEN */
152
153 #ifdef CONFIG_PM_DEVICE_RUNTIME
154 #define Z_PM_DEVICE_RUNTIME_INIT(obj) \
155 .lock = Z_SEM_INITIALIZER(obj.lock, 1, 1), \
156 .event = Z_EVENT_INITIALIZER(obj.event),
157 #else
158 #define Z_PM_DEVICE_RUNTIME_INIT(obj)
159 #endif /* CONFIG_PM_DEVICE_RUNTIME */
160
161 #ifdef CONFIG_PM_DEVICE_POWER_DOMAIN
162 #define Z_PM_DEVICE_POWER_DOMAIN_INIT(_node_id) \
163 .domain = DEVICE_DT_GET_OR_NULL(DT_PHANDLE(_node_id, \
164 power_domain)),
165 #else
166 #define Z_PM_DEVICE_POWER_DOMAIN_INIT(obj)
167 #endif /* CONFIG_PM_DEVICE_POWER_DOMAIN */
168
169 /**
170 * @brief Utility macro to initialize #pm_device flags
171 *
172 * @param node_id Devicetree node for the initialized device (can be invalid).
173 */
174 #define Z_PM_DEVICE_FLAGS(node_id) \
175 (COND_CODE_1( \
176 DT_NODE_EXISTS(node_id), \
177 ((DT_PROP_OR(node_id, wakeup_source, 0) \
178 << PM_DEVICE_FLAG_WS_CAPABLE) | \
179 (DT_PROP_OR(node_id, zephyr_pm_device_runtime_auto, 0) \
180 << PM_DEVICE_FLAG_RUNTIME_AUTO) | \
181 (DT_NODE_HAS_COMPAT(node_id, power_domain) << \
182 PM_DEVICE_FLAG_PD)), \
183 (0)))
184
185 /**
186 * @brief Utility macro to initialize #pm_device.
187 *
188 * @note #DT_PROP_OR is used to retrieve the wakeup_source property because
189 * it may not be defined on all devices.
190 *
191 * @param obj Name of the #pm_device structure being initialized.
192 * @param node_id Devicetree node for the initialized device (can be invalid).
193 * @param pm_action_cb Device PM control callback function.
194 */
195 #define Z_PM_DEVICE_INIT(obj, node_id, pm_action_cb) \
196 { \
197 Z_PM_DEVICE_RUNTIME_INIT(obj) \
198 .action_cb = pm_action_cb, \
199 .state = PM_DEVICE_STATE_ACTIVE, \
200 .flags = ATOMIC_INIT(Z_PM_DEVICE_FLAGS(node_id)), \
201 Z_PM_DEVICE_POWER_DOMAIN_INIT(node_id) \
202 }
203
204 /**
205 * Get the name of device PM resources.
206 *
207 * @param dev_id Device id.
208 */
209 #define Z_PM_DEVICE_NAME(dev_id) _CONCAT(__pm_device_, dev_id)
210
211 /**
212 * @brief Define device PM slot.
213 *
214 * This macro defines a pointer to a device in the pm_device_slots region.
215 * When invoked for each device with PM, it will effectively result in a device
216 * pointer array with the same size of the actual devices with PM enabled. This
217 * is used internally by the PM subsystem to keep track of suspended devices
218 * during system power transitions.
219 *
220 * @param dev_id Device id.
221 */
222 #define Z_PM_DEVICE_DEFINE_SLOT(dev_id) \
223 static const STRUCT_SECTION_ITERABLE_ALTERNATE(pm_device_slots, device, \
224 _CONCAT(__pm_slot_, dev_id))
225
226 #ifdef CONFIG_PM_DEVICE
227 /**
228 * Define device PM resources for the given node identifier.
229 *
230 * @param node_id Node identifier (DT_INVALID_NODE if not a DT device).
231 * @param dev_id Device id.
232 * @param pm_action_cb PM control callback.
233 */
234 #define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb) \
235 Z_PM_DEVICE_DEFINE_SLOT(dev_id); \
236 static struct pm_device Z_PM_DEVICE_NAME(dev_id) = \
237 Z_PM_DEVICE_INIT(Z_PM_DEVICE_NAME(dev_id), node_id, \
238 pm_action_cb)
239
240 /**
241 * Get a reference to the device PM resources.
242 *
243 * @param dev_id Device id.
244 */
245 #define Z_PM_DEVICE_GET(dev_id) (&Z_PM_DEVICE_NAME(dev_id))
246
247 #else
248 #define Z_PM_DEVICE_DEFINE(node_id, dev_id, pm_action_cb)
249 #define Z_PM_DEVICE_GET(dev_id) NULL
250 #endif /* CONFIG_PM_DEVICE */
251
252 /** @endcond */
253
254 /**
255 * Define device PM resources for the given device name.
256 *
257 * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled.
258 *
259 * @param dev_id Device id.
260 * @param pm_action_cb PM control callback.
261 *
262 * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DT_INST_DEFINE
263 */
264 #define PM_DEVICE_DEFINE(dev_id, pm_action_cb) \
265 Z_PM_DEVICE_DEFINE(DT_INVALID_NODE, dev_id, pm_action_cb)
266
267 /**
268 * Define device PM resources for the given node identifier.
269 *
270 * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled.
271 *
272 * @param node_id Node identifier.
273 * @param pm_action_cb PM control callback.
274 *
275 * @see #PM_DEVICE_DT_INST_DEFINE, #PM_DEVICE_DEFINE
276 */
277 #define PM_DEVICE_DT_DEFINE(node_id, pm_action_cb) \
278 Z_PM_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_ID(node_id), \
279 pm_action_cb)
280
281 /**
282 * Define device PM resources for the given instance.
283 *
284 * @note This macro is a no-op if @kconfig{CONFIG_PM_DEVICE} is not enabled.
285 *
286 * @param idx Instance index.
287 * @param pm_action_cb PM control callback.
288 *
289 * @see #PM_DEVICE_DT_DEFINE, #PM_DEVICE_DEFINE
290 */
291 #define PM_DEVICE_DT_INST_DEFINE(idx, pm_action_cb) \
292 Z_PM_DEVICE_DEFINE(DT_DRV_INST(idx), \
293 Z_DEVICE_DT_DEV_ID(DT_DRV_INST(idx)), \
294 pm_action_cb)
295
296 /**
297 * @brief Obtain a reference to the device PM resources for the given device.
298 *
299 * @param dev_id Device id.
300 *
301 * @return Reference to the device PM resources (NULL if device
302 * @kconfig{CONFIG_PM_DEVICE} is disabled).
303 */
304 #define PM_DEVICE_GET(dev_id) \
305 Z_PM_DEVICE_GET(dev_id)
306
307 /**
308 * @brief Obtain a reference to the device PM resources for the given node.
309 *
310 * @param node_id Node identifier.
311 *
312 * @return Reference to the device PM resources (NULL if device
313 * @kconfig{CONFIG_PM_DEVICE} is disabled).
314 */
315 #define PM_DEVICE_DT_GET(node_id) \
316 PM_DEVICE_GET(Z_DEVICE_DT_DEV_ID(node_id))
317
318 /**
319 * @brief Obtain a reference to the device PM resources for the given instance.
320 *
321 * @param idx Instance index.
322 *
323 * @return Reference to the device PM resources (NULL if device
324 * @kconfig{CONFIG_PM_DEVICE} is disabled).
325 */
326 #define PM_DEVICE_DT_INST_GET(idx) \
327 PM_DEVICE_DT_GET(DT_DRV_INST(idx))
328
329 /**
330 * @brief Get name of device PM state
331 *
332 * @param state State id which name should be returned
333 */
334 const char *pm_device_state_str(enum pm_device_state state);
335
336 /**
337 * @brief Run a pm action on a device.
338 *
339 * This function calls the device PM control callback so that the device does
340 * the necessary operations to execute the given action.
341 *
342 * @param dev Device instance.
343 * @param action Device pm action.
344 *
345 * @retval 0 If successful.
346 * @retval -ENOTSUP If requested state is not supported.
347 * @retval -EALREADY If device is already at the requested state.
348 * @retval -EBUSY If device is changing its state.
349 * @retval -ENOSYS If device does not support PM.
350 * @retval -EPERM If device has power state locked.
351 * @retval Errno Other negative errno on failure.
352 */
353 int pm_device_action_run(const struct device *dev,
354 enum pm_device_action action);
355
356 /**
357 * @brief Run a pm action on all children of a device.
358 *
359 * This function calls all child devices PM control callback so that the device
360 * does the necessary operations to execute the given action.
361 *
362 * @param dev Device instance.
363 * @param action Device pm action.
364 * @param failure_cb Function to call if a child fails the action, can be NULL.
365 */
366 void pm_device_children_action_run(const struct device *dev,
367 enum pm_device_action action,
368 pm_device_action_failed_cb_t failure_cb);
369
370 #if defined(CONFIG_PM_DEVICE) || defined(__DOXYGEN__)
371 /**
372 * @brief Obtain the power state of a device.
373 *
374 * @param dev Device instance.
375 * @param state Pointer where device power state will be stored.
376 *
377 * @retval 0 If successful.
378 * @retval -ENOSYS If device does not implement power management.
379 */
380 int pm_device_state_get(const struct device *dev,
381 enum pm_device_state *state);
382
383 /**
384 * @brief Initialize a device state to #PM_DEVICE_STATE_SUSPENDED.
385 *
386 * By default device state is initialized to #PM_DEVICE_STATE_ACTIVE. However
387 * in order to save power some drivers may choose to only initialize the device
388 * to the suspended state, or actively put the device into the suspended state.
389 * This function can therefore be used to notify the PM subsystem that the
390 * device is in #PM_DEVICE_STATE_SUSPENDED instead of the default.
391 *
392 * @param dev Device instance.
393 */
pm_device_init_suspended(const struct device * dev)394 static inline void pm_device_init_suspended(const struct device *dev)
395 {
396 struct pm_device *pm = dev->pm;
397
398 pm->state = PM_DEVICE_STATE_SUSPENDED;
399 }
400
401 /**
402 * @brief Initialize a device state to #PM_DEVICE_STATE_OFF.
403 *
404 * By default device state is initialized to #PM_DEVICE_STATE_ACTIVE. In
405 * general, this makes sense because the device initialization function will
406 * resume and configure a device, leaving it operational. However, when power
407 * domains are enabled, the device may be connected to a switchable power
408 * source, in which case it won't be powered at boot. This function can
409 * therefore be used to notify the PM subsystem that the device is in
410 * #PM_DEVICE_STATE_OFF instead of the default.
411 *
412 * @param dev Device instance.
413 */
pm_device_init_off(const struct device * dev)414 static inline void pm_device_init_off(const struct device *dev)
415 {
416 struct pm_device *pm = dev->pm;
417
418 pm->state = PM_DEVICE_STATE_OFF;
419 }
420
421 /**
422 * @brief Mark a device as busy.
423 *
424 * Devices marked as busy will not be suspended when the system goes into
425 * low-power states. This can be useful if, for example, the device is in the
426 * middle of a transaction.
427 *
428 * @param dev Device instance.
429 *
430 * @see pm_device_busy_clear()
431 */
432 void pm_device_busy_set(const struct device *dev);
433
434 /**
435 * @brief Clear a device busy status.
436 *
437 * @param dev Device instance.
438 *
439 * @see pm_device_busy_set()
440 */
441 void pm_device_busy_clear(const struct device *dev);
442
443 /**
444 * @brief Check if any device is busy.
445 *
446 * @retval false If no device is busy
447 * @retval true If one or more devices are busy
448 */
449 bool pm_device_is_any_busy(void);
450
451 /**
452 * @brief Check if a device is busy.
453 *
454 * @param dev Device instance.
455 *
456 * @retval false If the device is not busy
457 * @retval true If the device is busy
458 */
459 bool pm_device_is_busy(const struct device *dev);
460
461 /**
462 * @brief Enable or disable a device as a wake up source.
463 *
464 * A device marked as a wake up source will not be suspended when the system
465 * goes into low-power modes, thus allowing to use it as a wake up source for
466 * the system.
467 *
468 * @param dev Device instance.
469 * @param enable @c true to enable or @c false to disable
470 *
471 * @retval true If the wakeup source was successfully enabled.
472 * @retval false If the wakeup source was not successfully enabled.
473 */
474 bool pm_device_wakeup_enable(const struct device *dev, bool enable);
475
476 /**
477 * @brief Check if a device is enabled as a wake up source.
478 *
479 * @param dev Device instance.
480 *
481 * @retval true if the wakeup source is enabled.
482 * @retval false if the wakeup source is not enabled.
483 */
484 bool pm_device_wakeup_is_enabled(const struct device *dev);
485
486 /**
487 * @brief Check if a device is wake up capable
488 *
489 * @param dev Device instance.
490 *
491 * @retval true If the device is wake up capable.
492 * @retval false If the device is not wake up capable.
493 */
494 bool pm_device_wakeup_is_capable(const struct device *dev);
495
496 /**
497 * @brief Lock current device state.
498 *
499 * This function locks the current device power state. Once
500 * locked the device power state will not be changed by
501 * system power management or device runtime power
502 * management until unlocked.
503 *
504 * @note The given device should not have device runtime enabled.
505 *
506 * @see pm_device_state_unlock
507 *
508 * @param dev Device instance.
509 */
510 void pm_device_state_lock(const struct device *dev);
511
512 /**
513 * @brief Unlock the current device state.
514 *
515 * Unlocks a previously locked device pm.
516 *
517 * @see pm_device_state_lock
518 *
519 * @param dev Device instance.
520 */
521 void pm_device_state_unlock(const struct device *dev);
522
523 /**
524 * @brief Check if the device pm is locked.
525 *
526 * @param dev Device instance.
527 *
528 * @retval true If device is locked.
529 * @retval false If device is not locked.
530 */
531 bool pm_device_state_is_locked(const struct device *dev);
532
533 /**
534 * @brief Check if the device is on a switchable power domain.
535 *
536 * @param dev Device instance.
537 *
538 * @retval true If device is on a switchable power domain.
539 * @retval false If device is not on a switchable power domain.
540 */
541 bool pm_device_on_power_domain(const struct device *dev);
542
543 /**
544 * @brief Add a device to a power domain.
545 *
546 * This function adds a device to a given power domain.
547 *
548 * @param dev Device to be added to the power domain.
549 * @param domain Power domain.
550 *
551 * @retval 0 If successful.
552 * @retval -EALREADY If device is already part of the power domain.
553 * @retval -ENOSYS If the application was built without power domain support.
554 * @retval -ENOSPC If there is no space available in the power domain to add the device.
555 */
556 int pm_device_power_domain_add(const struct device *dev,
557 const struct device *domain);
558
559 /**
560 * @brief Remove a device from a power domain.
561 *
562 * This function removes a device from a given power domain.
563 *
564 * @param dev Device to be removed from the power domain.
565 * @param domain Power domain.
566 *
567 * @retval 0 If successful.
568 * @retval -ENOSYS If the application was built without power domain support.
569 * @retval -ENOENT If device is not in the given domain.
570 */
571 int pm_device_power_domain_remove(const struct device *dev,
572 const struct device *domain);
573
574 /**
575 * @brief Check if the device is currently powered.
576 *
577 * @param dev Device instance.
578 *
579 * @retval true If device is currently powered
580 * @retval false If device is not currently powered
581 */
582 bool pm_device_is_powered(const struct device *dev);
583 #else
pm_device_state_get(const struct device * dev,enum pm_device_state * state)584 static inline int pm_device_state_get(const struct device *dev,
585 enum pm_device_state *state)
586 {
587 ARG_UNUSED(dev);
588
589 *state = PM_DEVICE_STATE_ACTIVE;
590
591 return 0;
592 }
593
pm_device_init_suspended(const struct device * dev)594 static inline void pm_device_init_suspended(const struct device *dev)
595 {
596 ARG_UNUSED(dev);
597 }
pm_device_init_off(const struct device * dev)598 static inline void pm_device_init_off(const struct device *dev)
599 {
600 ARG_UNUSED(dev);
601 }
pm_device_busy_set(const struct device * dev)602 static inline void pm_device_busy_set(const struct device *dev)
603 {
604 ARG_UNUSED(dev);
605 }
pm_device_busy_clear(const struct device * dev)606 static inline void pm_device_busy_clear(const struct device *dev)
607 {
608 ARG_UNUSED(dev);
609 }
pm_device_is_any_busy(void)610 static inline bool pm_device_is_any_busy(void) { return false; }
pm_device_is_busy(const struct device * dev)611 static inline bool pm_device_is_busy(const struct device *dev)
612 {
613 ARG_UNUSED(dev);
614 return false;
615 }
pm_device_wakeup_enable(const struct device * dev,bool enable)616 static inline bool pm_device_wakeup_enable(const struct device *dev,
617 bool enable)
618 {
619 ARG_UNUSED(dev);
620 ARG_UNUSED(enable);
621 return false;
622 }
pm_device_wakeup_is_enabled(const struct device * dev)623 static inline bool pm_device_wakeup_is_enabled(const struct device *dev)
624 {
625 ARG_UNUSED(dev);
626 return false;
627 }
pm_device_wakeup_is_capable(const struct device * dev)628 static inline bool pm_device_wakeup_is_capable(const struct device *dev)
629 {
630 ARG_UNUSED(dev);
631 return false;
632 }
pm_device_state_lock(const struct device * dev)633 static inline void pm_device_state_lock(const struct device *dev)
634 {
635 ARG_UNUSED(dev);
636 }
pm_device_state_unlock(const struct device * dev)637 static inline void pm_device_state_unlock(const struct device *dev)
638 {
639 ARG_UNUSED(dev);
640 }
pm_device_state_is_locked(const struct device * dev)641 static inline bool pm_device_state_is_locked(const struct device *dev)
642 {
643 ARG_UNUSED(dev);
644 return false;
645 }
pm_device_on_power_domain(const struct device * dev)646 static inline bool pm_device_on_power_domain(const struct device *dev)
647 {
648 ARG_UNUSED(dev);
649 return false;
650 }
651
pm_device_power_domain_add(const struct device * dev,const struct device * domain)652 static inline int pm_device_power_domain_add(const struct device *dev,
653 const struct device *domain)
654 {
655 return -ENOSYS;
656 }
657
pm_device_power_domain_remove(const struct device * dev,const struct device * domain)658 static inline int pm_device_power_domain_remove(const struct device *dev,
659 const struct device *domain)
660 {
661 return -ENOSYS;
662 }
663
pm_device_is_powered(const struct device * dev)664 static inline bool pm_device_is_powered(const struct device *dev)
665 {
666 ARG_UNUSED(dev);
667 return true;
668 }
669 #endif /* CONFIG_PM_DEVICE */
670
671 /** @} */
672
673 #ifdef __cplusplus
674 }
675 #endif
676
677 #endif
678