Skip to content

drivers: adc: cc23x0: Add power management #92222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 82 additions & 1 deletion drivers/adc/adc_cc23x0.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ LOG_MODULE_REGISTER(adc_cc23x0, CONFIG_ADC_LOG_LEVEL);
#include <zephyr/drivers/dma.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/irq.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/pm/policy.h>
#include <zephyr/sys/util.h>

#include <driverlib/adc.h>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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();
}

Expand All @@ -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,
Expand All @@ -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
/*
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -490,13 +536,47 @@ 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);

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,
Expand All @@ -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) \
{ \
Expand All @@ -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, \
Expand Down