From 31c50439d897f61f909380b567aca879984627d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Chru=C5=9Bci=C5=84ski?= Date: Fri, 20 Sep 2024 13:17:19 +0200 Subject: [PATCH] drivers: pwm: nrfx: Improve runtime PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rework PM handling to use pm_device_driver_init(). Shim is not using put and get internally as there is no api that disables or stops pwm so it is hard to determine when to put the device. There are cases when PWM peripheral is stopped but PWM is still active because duty cycle is 100% or 0% and pin is driven by GPIO and not PWM. If user want to use runtime PM with PWM it is possible and getting the device will initialize internal data and putting will suspend by forcing PWM stop if used and setting pins to sleep state. However, from power consumption perspective it is enough to set 0% or 100% duty cycle on all channels. Signed-off-by: Krzysztof Chruściński --- drivers/pwm/pwm_nrfx.c | 76 +++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/drivers/pwm/pwm_nrfx.c b/drivers/pwm/pwm_nrfx.c index 321cdf3b8734f19..528e8e5440c5a93 100644 --- a/drivers/pwm/pwm_nrfx.c +++ b/drivers/pwm/pwm_nrfx.c @@ -262,16 +262,13 @@ static const struct pwm_driver_api pwm_nrfx_drv_api_funcs = { .get_cycles_per_sec = pwm_nrfx_get_cycles_per_sec, }; -static int pwm_nrfx_init(const struct device *dev) +static int pwm_resume(const struct device *dev) { const struct pwm_nrfx_config *config = dev->config; uint8_t initially_inverted = 0; - nrfx_err_t result; int ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - ANOMALY_109_EGU_IRQ_CONNECT(NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE); - if (ret < 0) { return ret; } @@ -295,60 +292,69 @@ static int pwm_nrfx_init(const struct device *dev) seq_values_ptr_get(dev)[i] = PWM_NRFX_CH_VALUE(0, inverted); } - result = nrfx_pwm_init(&config->pwm, &config->initial_config, pwm_handler, dev->data); - if (result != NRFX_SUCCESS) { - LOG_ERR("Failed to initialize device: %s", dev->name); - return -EBUSY; - } - return 0; } -#ifdef CONFIG_PM_DEVICE -static void pwm_nrfx_uninit(const struct device *dev) +static int pwm_suspend(const struct device *dev, bool do_pinctrl) { const struct pwm_nrfx_config *config = dev->config; + struct pwm_nrfx_data *data = dev->data; - nrfx_pwm_uninit(&config->pwm); + if (data->active) { + /* PWM is still in use. Force stopping. */ + data->stop_requested = true; + nrfx_pwm_stop(&config->pwm, false); + while (data->stop_requested) { + } + } memset(dev->data, 0, sizeof(struct pwm_nrfx_data)); + + if (IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME)) { + return pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); + } + + return 0; } static int pwm_nrfx_pm_action(const struct device *dev, enum pm_device_action action) { - const struct pwm_nrfx_config *config = dev->config; - int ret = 0; + int ret = -ENOTSUP; switch (action) { - case PM_DEVICE_ACTION_RESUME: - ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - return ret; - } - ret = pwm_nrfx_init(dev); - break; - case PM_DEVICE_ACTION_SUSPEND: - pwm_nrfx_uninit(dev); - - ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_SLEEP); - if (ret < 0) { - return ret; - } + ret = pwm_suspend(dev, true); + break; + case PM_DEVICE_ACTION_RESUME: + ret = pwm_resume(dev); break; - default: - return -ENOTSUP; + break; } return ret; } -#else -#define pwm_nrfx_pm_action NULL +static int pwm_nrfx_init(const struct device *dev) +{ + const struct pwm_nrfx_config *config = dev->config; + nrfx_err_t err; + int ret; + + err = nrfx_pwm_init(&config->pwm, &config->initial_config, pwm_handler, dev->data); + if (err != NRFX_SUCCESS) { + LOG_ERR("Failed to initialize device: %s", dev->name); + return -EBUSY; + } -#endif /* CONFIG_PM_DEVICE */ + ret = pwm_suspend(dev); + if (ret != 0) { + return ret; + } + + return pm_device_driver_init(dev, pwm_nrfx_pm_action); +} #define PWM(dev_idx) DT_NODELABEL(pwm##dev_idx) #define PWM_PROP(dev_idx, prop) DT_PROP(PWM(dev_idx), prop) @@ -387,6 +393,8 @@ static int pwm_nrfx_pm_action(const struct device *dev, { \ IRQ_CONNECT(DT_IRQN(PWM(idx)), DT_IRQ(PWM(idx), priority), \ nrfx_isr, nrfx_pwm_##idx##_irq_handler, 0); \ + ANOMALY_109_EGU_IRQ_CONNECT( \ + NRFX_PWM_NRF52_ANOMALY_109_EGU_INSTANCE); \ return pwm_nrfx_init(dev); \ }; \ PM_DEVICE_DT_DEFINE(PWM(idx), pwm_nrfx_pm_action); \