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 types of device power management:
14
15 - :ref:`Device Runtime Power Management <pm-device-runtime-pm>`
16 - :ref:`System Power Management <pm-device-system-pm>`
17
18.. _pm-device-runtime-pm:
19
20Device Runtime Power Management
21*******************************
22
23In this method, the application or any component that deals with devices directly
24and has the best knowledge of their use, performs the device power management. This
25saves power if some devices that are not in use can be turned off or put
26in power saving mode. This method allows saving power even when the CPU is
27active. The components that use the devices need to be power aware and should
28be able to make decisions related to managing device power.
29
30When using this type of device power management, the kernel can change CPU
31power states quickly when :c:func:`pm_system_suspend()` gets called. This is
32because it does not need to spend time doing device power management if the
33devices are already put in the appropriate power state by the application or
34component managing the devices.
35
36For more information, see :ref:`pm-device-runtime`.
37
38.. _pm-device-system-pm:
39
40System Power Management
41***********************
42
43When using this type, device power management is mostly done inside
44:c:func:`pm_system_suspend()` along with entering a CPU or SOC power state.
45
46If a decision to enter a CPU lower power state is made, the power management
47subsystem will suspend devices before changing state. The subsystem takes care
48of suspending devices following their initialization order, ensuring that
49possible dependencies between them are satisfied. As soon as the CPU wakes up
50from a sleep state, devices are resumed in the opposite order that they were
51suspended.
52
53.. note::
54
55   When using :ref:`pm-system`, device transitions can be run from the idle thread.
56   As functions in this context cannot block, transitions that intend to use blocking
57   APIs **must** check whether they can do so with :c:func:`k_can_yield`.
58
59This type of device power management can be useful when the application is not
60power aware and does not implement runtime device power management. Though,
61:ref:`Device Runtime Power Management <pm-device-runtime-pm>` is the **preferred**
62option for device power management.
63
64.. note::
65
66    When using this type of device power management, the CPU will only enter
67    a low power state only if no device is in the middle of a hardware
68    transaction that cannot be interrupted.
69
70.. note::
71
72    This type of device power management is disabled when
73    :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE` is set to ``y`` (that is
74    the default value when :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME` is enabled)
75
76.. note::
77
78   Devices are suspended only when the last active core is entering a low power
79   state and devices are resumed by the first core that becomes active.
80
81Device Power Management States
82******************************
83
84The power management subsystem defines device states in
85:c:enum:`pm_device_state`. This type is used to track power states of
86a particular device. It is important to emphasize that, although the
87state is tracked by the subsystem, it is the responsibility of each device driver
88to handle device actions(:c:enum:`pm_device_action`) which change device state.
89
90Each :c:enum:`pm_device_action` have a direct an unambiguous relationship with
91a :c:enum:`pm_device_state`.
92
93.. graphviz::
94   :caption: Device actions x states
95
96    digraph {
97        node [shape=circle];
98        rankdir=LR;
99        subgraph {
100
101            SUSPENDED [label=PM_DEVICE_STATE_SUSPENDED];
102            SUSPENDING [label=PM_DEVICE_STATE_SUSPENDING];
103            ACTIVE [label=PM_DEVICE_STATE_ACTIVE];
104            OFF [label=PM_DEVICE_STATE_OFF];
105
106
107            ACTIVE -> SUSPENDING -> SUSPENDED;
108            ACTIVE -> SUSPENDED ["label"="PM_DEVICE_ACTION_SUSPEND"];
109            SUSPENDED -> ACTIVE ["label"="PM_DEVICE_ACTION_RESUME"];
110
111            {rank = same; SUSPENDED; SUSPENDING;}
112
113            OFF -> SUSPENDED ["label"="PM_DEVICE_ACTION_TURN_ON"];
114            SUSPENDED -> OFF ["label"="PM_DEVICE_ACTION_TURN_OFF"];
115            ACTIVE -> OFF ["label"="PM_DEVICE_ACTION_TURN_OFF"];
116        }
117    }
118
119As mentioned above, device drivers do not directly change between these states.
120This is entirely done by the power management subsystem. Instead, drivers are
121responsible for implementing any hardware-specific tasks needed to handle state
122changes.
123
124Device Model with Power Management Support
125******************************************
126
127Drivers initialize devices using macros. See :ref:`device_model_api` for
128details on how these macros are used. A driver which implements device power
129management support must provide these macros with arguments that describe its
130power management implementation.
131
132Use :c:macro:`PM_DEVICE_DEFINE` or :c:macro:`PM_DEVICE_DT_DEFINE` to define the
133power management resources required by a driver. These macros allocate the
134driver-specific state which is required by the power management subsystem.
135
136Drivers can use :c:macro:`PM_DEVICE_GET` or
137:c:macro:`PM_DEVICE_DT_GET` to get a pointer to this state. These
138pointers should be passed to ``DEVICE_DEFINE`` or ``DEVICE_DT_DEFINE``
139to initialize the power management field in each :c:struct:`device`.
140
141Here is some example code showing how to implement device power management
142support in a device driver.
143
144.. code-block:: c
145
146    #define DT_DRV_COMPAT dummy_device
147
148    static int dummy_driver_pm_action(const struct device *dev,
149                                      enum pm_device_action action)
150    {
151        switch (action) {
152        case PM_DEVICE_ACTION_SUSPEND:
153            /* suspend the device */
154            ...
155            break;
156        case PM_DEVICE_ACTION_RESUME:
157            /* resume the device */
158            ...
159            break;
160        case PM_DEVICE_ACTION_TURN_ON:
161            /*
162             * powered on the device, used when the power
163             * domain this device belongs is resumed.
164             */
165            ...
166            break;
167        case PM_DEVICE_ACTION_TURN_OFF:
168            /*
169             * power off the device, used when the power
170             * domain this device belongs is suspended.
171             */
172            ...
173            break;
174        default:
175            return -ENOTSUP;
176        }
177
178        return 0;
179    }
180
181    PM_DEVICE_DT_INST_DEFINE(0, dummy_driver_pm_action);
182
183    DEVICE_DT_INST_DEFINE(0, &dummy_init,
184        PM_DEVICE_DT_INST_GET(0), NULL, NULL, POST_KERNEL,
185        CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, NULL);
186
187.. _pm-device-busy:
188
189Busy Status Indication
190**********************
191
192When the system is idle and the SoC is going to sleep, the power management
193subsystem can suspend devices, as described in :ref:`pm-device-system-pm`. This
194can cause device hardware to lose some states. Suspending a device which is in
195the middle of a hardware transaction, such as writing to a flash memory, may
196lead to undefined behavior or inconsistent states. This API guards such
197transactions by indicating to the kernel that the device is in the middle of an
198operation and should not be suspended.
199
200When :c:func:`pm_device_busy_set` is called, the device is marked as busy and
201the system will not do power management on it. After the device is no
202longer doing an operation and can be suspended, it should call
203:c:func:`pm_device_busy_clear`.
204
205Wakeup capability
206*****************
207
208Some devices are capable of waking the system up from a sleep state.
209When a device has such capability, applications can enable or disable
210this feature on a device dynamically using
211:c:func:`pm_device_wakeup_enable`.
212
213This property can be set on device declaring the property ``wakeup-source`` in
214the device node in devicetree. For example, this devicetree fragment sets the
215``gpio0`` device as a "wakeup" source:
216
217.. code-block:: devicetree
218
219                gpio0: gpio@40022000 {
220                        compatible = "ti,cc13xx-cc26xx-gpio";
221                        reg = <0x40022000 0x400>;
222                        interrupts = <0 0>;
223                        status = "disabled";
224                        label = "GPIO_0";
225                        gpio-controller;
226                        wakeup-source;
227                        #gpio-cells = <2>;
228                };
229
230By default, "wakeup" capable devices do not have this functionality enabled
231during the device initialization. Applications can enable this functionality
232later calling :c:func:`pm_device_wakeup_enable`.
233
234.. note::
235
236   This property is **only** used by the system power management to identify
237   devices that should not be suspended.
238   It is responsibility of driver or the application to do any additional
239   configuration required by the device to support it.
240
241Power Domain
242************
243
244Power domain on Zephyr is represented as a regular device. The power management
245subsystem ensures that a domain is resumed before and suspended after devices
246using it. For more details, see :ref:`pm-power-domain`.
247