From db3d51bb7d40c8e38100fc2eb2d13ca6f0785e83 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Sat, 12 Mar 2022 21:10:42 +1000 Subject: [PATCH] pm: device_runtime: add `zephyr,pm-device-runtime-auto` Add the `zephyr,pm-device-runtime-auto` flag to `pm.yaml` and `struct pm_device`. This flag is intended to signify to the boot system that device runtime PM should be automatically enabled on the device after the init function has run. Only run `pm_device_runtime_auto_enable` function on a device if initialisation succeeded. This prevents actions being run on devices that are not ready. Signed-off-by: Jordan Yates --- dts/bindings/base/pm.yaml | 6 ++++++ include/zephyr/pm/device.h | 20 ++++++++++++-------- include/zephyr/pm/device_runtime.h | 20 ++++++++++++++++++++ kernel/init.c | 5 +++++ subsys/pm/device_runtime.c | 11 +++++++++++ 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/dts/bindings/base/pm.yaml b/dts/bindings/base/pm.yaml index 7caa774bc02..0776170d8f2 100644 --- a/dts/bindings/base/pm.yaml +++ b/dts/bindings/base/pm.yaml @@ -24,3 +24,9 @@ properties: The device will be notified when the power domain it belongs to is either suspended or resumed. + + zephyr,pm-device-runtime-auto: + type: boolean + description: | + Automatically configure the device for runtime power management after the + init function runs. diff --git a/include/zephyr/pm/device.h b/include/zephyr/pm/device.h index 074cf9bbde2..466c528f020 100644 --- a/include/zephyr/pm/device.h +++ b/include/zephyr/pm/device.h @@ -45,8 +45,10 @@ enum pm_device_flag { PM_DEVICE_FLAG_RUNTIME_ENABLED, /** Indicates if the device pm is locked. */ PM_DEVICE_FLAG_STATE_LOCKED, - /** Indicateds if the device is used as a power domain */ + /** Indicates if the device is used as a power domain */ PM_DEVICE_FLAG_PD, + /** Indicates if device runtime PM should be automatically enabled */ + PM_DEVICE_FLAG_RUNTIME_AUTO, }; /** @endcond */ @@ -168,13 +170,15 @@ struct pm_device { * * @param node_id Devicetree node for the initialized device (can be invalid). */ -#define Z_PM_DEVICE_FLAGS(node_id) \ - (COND_CODE_1( \ - DT_NODE_EXISTS(node_id), \ - ((DT_PROP_OR(node_id, wakeup_source, 0) \ - << PM_DEVICE_FLAG_WS_CAPABLE) | \ - (DT_NODE_HAS_COMPAT(node_id, power_domain) << \ - PM_DEVICE_FLAG_PD)), \ +#define Z_PM_DEVICE_FLAGS(node_id) \ + (COND_CODE_1( \ + DT_NODE_EXISTS(node_id), \ + ((DT_PROP_OR(node_id, wakeup_source, 0) \ + << PM_DEVICE_FLAG_WS_CAPABLE) | \ + (DT_PROP_OR(node_id, zephyr_pm_device_runtime_auto, 0) \ + << PM_DEVICE_FLAG_RUNTIME_AUTO) | \ + (DT_NODE_HAS_COMPAT(node_id, power_domain) << \ + PM_DEVICE_FLAG_PD)), \ (0))) /** diff --git a/include/zephyr/pm/device_runtime.h b/include/zephyr/pm/device_runtime.h index cb7c7d37b1e..c965caa89b3 100644 --- a/include/zephyr/pm/device_runtime.h +++ b/include/zephyr/pm/device_runtime.h @@ -22,6 +22,20 @@ extern "C" { */ #if defined(CONFIG_PM_DEVICE_RUNTIME) || defined(__DOXYGEN__) +/** + * @brief Automatically enable device runtime based on devicetree properties + * + * @note Must not be called from application code. See the + * zephyr,pm-device-runtime-auto property in pm.yaml and z_sys_init_run_level. + * + * @param dev Device instance. + * + * @retval 0 If the device runtime PM is enabled successfully or it has not + * been requested for this device in devicetree. + * @retval -errno Other negative errno, result of enabled device runtime PM. + */ +int pm_device_runtime_auto_enable(const struct device *dev); + /** * @brief Enable device runtime PM * @@ -142,6 +156,12 @@ bool pm_device_runtime_is_enabled(const struct device *dev); #else +static inline int pm_device_runtime_auto_enable(const struct device *dev) +{ + ARG_UNUSED(dev); + return 0; +} + static inline int pm_device_runtime_enable(const struct device *dev) { ARG_UNUSED(dev); diff --git a/kernel/init.c b/kernel/init.c index 950fc294692..06f7455ec47 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -34,6 +34,7 @@ #include #include #include +#include LOG_MODULE_REGISTER(os, CONFIG_KERNEL_LOG_LEVEL); /* the only struct z_kernel instance */ @@ -261,6 +262,10 @@ static void z_sys_init_run_level(enum init_level level) dev->state->init_res = rc; } dev->state->initialized = true; + if (rc == 0) { + /* Run automatic device runtime enablement */ + (void)pm_device_runtime_auto_enable(dev); + } } } } diff --git a/subsys/pm/device_runtime.c b/subsys/pm/device_runtime.c index b404ba0c034..5701d507d6f 100644 --- a/subsys/pm/device_runtime.c +++ b/subsys/pm/device_runtime.c @@ -242,6 +242,17 @@ int pm_device_runtime_put_async(const struct device *dev) return ret; } +int pm_device_runtime_auto_enable(const struct device *dev) +{ + struct pm_device *pm = dev->pm; + + /* No action needed if PM_DEVICE_FLAG_RUNTIME_AUTO is not enabled */ + if (!pm || !atomic_test_bit(&pm->flags, PM_DEVICE_FLAG_RUNTIME_AUTO)) { + return 0; + } + return pm_device_runtime_enable(dev); +} + int pm_device_runtime_enable(const struct device *dev) { int ret = 0;