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. The suspension will
111then be carried out when the system work queue gets the chance to run. The
112sequence diagram shown below illustrates this scenario.
113
114.. figure:: images/devr-async-ops.svg
115
116    Asynchronous operation on a single device
117
118Implementation guidelines
119*************************
120
121In a first place, a device driver needs to implement the PM action callback used
122by the PM subsystem to suspend or resume devices.
123
124.. code-block:: c
125
126    static int mydev_pm_action(const struct device *dev,
127                               enum pm_device_action action)
128    {
129        switch (action) {
130        case PM_DEVICE_ACTION_SUSPEND:
131            /* suspend the device */
132            ...
133            break;
134        case PM_DEVICE_ACTION_RESUME:
135            /* resume the device */
136            ...
137            break;
138        default:
139            return -ENOTSUP;
140        }
141
142        return 0;
143    }
144
145The PM action callback calls are serialized by the PM subsystem, therefore, no
146special synchronization is required.
147
148To enable device runtime power management on a device, the driver needs to call
149:c:func:`pm_device_runtime_enable` at initialization time. Note that this
150function will suspend the device if its state is
151:c:enumerator:`PM_DEVICE_STATE_ACTIVE`. In case the device is physically
152suspended, the init function should call
153:c:func:`pm_device_init_suspended` before calling
154:c:func:`pm_device_runtime_enable`.
155
156.. code-block:: c
157
158    /* device driver initialization function */
159    static int mydev_init(const struct device *dev)
160    {
161        int ret;
162        ...
163
164        /* OPTIONAL: mark device as suspended if it is physically suspended */
165        pm_device_init_suspended(dev);
166
167        /* enable device runtime power management */
168        ret = pm_device_runtime_enable(dev);
169        if ((ret < 0) && (ret != -ENOSYS)) {
170            return ret;
171        }
172    }
173
174Device runtime power management can also be automatically enabled on a device
175instance by adding the ``zephyr,pm-device-runtime-auto`` flag onto the corresponding
176devicetree node. If enabled, :c:func:`pm_device_runtime_enable` is called immediately
177after the ``init`` function of the device runs and returns successfully.
178
179.. code-block:: dts
180
181    foo {
182        /* ... */
183        zephyr,pm-device-runtime-auto;
184    };
185
186Assuming an example device driver that implements an ``operation`` API call, the
187*get* and *put* operations could be carried out as follows:
188
189.. code-block:: c
190
191    static int mydev_operation(const struct device *dev)
192    {
193        int ret;
194
195        /* "get" device (increases usage count, resumes device if suspended) */
196        ret = pm_device_runtime_get(dev);
197        if (ret < 0) {
198            return ret;
199        }
200
201        /* do something with the device */
202        ...
203
204        /* "put" device (decreases usage count, suspends device if no more users) */
205        return pm_device_runtime_put(dev);
206    }
207
208In case the suspend operation is *slow*, the device driver can use the
209asynchronous API:
210
211.. code-block:: c
212
213    static int mydev_operation(const struct device *dev)
214    {
215        int ret;
216
217        /* "get" device (increases usage count, resumes device if suspended) */
218        ret = pm_device_runtime_get(dev);
219        if (ret < 0) {
220            return ret;
221        }
222
223        /* do something with the device */
224        ...
225
226        /* "put" device (decreases usage count, schedule suspend if no more users) */
227        return pm_device_runtime_put_async(dev, K_NO_WAIT);
228    }
229
230Examples
231********
232
233Some helpful examples showing device runtime power management features:
234
235* :zephyr_file:`tests/subsys/pm/device_runtime_api/`
236* :zephyr_file:`tests/subsys/pm/device_power_domains/`
237* :zephyr_file:`tests/subsys/pm/power_domain/`
238