1.. _pm-device-runtime: 2 3Device Runtime Power Management 4############################### 5 6Introduction 7************ 8 9The device runtime power management (PM) framework is an active power management 10mechanism which reduces the overall system power consumption by suspending the 11devices which are idle or not used independently of the system state. It can be 12enabled by setting :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME`. In this model the device 13driver is responsible to indicate when it needs the device and when it does not. 14This information is used to determine when to suspend or resume a device based 15on usage count. 16 17When device runtime power management is enabled on a device, its state will be 18initially set to a :c:enumerator:`PM_DEVICE_STATE_SUSPENDED` indicating it is 19not used. On the first device request, it will be resumed and so put into the 20:c:enumerator:`PM_DEVICE_STATE_ACTIVE` state. The device will remain in this 21state until it is no longer used. At this point, the device will be suspended 22until the next device request. If the suspension is performed synchronously the 23device will be immediately put into the 24:c:enumerator:`PM_DEVICE_STATE_SUSPENDED` state, whereas if it is performed 25asynchronously, it will be put into the 26:c:enumerator:`PM_DEVICE_STATE_SUSPENDING` state first and then into the 27:c:enumerator:`PM_DEVICE_STATE_SUSPENDED` state when the action is run. 28 29For devices on a power domain (via the devicetree 'power-domains' property), device runtime 30power management automatically attempts to request and release the dependent domain 31in response to :c:func:`pm_device_runtime_get` and :c:func:`pm_device_runtime_put` 32calls on the child device. 33 34For the previous to automatically control the power domain state, device runtime PM must be enabled 35on the power domain device (either through the ``zephyr,pm-device-runtime-auto`` devicetree property 36or :c:func:`pm_device_runtime_enable`). 37 38.. graphviz:: 39 :caption: Device states and transitions 40 41 digraph { 42 node [shape=box]; 43 init [shape=point]; 44 45 SUSPENDED [label=PM_DEVICE_STATE_SUSPENDED]; 46 ACTIVE [label=PM_DEVICE_STATE_ACTIVE]; 47 SUSPENDING [label=PM_DEVICE_STATE_SUSPENDING]; 48 49 init -> SUSPENDED; 50 SUSPENDED -> ACTIVE; 51 ACTIVE -> SUSPENDED; 52 ACTIVE -> SUSPENDING [constraint=false] 53 SUSPENDING -> SUSPENDED [constraint=false]; 54 SUSPENDED -> SUSPENDING [style=invis]; 55 SUSPENDING -> ACTIVE [style=invis]; 56 } 57 58The device runtime power management framework has been designed to minimize 59devices power consumption with minimal application work. Device drivers are 60responsible for indicating when they need the device to be operational and 61when they do not. Therefore, applications can not manually suspend or resume a 62device. An application can, however, decide when to disable or enable runtime 63power management for a device. This can be useful, for example, if an 64application wants a particular device to be always active. 65 66Design principles 67***************** 68 69When runtime PM is enabled on a device it will no longer be resumed or suspended 70during system power transitions. Instead, the device is fully responsible to 71indicate when it needs a device and when it does not. The device runtime PM API 72uses reference counting to keep track of device's usage. This allows the API to 73determine when a device needs to be resumed or suspended. The API uses the *get* 74and *put* terminology to indicate when a device is needed or not, respectively. 75This mechanism plays a key role when we account for device dependencies. For 76example, if a bus device is used by multiple sensors, we can keep the bus active 77until the last sensor has finished using it. 78 79.. note:: 80 81 As of today, the device runtime power management API does not manage device 82 dependencies. This effectively means that, if a device depends on other 83 devices to operate (e.g. a sensor may depend on a bus device), the bus will 84 be resumed and suspended on every transaction. In general, it is more 85 efficient to keep parent devices active when their children are used, since 86 the children may perform multiple transactions in a short period of time. 87 Until this feature is added, devices can manually *get* or *put* their 88 dependencies. 89 90The :c:func:`pm_device_runtime_get` function can be used by a device driver to 91indicate it *needs* the device to be active or operational. This function will 92increase device usage count and resume the device if necessary. Similarly, the 93:c:func:`pm_device_runtime_put` function can be used to indicate that the device 94is no longer needed. This function will decrease the device usage count and 95suspend the device if necessary. It is worth to note that in both cases, the 96operation is carried out synchronously. The sequence diagram shown below 97illustrates how a device can use this API and the expected sequence of events. 98 99.. figure:: images/devr-sync-ops.svg 100 101 Synchronous operation on a single device 102 103The synchronous model is as simple as it gets. However, it may introduce 104unnecessary delays since the application will not get the operation result until 105the device is suspended (in case device is no longer used). It will likely not 106be a problem if the operation is fast, e.g. a register toggle. However, the 107situation will not be the same if suspension involves sending packets through a 108slow bus. For this reason the device drivers can also make use of the 109:c:func:`pm_device_runtime_put_async` function. This function will schedule 110the suspend operation, again, if device is no longer used. 111 112 113By default, runtime PM operations are offloaded to the system work queue. 114However, device drivers must not perform any blocking operations during suspend, as 115this can stall the system work queue and negatively impact system responsiveness. 116 117To address this, applications can configure runtime PM to use a dedicated work queue 118by enabling :kconfig:option:`CONFIG_PM_DEVICE_RUNTIME_USE_DEDICATED_WQ`. 119 120If blocking behavior is required—for example, when accessing a slow peripheral 121or waiting for a bus transaction—the PM subsystem work queue must be used instead. 122Drivers that require this behavior can explicitly request it by enabling 123:kconfig:option:`CONFIG_PM_DEVICE_DRIVER_NEEDS_DEDICATED_WQ`. 124 125For targets with constrained resources that do not need asynchronous 126operations, this functionality can be disabled altogether by 127de-selecting :kconfig:option:`CONFIOG_PM_DEVICE_RUNTIME_ASYNC`, reducing 128memory usage and system complexity. 129 130 131.. figure:: images/devr-async-ops.svg 132 133 Asynchronous operation on a single device 134 135Implementation guidelines 136************************* 137 138In a first place, a device driver needs to implement the PM action callback used 139by the PM subsystem to suspend or resume devices. 140 141.. code-block:: c 142 143 static int mydev_pm_action(const struct device *dev, 144 enum pm_device_action action) 145 { 146 switch (action) { 147 case PM_DEVICE_ACTION_SUSPEND: 148 /* suspend the device */ 149 ... 150 break; 151 case PM_DEVICE_ACTION_RESUME: 152 /* resume the device */ 153 ... 154 break; 155 default: 156 return -ENOTSUP; 157 } 158 159 return 0; 160 } 161 162The PM action callback calls are serialized by the PM subsystem, therefore, no 163special synchronization is required. 164 165To enable device runtime power management on a device, the driver needs to call 166:c:func:`pm_device_runtime_enable` at initialization time. Note that this 167function will suspend the device if its state is 168:c:enumerator:`PM_DEVICE_STATE_ACTIVE`. In case the device is physically 169suspended, the init function should call 170:c:func:`pm_device_init_suspended` before calling 171:c:func:`pm_device_runtime_enable`. 172 173.. code-block:: c 174 175 /* device driver initialization function */ 176 static int mydev_init(const struct device *dev) 177 { 178 int ret; 179 ... 180 181 /* OPTIONAL: mark device as suspended if it is physically suspended */ 182 pm_device_init_suspended(dev); 183 184 /* enable device runtime power management */ 185 ret = pm_device_runtime_enable(dev); 186 if ((ret < 0) && (ret != -ENOSYS)) { 187 return ret; 188 } 189 } 190 191Device runtime power management can also be automatically enabled on a device 192instance by adding the ``zephyr,pm-device-runtime-auto`` flag onto the corresponding 193devicetree node. If enabled, :c:func:`pm_device_runtime_enable` is called immediately 194after the ``init`` function of the device runs and returns successfully. 195 196.. code-block:: dts 197 198 foo { 199 /* ... */ 200 zephyr,pm-device-runtime-auto; 201 }; 202 203Assuming an example device driver that implements an ``operation`` API call, the 204*get* and *put* operations could be carried out as follows: 205 206.. code-block:: c 207 208 static int mydev_operation(const struct device *dev) 209 { 210 int ret; 211 212 /* "get" device (increases usage count, resumes device if suspended) */ 213 ret = pm_device_runtime_get(dev); 214 if (ret < 0) { 215 return ret; 216 } 217 218 /* do something with the device */ 219 ... 220 221 /* "put" device (decreases usage count, suspends device if no more users) */ 222 return pm_device_runtime_put(dev); 223 } 224 225In case the suspend operation is *slow*, the device driver can use the 226asynchronous API: 227 228.. code-block:: c 229 230 static int mydev_operation(const struct device *dev) 231 { 232 int ret; 233 234 /* "get" device (increases usage count, resumes device if suspended) */ 235 ret = pm_device_runtime_get(dev); 236 if (ret < 0) { 237 return ret; 238 } 239 240 /* do something with the device */ 241 ... 242 243 /* "put" device (decreases usage count, schedule suspend if no more users) */ 244 return pm_device_runtime_put_async(dev, K_NO_WAIT); 245 } 246 247Examples 248******** 249 250Some helpful examples showing device runtime power management features: 251 252* :zephyr_file:`tests/subsys/pm/device_runtime_api/` 253* :zephyr_file:`tests/subsys/pm/device_power_domains/` 254* :zephyr_file:`tests/subsys/pm/power_domain/` 255