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