diff --git a/doc/services/pm/device.rst b/doc/services/pm/device.rst index e473fe3f4bf..379ebfbef74 100644 --- a/doc/services/pm/device.rst +++ b/doc/services/pm/device.rst @@ -307,6 +307,96 @@ the system will not do power management on it. After the device is no longer doing an operation and can be suspended, it should call :c:func:`pm_device_busy_clear`. +.. _pm-device-constraint: + +Device Power Management X System Power Management +************************************************* + +When managing power in embedded systems, it's crucial to understand +the interplay between device power state and the overall system power +state. Some devices may have dependencies on the system power +state. For example, certain low-power states of the SoC might not +supply power to peripheral devices, leading to problems if the device +is in the middle of an operation. Proper coordination is essential to +maintain system stability and data integrity. + +To avoid this sort of problem, devices must :ref:`get and release lock ` +power states that cause power loss during an operation. + +Zephyr provides a mechanism for devices to declare which power states cause power +loss and an API that automatically get and put lock on them. This feature is +enabled setting :kconfig:option:`CONFIG_PM_POLICY_DEVICE_CONSTRAINTS` to ``y``. + +Once this feature is enabled, devices must declare in devicetree which +states cause power loss. In the following example, device ``test_dev`` +says that power states ``state1`` and ``state2`` cause power loss. + +.. code-block:: devicetree + + power-states { + state0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <10000>; + exit-latency-us = <100>; + }; + + state1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <20000>; + exit-latency-us = <200>; + }; + + state2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + min-residency-us = <50000>; + exit-latency-us = <500>; + }; + + state3: state3 { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + status = "disabled"; + }; + }; + + test_dev: test_dev { + compatible = "test-device-pm"; + status = "okay"; + zephyr,disabling-power-states = <&state1 &state2>; + }; + +After that devices can lock these state calling +:c:func:`pm_policy_device_power_lock_get` and release with +:c:func:`pm_policy_device_power_lock_put`. For example: + +.. code-block:: C + + static void timer_expire_cb(struct k_timer *timer) + { + struct test_driver_data *data = k_timer_user_data_get(timer); + + data->ongoing = false; + k_timer_stop(timer); + pm_policy_device_power_lock_put(data->self); + } + + void test_driver_async_operation(const struct device *dev) + { + struct test_driver_data *data = dev->data; + + data->ongoing = true; + pm_policy_device_power_lock_get(dev); + + /** Lets set a timer big enough to ensure that any deep + * sleep state would be suitable but constraints will + * make only state0 (suspend-to-idle) will be used. + */ + k_timer_start(&data->timer, K_MSEC(500), K_NO_WAIT); + } + Wakeup capability ***************** diff --git a/doc/services/pm/system.rst b/doc/services/pm/system.rst index d6ec306a200..49ba81e9357 100644 --- a/doc/services/pm/system.rst +++ b/doc/services/pm/system.rst @@ -122,6 +122,8 @@ remaining time until the next scheduled timeout. An example of an application that defines its own policy can be found in :zephyr_file:`tests/subsys/pm/power_mgmt/`. +.. _pm-policy-power-states: + Policy and Power States ------------------------