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