Skip to content

Commit 1fdaec3

Browse files
committed
drivers: spi: cc23x0: Add support for DMA mode
Two DMA channels are assigned to TX and RX respectively: - A TX DMA single request is asserted when there is space in the FIFO. - A RX DMA single request is asserted when data is in the FIFO. Signed-off-by: Julien Panis <jpanis@baylibre.com>
1 parent 179045e commit 1fdaec3

File tree

3 files changed

+166
-2
lines changed

3 files changed

+166
-2
lines changed

drivers/spi/Kconfig.cc23x0

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ config SPI_CC23X0
1010
select PINCTRL
1111
help
1212
Enable support for the TI SimpleLink CC23x0 SPI peripheral
13+
14+
config SPI_CC23X0_DMA_DRIVEN
15+
bool "DMA support for TI CC23X0 SPI devices"
16+
depends on SPI_CC23X0
17+
select DMA
18+
help
19+
DMA driven transactions for the SPI.
20+
DMA driven mode offloads data transfer tasks from the CPU
21+
and requires fewer interrupts to handle the SPI transfers.

drivers/spi/spi_cc23x0.c

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
LOG_MODULE_REGISTER(spi_cc23x0, CONFIG_SPI_LOG_LEVEL);
1111

1212
#include <zephyr/device.h>
13+
#include <zephyr/drivers/dma.h>
1314
#include <zephyr/drivers/pinctrl.h>
1415
#include <zephyr/drivers/spi.h>
1516
#include <zephyr/irq.h>
@@ -18,6 +19,8 @@ LOG_MODULE_REGISTER(spi_cc23x0, CONFIG_SPI_LOG_LEVEL);
1819
#include <driverlib/clkctl.h>
1920
#include <driverlib/spi.h>
2021

22+
#include <inc/hw_memmap.h>
23+
2124
#include "spi_context.h"
2225

