From 8c0863dae22e529ab1cc23b5357f70a64089a91b Mon Sep 17 00:00:00 2001 From: Julien Panis Date: Tue, 15 Oct 2024 11:44:40 +0200 Subject: [PATCH] drivers: adc: cc23x0: Add power management Add PM support to cc23x0 ADC module. Signed-off-by: Julien Panis --- drivers/adc/adc_cc23x0.c | 83 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/adc/adc_cc23x0.c b/drivers/adc/adc_cc23x0.c index 4c02ff43a83f..d412f6d9d312 100644 --- a/drivers/adc/adc_cc23x0.c +++ b/drivers/adc/adc_cc23x0.c @@ -14,6 +14,9 @@ LOG_MODULE_REGISTER(adc_cc23x0, CONFIG_ADC_LOG_LEVEL); #include #include #include +#include +#include +#include #include #include @@ -72,8 +75,27 @@ struct adc_cc23x0_data { uint8_t ch_count; uint8_t mem_index; uint16_t *buffer; +#ifdef CONFIG_PM_DEVICE + bool configured; +#endif }; +static inline void adc_cc23x0_pm_policy_state_lock_get(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_get(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); + pm_policy_state_lock_get(PM_STATE_STANDBY, PM_ALL_SUBSTATES); +#endif +} + +static inline void adc_cc23x0_pm_policy_state_lock_put(void) +{ +#ifdef CONFIG_PM_DEVICE + pm_policy_state_lock_put(PM_STATE_STANDBY, PM_ALL_SUBSTATES); + pm_policy_state_lock_put(PM_STATE_RUNTIME_IDLE, PM_ALL_SUBSTATES); +#endif +} + static void adc_context_start_sampling(struct adc_context *ctx) { struct adc_cc23x0_data *data = CONTAINER_OF(ctx, struct adc_cc23x0_data, ctx); @@ -102,6 +124,12 @@ static void adc_context_start_sampling(struct adc_context *ctx) int ret; + ret = pm_device_runtime_get(cfg->dma_dev); + if (ret) { + LOG_ERR("Failed to resume DMA (%d)", ret); + return; + } + ret = dma_config(cfg->dma_dev, cfg->dma_channel, &dma_cfg); if (ret) { LOG_ERR("Failed to configure DMA (%d)", ret); @@ -115,6 +143,8 @@ static void adc_context_start_sampling(struct adc_context *ctx) data->mem_index = 0; #endif + adc_cc23x0_pm_policy_state_lock_get(); + ADCManualTrigger(); } @@ -136,6 +166,9 @@ static void adc_cc23x0_isr(const struct device *dev) #endif #ifdef CONFIG_ADC_CC23X0_DMA_DRIVEN + const struct adc_cc23x0_config *cfg = dev->config; + int ret; + /* * In DMA mode, do not compensate for the ADC internal gain with * ADCAdjustValueForGain() function. To perform this compensation, @@ -144,6 +177,14 @@ static void adc_cc23x0_isr(const struct device *dev) */ ADCClearInterrupt(ADC_INT_DMADONE); LOG_DBG("DMA done"); + + ret = pm_device_runtime_put(cfg->dma_dev); + if (ret) { + LOG_ERR("Failed to suspend DMA (%d)", ret); + return; + } + + adc_cc23x0_pm_policy_state_lock_put(); adc_context_on_sampling_done(&data->ctx, dev); #else /* @@ -174,6 +215,7 @@ static void adc_cc23x0_isr(const struct device *dev) /* Trigger next conversion */ ADCManualTrigger(); } else { + adc_cc23x0_pm_policy_state_lock_put(); adc_context_on_sampling_done(&data->ctx, dev); } #endif @@ -462,6 +504,10 @@ static int adc_cc23x0_channel_setup(const struct device *dev, return -EINVAL; } +#ifdef CONFIG_PM_DEVICE + data->configured = true; +#endif + return 0; } @@ -490,6 +536,12 @@ static int adc_cc23x0_init(const struct device *dev) if (!device_is_ready(cfg->dma_dev)) { return -ENODEV; } + + ret = pm_device_runtime_enable(cfg->dma_dev); + if (ret) { + LOG_ERR("Failed to enable DMA runtime PM"); + return ret; + } #endif adc_context_unlock_unconditionally(&data->ctx); @@ -497,6 +549,34 @@ static int adc_cc23x0_init(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE + +static int adc_cc23x0_pm_action(const struct device *dev, enum pm_device_action action) +{ + struct adc_cc23x0_data *data = dev->data; + + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + CLKCTLDisable(CLKCTL_BASE, CLKCTL_ADC0); + return 0; + case PM_DEVICE_ACTION_RESUME: + CLKCTLEnable(CLKCTL_BASE, CLKCTL_ADC0); + ADCEnableInterrupt(ADC_CC23X0_INT_MASK); + + /* Restore context if needed */ + if (data->configured) { + ADCSetSampleDuration(adc_cc23x0_clkdiv_to_field(data->clk_div), + data->clk_cycles); + } + + return 0; + default: + return -ENOTSUP; + } +} + +#endif /* CONFIG_PM_DEVICE */ + static DEVICE_API(adc, adc_cc23x0_driver_api) = { .channel_setup = adc_cc23x0_channel_setup, .read = adc_cc23x0_read, @@ -517,6 +597,7 @@ static DEVICE_API(adc, adc_cc23x0_driver_api) = { #define CC23X0_ADC_INIT(n) \ PINCTRL_DT_INST_DEFINE(n); \ + PM_DEVICE_DT_INST_DEFINE(n, adc_cc23x0_pm_action); \ \ static void adc_cc23x0_cfg_func_##n(void) \ { \ @@ -542,7 +623,7 @@ static DEVICE_API(adc, adc_cc23x0_driver_api) = { \ DEVICE_DT_INST_DEFINE(n, \ &adc_cc23x0_init, \ - NULL, \ + PM_DEVICE_DT_INST_GET(n), \ &adc_cc23x0_data_##n, \ &adc_cc23x0_config_##n, \ POST_KERNEL, \