From 4279eb679146bc6ef454c5de49a4c1b336eeca24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Stasiak?= Date: Thu, 12 Dec 2024 12:04:44 +0100 Subject: [PATCH] drivers: pwm: nrfx: add global hsfll request for fast PWM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added clock control api for global hsfll used in fast PWM120 driver. Signed-off-by: MichaƂ Stasiak --- drivers/pwm/Kconfig.nrfx | 5 +++ drivers/pwm/pwm_nrfx.c | 96 +++++++++++++++++++++++++++++++++++----- 2 files changed, 91 insertions(+), 10 deletions(-) diff --git a/drivers/pwm/Kconfig.nrfx b/drivers/pwm/Kconfig.nrfx index 933fe7cb29c3f26..1e2e122c1b42b79 100644 --- a/drivers/pwm/Kconfig.nrfx +++ b/drivers/pwm/Kconfig.nrfx @@ -20,3 +20,8 @@ config PWM_NRFX select PINCTRL help Enable support for nrfx Hardware PWM driver for nRF52 MCU series. + +config PWM_NRFX_INIT_PRIORITY + int + default 99 if HAS_HW_NRF_PWM120 + default PWM_INIT_PRIORITY diff --git a/drivers/pwm/pwm_nrfx.c b/drivers/pwm/pwm_nrfx.c index 41b43cda3391bbc..0f3d35a19830706 100644 --- a/drivers/pwm/pwm_nrfx.c +++ b/drivers/pwm/pwm_nrfx.c @@ -13,6 +13,9 @@ #include #include #include +#ifdef CONFIG_CLOCK_CONTROL +#include +#endif #ifdef CONFIG_SOC_NRF54H20_GPD #include #endif @@ -35,6 +38,20 @@ LOG_MODULE_REGISTER(pwm_nrfx, CONFIG_PWM_LOG_LEVEL); #define ANOMALY_109_EGU_IRQ_CONNECT(idx) #endif +#define PWM(dev_idx) DT_NODELABEL(pwm##dev_idx) +#define PWM_PROP(dev_idx, prop) DT_PROP(PWM(dev_idx), prop) +#define PWM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(PWM(idx), prop) + +#define PWM_NRFX_IS_FAST(unused, prefix, idx, _) \ + COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(PWM(idx)), \ + (COND_CODE_1(PWM_HAS_PROP(idx, power_domains), \ + (IS_EQ(DT_PHA(PWM(idx), power_domains, id), NRF_GPD_FAST_ACTIVE1)), \ + (0))), (0)) + +#if (NRFX_FOREACH_PRESENT(PWM, PWM_NRFX_IS_FAST, (||), (0))) && CONFIG_CLOCK_CONTROL +#define PWM_NRFX_USE_CLOCK_CONTROL 1 +#endif + #define PWM_NRFX_CH_POLARITY_MASK BIT(15) #define PWM_NRFX_CH_COMPARE_MASK BIT_MASK(15) #define PWM_NRFX_CH_VALUE(compare_value, inverted) \ @@ -49,6 +66,10 @@ struct pwm_nrfx_config { #ifdef CONFIG_DCACHE uint32_t mem_attr; #endif +#ifdef PWM_NRFX_USE_CLOCK_CONTROL + const struct device *clk_dev; + struct nrf_clock_spec clk_spec; +#endif }; struct pwm_nrfx_data { @@ -57,6 +78,9 @@ struct pwm_nrfx_data { uint8_t pwm_needed; uint8_t prescaler; bool stop_requested; +#ifdef PWM_NRFX_USE_CLOCK_CONTROL + bool clock_requested; +#endif }; /* Ensure the pwm_needed bit mask can accommodate all available channels. */ #if (NRF_PWM_CHANNEL_COUNT > 8) @@ -229,6 +253,18 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel, * ensure it is stopped before starting the next playback. */ nrfx_pwm_stop(&config->pwm, false); +#if PWM_NRFX_USE_CLOCK_CONTROL + if (data->clock_requested) { + int ret = nrf_clock_control_release(config->clk_dev, &config->clk_spec); + + if (ret < 0) { + LOG_ERR("Global HSFLL release failed: %d", ret); + return ret; + } + + data->clock_requested = false; + } +#endif data->stop_requested = true; } else { if (data->stop_requested) { @@ -248,6 +284,20 @@ static int pwm_nrfx_set_cycles(const struct device *dev, uint32_t channel, * until another playback is requested (new values will be * loaded then) or the PWM peripheral is stopped. */ +#if PWM_NRFX_USE_CLOCK_CONTROL + if (!data->clock_requested) { + int ret = nrf_clock_control_request_sync(config->clk_dev, + &config->clk_spec, + K_FOREVER); + + if (ret < 0) { + LOG_ERR("Global HSFLL request failed: %d", ret); + return ret; + } + + data->clock_requested = true; + } +#endif nrfx_pwm_simple_playback(&config->pwm, &config->seq, 1, NRFX_PWM_FLAG_NO_EVT_FINISHED); } @@ -270,7 +320,7 @@ static DEVICE_API(pwm, pwm_nrfx_drv_api_funcs) = { .get_cycles_per_sec = pwm_nrfx_get_cycles_per_sec, }; -static void pwm_resume(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; @@ -299,13 +349,29 @@ static void pwm_resume(const struct device *dev) seq_values_ptr_get(dev)[i] = PWM_NRFX_CH_VALUE(0, inverted); } + + return 0; } -static void pwm_suspend(const struct device *dev) +static int pwm_suspend(const struct device *dev) { const struct pwm_nrfx_config *config = dev->config; nrfx_pwm_stop(&config->pwm, false); +#if PWM_NRFX_USE_CLOCK_CONTROL + struct pwm_nrfx_data *data = dev->data; + + if (data->clock_requested) { + int ret = nrf_clock_control_release(config->clk_dev, &config->clk_spec); + + if (ret < 0) { + LOG_ERR("Global HSFLL release failed: %d", ret); + return ret; + } + + data->clock_requested = false; + } +#endif while (!nrfx_pwm_stopped_check(&config->pwm)) { } @@ -315,20 +381,24 @@ static void pwm_suspend(const struct device *dev) memset(dev->data, 0, sizeof(struct pwm_nrfx_data)); (void)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) { + int ret = 0; + if (action == PM_DEVICE_ACTION_RESUME) { - pwm_resume(dev); + ret = pwm_resume(dev); } else if (IS_ENABLED(CONFIG_PM_DEVICE) && (action == PM_DEVICE_ACTION_SUSPEND)) { - pwm_suspend(dev); + ret = pwm_suspend(dev); } else { - return -ENOTSUP; + ret = -ENOTSUP; } - return 0; + return ret; } static int pwm_nrfx_init(const struct device *dev) @@ -351,9 +421,6 @@ static int pwm_nrfx_init(const struct device *dev) 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) -#define PWM_HAS_PROP(idx, prop) DT_NODE_HAS_PROP(PWM(idx), prop) #define PWM_MEM_REGION(idx) DT_PHANDLE(PWM(idx), memory_regions) #define PWM_MEMORY_SECTION(idx) \ @@ -393,6 +460,15 @@ static int pwm_nrfx_init(const struct device *dev) (16ul * 1000ul * 1000ul)), \ IF_ENABLED(CONFIG_DCACHE, \ (.mem_attr = PWM_GET_MEM_ATTR(idx),)) \ + IF_ENABLED(PWM_NRFX_USE_CLOCK_CONTROL, \ + (.clk_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(PWM(idx))), \ + .clk_spec = { \ + .frequency = \ + NRF_PERIPH_GET_FREQUENCY(PWM(idx)), \ + .accuracy = 0, \ + .precision = \ + NRF_CLOCK_CONTROL_PRECISION_DEFAULT, \ + },)) \ }; \ static int pwm_nrfx_init##idx(const struct device *dev) \ { \ @@ -405,7 +481,7 @@ static int pwm_nrfx_init(const struct device *dev) pwm_nrfx_init##idx, PM_DEVICE_DT_GET(PWM(idx)), \ &pwm_nrfx_##idx##_data, \ &pwm_nrfx_##idx##_config, \ - POST_KERNEL, CONFIG_PWM_INIT_PRIORITY, \ + POST_KERNEL, CONFIG_PWM_NRFX_INIT_PRIORITY, \ &pwm_nrfx_drv_api_funcs) #define COND_PWM_NRFX_DEVICE(unused, prefix, i, _) \