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