1Device Power Management
2#######################
3
4Introduction
5************
6
7Device power management (PM) on Zephyr is a feature that enables devices to
8save energy when they are not being used. This feature can be enabled by
9setting :kconfig:option:`CONFIG_PM_DEVICE` to ``y``. When this option is
10selected, device drivers implementing power management will be able to take
11advantage of the device power management subsystem.
12
13Zephyr supports two methods of device power management:
14
15 - :ref:`Device Runtime Power Management <pm-device-runtime-pm>`
16 - :ref:`System-Managed Device Power Management <pm-device-system-pm>`
17
18.. _pm-device-runtime-pm:
19
20Device Runtime Power Management
21===============================
22
23Device runtime power management involves coordinated interaction between
24device drivers, subsystems, and applications. While device drivers
25play a crucial role in directly controlling the power state of
26devices, the decision to suspend or resume a device can also be
27influenced by higher layers of the software stack.
28
29Each layer—device drivers, subsystems, and applications—can operate
30independently without needing to know about the specifics of the other
31layers because the subsystem uses reference count to check when it needs
32to suspend or resume a device.
33
34- **Device drivers** are responsible for managing the
35  power state of devices. They interact directly with the hardware to
36  put devices into low-power states (suspend) when they are not in
37  use, and bring them back (resume) when needed. Drivers should use the
38  :ref:`device runtime power management APIs <device_runtime_apis>` provided
39  by Zephyr to control the power state of devices.
40
41- **Subsystems**, such as sensors, file systems,
42  and network, can also influence device power management.
43  Subsystems may have better knowledge about the overall system
44  state and workload, allowing them to make informed decisions about
45  when to suspend or resume devices. For example, a networking
46  subsystem may decide to keep a network interface powered on if it
47  expects network activity in the near future.
48
49- **Applications** running on Zephyr can impact device
50  power management as well. An application may have specific
51  requirements regarding device usage and power consumption. For
52  example, an application that streams data over a network may need
53  to keep the network interface powered on continuously.
54
55Coordination between device drivers, subsystems, and applications is
56key to efficient device power management. For example, a device driver
57may not know that a subsystem will perform a series of sequential
58operations that require a device to remain powered on. In such cases,
59the subsystem can use device runtime power management to ensure that
60the device remains in an active state until the operations are
61complete.
62
63When using this Device Runtime Power Management, the System Power
64Management subsystem is able to change power states quickly because it
65does not need to spend time suspending and resuming devices that are
66runtime enabled.
67
68For more information, see :ref:`pm-device-runtime`.
69
70.. _pm-device-system-pm:
71
72System-Managed Device Power Management
73======================================
74
75The system managed device power management (PM) framework is a method where
76devices are suspended along with the system entering a CPU (or SoC) power state.
77It can be enabled by setting :kconfig:option:`CONFIG_PM_DEVICE_SYSTEM_MANAGED`.
78When using this method, device power management is mostly done inside
79:c:func:`pm_system_suspend()`.
80
81If a decision to enter a CPU lower power state is made, the power management
82subsystem will check if the selected low power state triggers device power
83management and then suspend devices before changing state. The subsystem takes
84care of suspending devices following their initialization order, ensuring that
85possible dependencies between them are satisfied. As soon as the CPU wakes up
86from a sleep state, devices are resumed in the opposite order that they were
87suspended.
88
89The decision about suspending devices when entering a low power state is done based on the
90state and if it has set the property ``zephyr,pm-device-disabled``. Here is
91an example of a target with two low power states with only one triggering device power
92management:
93
94.. code-block:: devicetree
95
96   /* Node in a DTS file */
97   cpus {
98        power-states {
99                state0: state0 {
100                        compatible = "zephyr,power-state";
101                        power-state-name = "standby";
102                        min-residency-us = <5000>;
103                        exit-latency-us = <240>;
104                        zephyr,pm-device-disabled;
105                };
106                state1: state1 {
107                        compatible = "zephyr,power-state";
108                        power-state-name = "suspend-to-ram";
109                        min-residency-us = <8000>;
110                        exit-latency-us = <360>;
111                };
112        };
113   };
114
115.. note::
116
117   When using :ref:`pm-system`, device transitions can be run from the idle thread.
118   As functions in this context cannot block, transitions that intend to use blocking
119   APIs **must** check whether they can do so with :c:func:`k_can_yield`.
120
121This method of device power management can be useful in the following scenarios:
122
123- Systems with no device requiring any blocking operations when suspending and
124  resuming. This implementation is reasonably simpler than device runtime
125  power management.
126- For devices that can not make any power management decision and have to be
127  always active. For example a firmware using Zephyr that is controlled by an
128  external entity (e.g Host CPU). In this scenario, some devices have to be
129  always active and should be suspended together with the SoC when requested by
130  this external entity.
131
132It is important to emphasize that this method has drawbacks (see above) and
133:ref:`Device Runtime Power Management <pm-device-runtime-pm>` is the
134**preferred** method for implementing device power management.
135
136.. note::
137
138    When using this method of device power management, the CPU will not
139    enter a low-power state if a device cannot be suspended. For example,
140    if a device returns an error such as ``-EBUSY`` in response to the
141    ``PM_DEVICE_ACTION_SUSPEND`` action, indicating it is in the middle of
142    a transaction that cannot be interrupted. Another condition that
143    prevents the CPU from entering a low-power state is if the option
144    :kconfig:option:`CONFIG_PM_NEED_ALL_DEVICES_IDLE` is set and a device
145    is marked as busy.
146
147.. note::
148
149   Devices are suspended only when the last active core is entering a low power
150   state and devices are resumed by the first core that becomes active.
151
152Device Power Management States
153******************************
154
155The power management subsystem defines device states in
156:c:enum:`pm_device_state`. This method is used to track power states of
157a particular device. It is important to emphasize that, although the
158state is tracked by the subsystem, it is the responsibility of each device driver
159to handle device actions(:c:enum:`pm_device_action`) which change device state.
160
161Each :c:enum:`pm_device_action` have a direct an unambiguous relationship with
162a :c:enum:`pm_device_state`.
163
164.. graphviz::
165   :caption: Device actions x states
166
167    digraph {
168        node [shape=circle];
169        rankdir=LR;
170        subgraph {
171
172            SUSPENDED [label=PM_DEVICE_STATE_SUSPENDED];
173            SUSPENDING [label=PM_DEVICE_STATE_SUSPENDING];
174            ACTIVE [label=PM_DEVICE_STATE_ACTIVE];
175            OFF [label=PM_DEVICE_STATE_OFF];
176
177
178            ACTIVE -> SUSPENDING -> SUSPENDED;
179            ACTIVE -> SUSPENDED ["label"="PM_DEVICE_ACTION_SUSPEND"];
180            SUSPENDED -> ACTIVE ["label"="PM_DEVICE_ACTION_RESUME"];
181
182            {rank = same; SUSPENDED; SUSPENDING;}
183
184            OFF -> SUSPENDED ["label"="PM_DEVICE_ACTION_TURN_ON"];
185            SUSPENDED -> OFF ["label"="PM_DEVICE_ACTION_TURN_OFF"];
186            ACTIVE -> OFF ["label"="PM_DEVICE_ACTION_TURN_OFF"];
187        }
188    }
189
190As mentioned above, device drivers do not directly change between these states.
191This is entirely done by the power management subsystem. Instead, drivers are
192responsible for implementing any hardware-specific tasks needed to handle state
193changes.
194
195Device Model with Power Management Support
196******************************************
197
198Drivers initialize devices using macros. See :ref:`device_model_api` for
199details on how these macros are used. A driver which implements device power
200management support must provide these macros with arguments that describe its
201power management implementation.
202
203Use :c:macro:`PM_DEVICE_DEFINE` or :c:macro:`PM_DEVICE_DT_DEFINE` to define the
204power management resources required by a driver. These macros allocate the
205driver-specific state which is required by the power management subsystem.
206
207Drivers can use :c:macro:`PM_DEVICE_GET` or
208:c:macro:`PM_DEVICE_DT_GET` to get a pointer to this state. These
209pointers should be passed to ``DEVICE_DEFINE`` or ``DEVICE_DT_DEFINE``
210to initialize the power management field in each :c:struct:`device`.
211
212Here is some example code showing how to implement device power management
213support in a device driver.
214
215.. code-block:: c
216
217    #define DT_DRV_COMPAT dummy_device
218
219    static int dummy_driver_pm_action(const struct device *dev,
220                                      enum pm_device_action action)
221    {
222        switch (action) {
223        case PM_DEVICE_ACTION_SUSPEND:
224            /* suspend the device */
225            ...
226            break;
227        case PM_DEVICE_ACTION_RESUME:
228            /* resume the device */
229            ...
230            break;
231        case PM_DEVICE_ACTION_TURN_ON:
232            /*
233             * powered on the device, used when the power
234             * domain this device belongs is resumed.
235             */
236            ...
237            break;
238        case PM_DEVICE_ACTION_TURN_OFF:
239            /*
240             * power off the device, used when the power
241             * domain this device belongs is suspended.
242             */
243            ...
244            break;
245        default:
246            return -ENOTSUP;
247        }
248
249        return 0;
250    }
251
252    PM_DEVICE_DT_INST_DEFINE(0, dummy_driver_pm_action);
253
254    DEVICE_DT_INST_DEFINE(0, &dummy_init,
255        PM_DEVICE_DT_INST_GET(0), NULL, NULL, POST_KERNEL,
256        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL);
257
258.. _pm-device-shell:
259
260Shell Commands
261**************
262
263Power management actions can be triggered from shell commands for testing
264purposes. To do that, enable the :kconfig:option:`CONFIG_PM_DEVICE_SHELL`
265option and issue a ``pm`` command on a device from the shell, for example:
266
267.. code-block:: console
268
269        uart:~$ device list
270        - buttons (active)
271        uart:~$ pm suspend buttons
272        uart:~$ device list
273        devices:
274        - buttons (suspended)
275
276To print the power management state of a device, enable
277:kconfig:option:`CONFIG_DEVICE_SHELL` and use the ``device list`` command, for
278example:
279
280.. code-block:: console
281
282        uart:~$ device list
283        devices:
284        - i2c@40003000 (active)
285        - buttons (active, usage=1)
286        - leds (READY)
287
288In this case, ``leds`` does not support PM, ``i2c`` supports PM with manual
289suspend and resume actions and it's currently active, ``buttons`` supports
290runtime PM and it's currently active with one user.
291
292.. _pm-device-busy:
293
294Busy Status Indication
295**********************
296
297When the system is idle and the SoC is going to sleep, the power management
298subsystem can suspend devices, as described in :ref:`pm-device-system-pm`. This
299can cause device hardware to lose some states. Suspending a device which is in
300the middle of a hardware transaction, such as writing to a flash memory, may
301lead to undefined behavior or inconsistent states. This API guards such
302transactions by indicating to the kernel that the device is in the middle of an
303operation and should not be suspended.
304
305When :c:func:`pm_device_busy_set` is called, the device is marked as busy and
306the system will not do power management on it. After the device is no
307longer doing an operation and can be suspended, it should call
308:c:func:`pm_device_busy_clear`.
309
310.. _pm-device-constraint:
311
312Device Power Management X System Power Management
313*************************************************
314
315When managing power in embedded systems, it's crucial to understand
316the interplay between device power state and the overall system power
317state. Some devices may have dependencies on the system power
318state. For example, certain low-power states of the SoC might not
319supply power to peripheral devices, leading to problems if the device
320is in the middle of an operation. Proper coordination is essential to
321maintain system stability and data integrity.
322
323To avoid this sort of problem, devices must :ref:`get and release lock <pm-policy-power-states>`
324power states that cause power loss during an operation.
325
326Zephyr provides a mechanism for devices to declare which power states cause power
327loss and an API that automatically get and put lock on them. This feature is
328enabled setting :kconfig:option:`CONFIG_PM_POLICY_DEVICE_CONSTRAINTS` to ``y``.
329
330Once this feature is enabled, devices must declare in devicetree which
331states cause power loss. In the following example, device ``test_dev``
332says that power states ``state1`` and ``state2`` cause power loss.
333
334.. code-block:: devicetree
335
336    power-states {
337            state0: state0 {
338                    compatible = "zephyr,power-state";
339                    power-state-name = "suspend-to-idle";
340                    min-residency-us = <10000>;
341                    exit-latency-us = <100>;
342            };
343
344            state1: state1 {
345                    compatible = "zephyr,power-state";
346                    power-state-name = "standby";
347                    min-residency-us = <20000>;
348                    exit-latency-us = <200>;
349            };
350
351            state2: state2 {
352                    compatible = "zephyr,power-state";
353                    power-state-name = "suspend-to-ram";
354                    min-residency-us = <50000>;
355                    exit-latency-us = <500>;
356            };
357
358            state3: state3 {
359                    compatible = "zephyr,power-state";
360                    power-state-name = "suspend-to-ram";
361                    status = "disabled";
362            };
363    };
364
365    test_dev: test_dev {
366            compatible = "test-device-pm";
367            status = "okay";
368            zephyr,disabling-power-states = <&state1 &state2>;
369    };
370
371After that devices can lock these state calling
372:c:func:`pm_policy_device_power_lock_get` and release with
373:c:func:`pm_policy_device_power_lock_put`. For example:
374
375.. code-block:: C
376
377    static void timer_expire_cb(struct k_timer *timer)
378    {
379           struct test_driver_data *data = k_timer_user_data_get(timer);
380
381           data->ongoing = false;
382           k_timer_stop(timer);
383           pm_policy_device_power_lock_put(data->self);
384    }
385
386    void test_driver_async_operation(const struct device *dev)
387    {
388           struct test_driver_data *data = dev->data;
389
390           data->ongoing = true;
391           pm_policy_device_power_lock_get(dev);
392
393           /** Lets set a timer big enough to ensure that any deep
394            *  sleep state would be suitable but constraints will
395            *  make only state0 (suspend-to-idle) will be used.
396            */
397           k_timer_start(&data->timer, K_MSEC(500), K_NO_WAIT);
398    }
399
400Wakeup capability
401*****************
402
403Some devices are capable of waking the system up from a sleep state.
404When a device has such capability, applications can enable or disable
405this feature on a device dynamically using
406:c:func:`pm_device_wakeup_enable`.
407
408This property can be set on device declaring the property ``wakeup-source`` in
409the device node in devicetree. For example, this devicetree fragment sets the
410``gpio0`` device as a "wakeup" source:
411
412.. code-block:: devicetree
413
414                gpio0: gpio@40022000 {
415                        compatible = "ti,cc13xx-cc26xx-gpio";
416                        reg = <0x40022000 0x400>;
417                        interrupts = <0 0>;
418                        status = "disabled";
419                        label = "GPIO_0";
420                        gpio-controller;
421                        wakeup-source;
422                        #gpio-cells = <2>;
423                };
424
425By default, "wakeup" capable devices do not have this functionality enabled
426during the device initialization. Applications can enable this functionality
427later calling :c:func:`pm_device_wakeup_enable`.
428
429.. note::
430
431   This property is **only** used by the system power management to identify
432   devices that should not be suspended.
433   It is responsibility of driver or the application to do any additional
434   configuration required by the device to support it.
435
436Examples
437********
438
439Some helpful examples showing device power management features:
440
441* :zephyr_file:`samples/subsys/pm/device_pm/`
442* :zephyr_file:`tests/subsys/pm/power_mgmt/`
443* :zephyr_file:`tests/subsys/pm/device_wakeup_api/`
444* :zephyr_file:`tests/subsys/pm/device_driver_init/`
445