Skip to content

drivers: spi: cc23x0: Add power management #92223

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
75 changes: 69 additions & 6 deletions drivers/spi/spi_cc23x0.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ LOG_MODULE_REGISTER(spi_cc23x0, CONFIG_SPI_LOG_LEVEL);
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/spi.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/clkctl.h>
Expand Down Expand Up @@ -63,6 +66,22 @@ struct spi_cc23x0_data {
#endif
};

static inline void spi_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 spi_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 spi_cc23x0_isr(const struct device *dev)
{
const struct spi_cc23x0_config *cfg = dev->config;
Expand Down Expand Up @@ -307,6 +326,8 @@ static int spi_cc23x0_transceive(const struct device *dev,
};
#endif

spi_cc23x0_pm_policy_state_lock_get();

spi_context_lock(ctx, false, NULL, NULL, config);

ret = spi_cc23x0_configure(dev, config);
Expand Down Expand Up @@ -339,16 +360,22 @@ static int spi_cc23x0_transceive(const struct device *dev,
block_cfg_rx.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
block_cfg_rx.block_size = SPI_CC23_DFS * data->tx_len_left;

ret = dma_config(cfg->dma_dev, cfg->dma_channel_tx, &dma_cfg_tx);
ret = pm_device_runtime_get(cfg->dma_dev);
if (ret) {
LOG_ERR("Failed to configure DMA TX channel");
LOG_ERR("Failed to resume DMA (%d)", ret);
goto int_disable;
}

ret = dma_config(cfg->dma_dev, cfg->dma_channel_tx, &dma_cfg_tx);
if (ret) {
LOG_ERR("Failed to configure DMA TX channel (%d)", ret);
goto dma_suspend;
}

ret = dma_config(cfg->dma_dev, cfg->dma_channel_rx, &dma_cfg_rx);
if (ret) {
LOG_ERR("Failed to configure DMA RX channel");
goto int_disable;
LOG_ERR("Failed to configure DMA RX channel (%d)", ret);
goto dma_suspend;
}

/* Disable DMA triggers */
Expand All @@ -364,14 +391,19 @@ static int spi_cc23x0_transceive(const struct device *dev,
ret = spi_context_wait_for_completion(&data->ctx);
if (ret) {
LOG_ERR("SPI transfer failed (%d)", ret);
goto int_disable;
goto dma_suspend;
}

spi_context_update_tx(ctx, SPI_CC23_DFS, data->tx_len_left);
spi_context_update_rx(ctx, SPI_CC23_DFS, data->tx_len_left);

LOG_DBG("SPI transfer completed");

dma_suspend:
ret = pm_device_runtime_put(cfg->dma_dev);
if (ret) {
LOG_ERR("Failed to suspend DMA (%d)", ret);
}
int_disable:
SPIDisableInt(cfg->base, SPI_CC23_INT_MASK);
#else
Expand All @@ -388,6 +420,7 @@ static int spi_cc23x0_transceive(const struct device *dev,

ctx_release:
spi_context_release(ctx, ret);
spi_cc23x0_pm_policy_state_lock_put();
return ret;
}

Expand Down Expand Up @@ -434,6 +467,12 @@ static int spi_cc23x0_init(const struct device *dev)
LOG_ERR("DMA not ready");
return -ENODEV;
}

ret = pm_device_runtime_enable(cfg->dma_dev);
if (ret) {
LOG_ERR("Failed to enable DMA runtime PM");
return ret;
}
#endif

ret = spi_context_cs_configure_all(&data->ctx);
Expand All @@ -446,6 +485,29 @@ static int spi_cc23x0_init(const struct device *dev)
return 0;
}

#ifdef CONFIG_PM_DEVICE

static int spi_cc23x0_pm_action(const struct device *dev, enum pm_device_action action)
{
const struct spi_cc23x0_config *cfg = dev->config;
struct spi_cc23x0_data *data = dev->data;

switch (action) {
case PM_DEVICE_ACTION_SUSPEND:
SPIDisable(cfg->base);
CLKCTLDisable(CLKCTL_BASE, CLKCTL_SPI0);
return 0;
case PM_DEVICE_ACTION_RESUME:
/* Force SPI to be reconfigured at next transfer */
data->ctx.config = NULL;
return 0;
default:
return -ENOTSUP;
}
}

#endif /* CONFIG_PM_DEVICE */

#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
#define SPI_CC23X0_DMA_INIT(n) \
.dma_dev = DEVICE_DT_GET(TI_CC23X0_DT_INST_DMA_CTLR(n, tx)), \
Expand All @@ -459,6 +521,7 @@ static int spi_cc23x0_init(const struct device *dev)

#define SPI_CC23X0_INIT(n) \
PINCTRL_DT_INST_DEFINE(n); \
PM_DEVICE_DT_INST_DEFINE(n, spi_cc23x0_pm_action); \
\
static void spi_irq_config_func_##n(void) \
{ \
Expand All @@ -484,7 +547,7 @@ static int spi_cc23x0_init(const struct device *dev)
\
DEVICE_DT_INST_DEFINE(n, \
spi_cc23x0_init, \
NULL, \
PM_DEVICE_DT_INST_GET(n), \
&spi_cc23x0_data_##n, \
&spi_cc23x0_config_##n, \
POST_KERNEL, \
Expand Down