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