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