2326
/*
@@ -30,33 +33,55 @@ LOG_MODULE_REGISTER(spi_cc23x0, CONFIG_SPI_LOG_LEVEL);
3033
#define SPI_CC23_DATA_WIDTH 8
3134
#define SPI_CC23_DFS (SPI_CC23_DATA_WIDTH >> 3)
3235

36+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
37+
#define SPI_CC23_REG_GET(base, offset) ((base) + (offset))
38+
#define SPI_CC23_INT_MASK SPI_DMA_DONE_RX
39+
#else
3340
#define SPI_CC23_INT_MASK (SPI_TXEMPTY | SPI_IDLE | SPI_RX)
41+
#endif
3442

3543
struct spi_cc23x0_config {
3644
uint32_t base;
3745
const struct pinctrl_dev_config *pincfg;
3846
void (*irq_config_func)(void);
47+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
48+
const struct device *dma_dev;
49+
uint8_t dma_channel_tx;
50+
uint8_t dma_trigsrc_tx;
51+
uint8_t dma_channel_rx;
52+
uint8_t dma_trigsrc_rx;
53+
#endif
3954
};
4055

4156
struct spi_cc23x0_data {
4257
struct spi_context ctx;
4358
size_t tx_len_left;
59+
#ifndef CONFIG_SPI_CC23X0_DMA_DRIVEN
4460
uint32_t tx_count;
4561
uint32_t rx_count;
4662
bool xfer_done;
63+
#endif
4764
};
4865

4966
static void spi_cc23x0_isr(const struct device *dev)
5067
{
5168
const struct spi_cc23x0_config *cfg = dev->config;
5269
struct spi_cc23x0_data *data = dev->data;
5370
struct spi_context *ctx = &data->ctx;
54-
uint32_t txd = 0, rxd;
5571
uint32_t status;
72+
#ifndef CONFIG_SPI_CC23X0_DMA_DRIVEN
73+
uint32_t txd = 0, rxd;
74+
#endif
5675

5776
status = SPIIntStatus(cfg->base, true);
5877
LOG_DBG("status = %08x", status);
5978

79+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
80+
if (status & SPI_DMA_DONE_RX) {
81+
SPIClearInt(cfg->base, SPI_DMA_DONE_RX);
82+
spi_context_complete(ctx, dev, 0);
83+
}
84+
#else
6085
/*
6186
* Disabling the interrupts in this ISR when SPI has completed
6287
* the transfer triggers a subsequent spurious interrupt, with
@@ -124,6 +149,7 @@ static void spi_cc23x0_isr(const struct device *dev)
124149
SPIDisableInt(cfg->base, SPI_CC23_INT_MASK);
125150
spi_context_complete(ctx, dev, 0);
126151
}
152+
#endif
127153
}
128154

129155
static int spi_cc23x0_configure(const struct device *dev,
@@ -221,9 +247,11 @@ static void spi_cc23x0_initialize_data(struct spi_cc23x0_data *data)
221247
{
222248
data->tx_len_left = MAX(spi_context_total_tx_len(&data->ctx),
223249
spi_context_total_rx_len(&data->ctx));
250+
#ifndef CONFIG_SPI_CC23X0_DMA_DRIVEN
224251
data->tx_count = 0;
225252
data->rx_count = 0;
226253
data->xfer_done = false;
254+
#endif
227255
}
228256

229257
static int spi_cc23x0_transceive(const struct device *dev,
@@ -235,6 +263,43 @@ static int spi_cc23x0_transceive(const struct device *dev,
235263
struct spi_cc23x0_data *data = dev->data;
236264
struct spi_context *ctx = &data->ctx;
237265
int ret;
266+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
267+
struct dma_block_config block_cfg_tx = {
268+
.dest_address = SPI_CC23_REG_GET(cfg->base, SPI_O_TXDATA),
269+
.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE,
270+
.block_size = 1,
271+
};
272+
273+
struct dma_config dma_cfg_tx = {
274+
.dma_slot = cfg->dma_trigsrc_tx,
275+
.channel_direction = MEMORY_TO_PERIPHERAL,
276+
.block_count = 1,
277+
.head_block = &block_cfg_tx,
278+
.source_data_size = SPI_CC23_DFS,
279+
.dest_data_size = SPI_CC23_DFS,
280+
.source_burst_length = SPI_CC23_DFS,
281+
.dma_callback = NULL,
282+
.user_data = NULL,
283+
};
284+
285+
struct dma_block_config block_cfg_rx = {
286+
.source_address = SPI_CC23_REG_GET(cfg->base, SPI_O_RXDATA),
287+
.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE,
288+
.block_size = 1,
289+
};
290+
291+
struct dma_config dma_cfg_rx = {
292+
.dma_slot = cfg->dma_trigsrc_rx,
293+
.channel_direction = PERIPHERAL_TO_MEMORY,
294+
.block_count = 1,
295+
.head_block = &block_cfg_rx,
296+
.source_data_size = SPI_CC23_DFS,
297+
.dest_data_size = SPI_CC23_DFS,
298+
.source_burst_length = SPI_CC23_DFS,
299+
.dma_callback = NULL,
300+
.user_data = NULL,
301+
};
302+
#endif
238303

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

@@ -245,19 +310,73 @@ static int spi_cc23x0_transceive(const struct device *dev,
245310

246311
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, SPI_CC23_DFS);
247312

313+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
314+
if (spi_context_total_tx_len(ctx) != spi_context_total_rx_len(ctx)) {
315+
LOG_ERR("In DMA mode, RX and TX buffer lengths must be the same");
316+
ret = -EINVAL;
317+
goto ctx_release;
318+
}
319+
#endif
320+
248321
spi_cc23x0_initialize_data(data);
249322

250323
spi_context_cs_control(ctx, true);
251324

252325
SPIEnableInt(cfg->base, SPI_CC23_INT_MASK);
253326

327+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
328+
block_cfg_tx.source_address = (uint32_t)ctx->tx_buf;
329+
block_cfg_tx.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
330+
block_cfg_tx.block_size = SPI_CC23_DFS * data->tx_len_left;
331+
332+
block_cfg_rx.dest_address = (uint32_t)ctx->rx_buf;
333+
block_cfg_rx.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
334+
block_cfg_rx.block_size = SPI_CC23_DFS * data->tx_len_left;
335+
336+
ret = dma_config(cfg->dma_dev, cfg->dma_channel_tx, &dma_cfg_tx);
337+
if (ret) {
338+
LOG_ERR("Failed to configure DMA TX channel");
339+
goto int_disable;
340+
}
341+
342+
ret = dma_config(cfg->dma_dev, cfg->dma_channel_rx, &dma_cfg_rx);
343+
if (ret) {
344+
LOG_ERR("Failed to configure DMA RX channel");
345+
goto int_disable;
346+
}
347+
348+
/* Disable DMA triggers */
349+
SPIDisableDMA(cfg->base, SPI_DMA_TX | SPI_DMA_RX);
350+
351+
/* Start DMA channels */
352+
dma_start(cfg->dma_dev, cfg->dma_channel_rx);
353+
dma_start(cfg->dma_dev, cfg->dma_channel_tx);
354+
355+
/* Enable DMA triggers to start transfer */
356+
SPIEnableDMA(cfg->base, SPI_DMA_TX | SPI_DMA_RX);
357+
358+
ret = spi_context_wait_for_completion(&data->ctx);
359+
if (ret) {
360+
LOG_ERR("SPI transfer failed (%d)", ret);
361+
goto int_disable;
362+
}
363+
364+
spi_context_update_tx(ctx, SPI_CC23_DFS, data->tx_len_left);
365+
spi_context_update_rx(ctx, SPI_CC23_DFS, data->tx_len_left);
366+
367+
LOG_DBG("SPI transfer completed");
368+
369+
int_disable:
370+
SPIDisableInt(cfg->base, SPI_CC23_INT_MASK);
371+
#else
254372
ret = spi_context_wait_for_completion(ctx);
255373
if (ret) {
256374
SPIDisableInt(cfg->base, SPI_CC23_INT_MASK);
257375
LOG_ERR("SPI transfer failed (%d)", ret);
258376
} else {
259377
LOG_DBG("SPI transfer completed");
260378
}
379+
#endif
261380

262381
spi_context_cs_control(ctx, false);
263382

@@ -304,6 +423,13 @@ static int spi_cc23x0_init(const struct device *dev)
304423
return ret;
305424
}
306425

426+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
427+
if (!device_is_ready(cfg->dma_dev)) {
428+
LOG_ERR("DMA not ready");
429+
return -ENODEV;
430+
}
431+
#endif
432+
307433
ret = spi_context_cs_configure_all(&data->ctx);
308434
if (ret) {
309435
return ret;
@@ -314,6 +440,17 @@ static int spi_cc23x0_init(const struct device *dev)
314440
return 0;
315441
}
316442

443+
#ifdef CONFIG_SPI_CC23X0_DMA_DRIVEN
444+
#define SPI_CC23X0_DMA_INIT(n) \
445+
.dma_dev = DEVICE_DT_GET(TI_CC23X0_DT_INST_DMA_CTLR(n, tx)), \
446+
.dma_channel_tx = TI_CC23X0_DT_INST_DMA_CHANNEL(n, tx), \
447+
.dma_trigsrc_tx = TI_CC23X0_DT_INST_DMA_TRIGSRC(n, tx), \
448+
.dma_channel_rx = TI_CC23X0_DT_INST_DMA_CHANNEL(n, rx), \
449+
.dma_trigsrc_rx = TI_CC23X0_DT_INST_DMA_TRIGSRC(n, rx),
450+
#else
451+
#define SPI_CC23X0_DMA_INIT(n)
452+
#endif
453+
317454
#define SPI_CC23X0_INIT(n) \
318455
PINCTRL_DT_INST_DEFINE(n); \
319456
\
@@ -329,7 +466,8 @@ static int spi_cc23x0_init(const struct device *dev)
329466
static const struct spi_cc23x0_config spi_cc23x0_config_##n = { \
330467
.base = DT_INST_REG_ADDR(n), \
331468
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
332-
.irq_config_func = spi_irq_config_func_##n \
469+
.irq_config_func = spi_irq_config_func_##n, \
470+
SPI_CC23X0_DMA_INIT(n) \
333471
}; \
334472
\
335473
static struct spi_cc23x0_data spi_cc23x0_data_##n = { \

dts/bindings/spi/ti,cc23x0-spi.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,20 @@ properties:
1919

2020
pinctrl-names:
2121
required: true
22+
23+
dmas:
24+
description: |
25+
Optional TX & RX DMA specifiers. Each specifier will have a phandle
26+
reference to the DMA controller, the channel number, and the peripheral
27+
trigger source.
28+
29+
Example for channels 0/1 with spi0txtrg/spi0rxtrg trigger sources:
30+
dmas = <&dma 0 0>, <&dma 1 1>;
31+
32+
dma-names:
33+
description: |
34+
Required if the dmas property exists. This should be "tx" and "rx"
35+
to match the dmas property.
36+
37+
Example:
38+
dma-names = "tx", "rx";

0 commit comments

Comments
 (0)