driver: spi: MAX32 add RTIO support plus refactor
Implements the SPIO RTIO API. Refactors internal transcive
fucntios to work with both existing SPI API and RTIO functions.
When SPI_RTIO is enabled the spi_transcieve call translates
the request into an RTIO transaction placed in the queue
that device will execute.
Include the latest refacor changes of RTIO.
Signed-off-by: Dimitrije Lilic <dimitrije.lilic@orioninc.com>
diff --git a/drivers/spi/Kconfig.max32 b/drivers/spi/Kconfig.max32
index 0f9e408..13584e9 100644
--- a/drivers/spi/Kconfig.max32
+++ b/drivers/spi/Kconfig.max32
@@ -23,4 +23,28 @@
help
Enable DMA support for MAX32 MCU SPI driver.
+config SPI_MAX32_RTIO
+ bool "MAX32 SPI RTIO Support"
+ default y if SPI_RTIO
+ depends on !SPI_ASYNC
+ select SPI_MAX32_INTERRUPT
+
+if SPI_MAX32_RTIO
+config SPI_MAX32_RTIO_SQ_SIZE
+ int "Number of available submission queue entries"
+ default 8 # Sensible default that covers most common spi transactions
+ help
+ When RTIO is used with SPI, each driver holds a context with which blocking
+ API calls use to perform SPI transactions. This queue needs to be as deep
+ as the longest set of spi_buf_sets used, where normal SPI operations are
+ used (equal length buffers). It may need to be slightly deeper where the
+ spi buffer sets for transmit/receive are not always matched equally in
+ length as these are transformed into normal transceives.
+
+config SPI_MAX32_RTIO_CQ_SIZE
+ int "Number of available completion queue entries"
+ default 8 # Sensible default that covers most common spi transactions
+
+endif # SPI_MAX32_RTIO
+
endif # SPI_MAX32
diff --git a/drivers/spi/spi_max32.c b/drivers/spi/spi_max32.c
index d0238c2..efa1024 100644
--- a/drivers/spi/spi_max32.c
+++ b/drivers/spi/spi_max32.c
@@ -17,6 +17,10 @@
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
+#include <zephyr/rtio/rtio.h>
+#include <zephyr/sys/__assert.h>
+#include <zephyr/sys/util.h>
+#include <zephyr/drivers/spi/rtio.h>
#include <wrap_max32_spi.h>
@@ -51,12 +55,18 @@
const struct device *dev;
mxc_spi_req_t req;
uint8_t dummy[2];
+
#ifdef CONFIG_SPI_MAX32_DMA
volatile uint8_t dma_stat;
#endif /* CONFIG_SPI_MAX32_DMA */
+
#ifdef CONFIG_SPI_ASYNC
struct k_work async_work;
#endif /* CONFIG_SPI_ASYNC */
+
+#ifdef CONFIG_SPI_RTIO
+ struct spi_rtio *rtio_ctx;
+#endif
};
#ifdef CONFIG_SPI_MAX32_DMA
@@ -234,6 +244,10 @@
const struct max32_spi_config *cfg = dev->config;
struct max32_spi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
+#ifdef CONFIG_SPI_RTIO
+ struct spi_rtio *rtio_ctx = data->rtio_ctx;
+ struct rtio_sqe *sqe = &rtio_ctx->txn_curr->sqe;
+#endif
uint32_t len;
uint8_t dfs_shift;
@@ -242,12 +256,48 @@
dfs_shift = spi_max32_get_dfs_shift(ctx);
len = spi_context_max_continuous_chunk(ctx);
+
+#ifdef CONFIG_SPI_RTIO
+ switch (sqe->op) {
+ case RTIO_OP_RX:
+ len = sqe->rx.buf_len;
+ data->req.rxData = sqe->rx.buf;
+ data->req.rxLen = sqe->rx.buf_len;
+ data->req.txData = NULL;
+ data->req.txLen = len >> dfs_shift;
+ break;
+ case RTIO_OP_TX:
+ len = sqe->tx.buf_len;
+ data->req.rxLen = 0;
+ data->req.rxData = data->dummy;
+ data->req.txData = (uint8_t *)sqe->tx.buf;
+ data->req.txLen = len >> dfs_shift;
+ break;
+ case RTIO_OP_TINY_TX:
+ len = sqe->tiny_tx.buf_len;
+ data->req.txData = (uint8_t *)sqe->tiny_tx.buf;
+ data->req.rxData = data->dummy;
+ data->req.txLen = len >> dfs_shift;
+ data->req.rxLen = 0;
+ break;
+ case RTIO_OP_TXRX:
+ len = sqe->txrx.buf_len;
+ data->req.txData = (uint8_t *)sqe->txrx.tx_buf;
+ data->req.rxData = sqe->txrx.rx_buf;
+ data->req.txLen = len >> dfs_shift;
+ data->req.rxLen = len >> dfs_shift;
+ break;
+ default:
+ break;
+ }
+#else
data->req.txLen = len >> dfs_shift;
data->req.txData = (uint8_t *)ctx->tx_buf;
data->req.rxLen = len >> dfs_shift;
data->req.rxData = ctx->rx_buf;
data->req.rxData = ctx->rx_buf;
+
data->req.rxLen = len >> dfs_shift;
if (!data->req.rxData) {
/* Pass a dummy buffer to HAL if receive buffer is NULL, otherwise
@@ -256,6 +306,7 @@
data->req.rxData = data->dummy;
data->req.rxLen = 0;
}
+#endif
data->req.spi = cfg->regs;
data->req.ssIdx = ctx->config->slave;
data->req.ssDeassert = 0;
@@ -296,10 +347,12 @@
bool async, spi_callback_t cb, void *userdata)
{
int ret = 0;
- const struct max32_spi_config *cfg = dev->config;
struct max32_spi_data *data = dev->data;
struct spi_context *ctx = &data->ctx;
+#ifndef CONFIG_SPI_RTIO
+ const struct max32_spi_config *cfg = dev->config;
bool hw_cs_ctrl = true;
+#endif
#ifndef CONFIG_SPI_MAX32_INTERRUPT
if (async) {
@@ -309,6 +362,7 @@
spi_context_lock(ctx, async, cb, userdata, config);
+#ifndef CONFIG_SPI_RTIO
ret = spi_configure(dev, config);
if (ret != 0) {
spi_context_release(ctx, ret);
@@ -363,9 +417,12 @@
cfg->regs->ctrl0 |= MXC_F_SPI_CTRL0_EN;
}
}
+#else
+ struct spi_rtio *rtio_ctx = data->rtio_ctx;
+ ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs);
+#endif
spi_context_release(ctx, ret);
-
return ret;
}
@@ -565,6 +622,99 @@
}
#endif /* CONFIG_SPI_MAX32_DMA */
+#ifdef CONFIG_SPI_RTIO
+static void spi_max32_iodev_complete(const struct device *dev, int status);
+
+static void spi_max32_iodev_start(const struct device *dev)
+{
+ struct max32_spi_data *data = dev->data;
+ struct spi_rtio *rtio_ctx = data->rtio_ctx;
+ struct rtio_sqe *sqe = &rtio_ctx->txn_curr->sqe;
+ int ret = 0;
+
+ switch (sqe->op) {
+ case RTIO_OP_RX:
+ case RTIO_OP_TX:
+ case RTIO_OP_TINY_TX:
+ case RTIO_OP_TXRX:
+ ret = spi_max32_transceive(dev);
+ break;
+ default:
+ spi_max32_iodev_complete(dev, -EINVAL);
+ break;
+ }
+ if (ret != 0) {
+ spi_max32_iodev_complete(dev, -EIO);
+ }
+}
+
+static inline void spi_max32_iodev_prepare_start(const struct device *dev)
+{
+ struct max32_spi_data *data = dev->data;
+ struct spi_rtio *rtio_ctx = data->rtio_ctx;
+ struct spi_dt_spec *spi_dt_spec = rtio_ctx->txn_curr->sqe.iodev->data;
+ struct spi_config *spi_config = &spi_dt_spec->config;
+ struct max32_spi_config *cfg = (struct max32_spi_config *)dev->config;
+ int ret;
+ bool hw_cs_ctrl = true;
+
+ ret = spi_configure(dev, spi_config);
+ __ASSERT(!ret, "%d", ret);
+
+ /* Check if CS GPIO exists */
+ if (spi_cs_is_gpio(spi_config)) {
+ hw_cs_ctrl = false;
+ }
+ MXC_SPI_HWSSControl(cfg->regs, hw_cs_ctrl);
+
+ /* Assert the CS line if HW control disabled */
+ if (!hw_cs_ctrl) {
+ spi_context_cs_control(&data->ctx, true);
+ } else {
+ cfg->regs->ctrl0 = (cfg->regs->ctrl0 & ~MXC_F_SPI_CTRL0_START) |
+ MXC_F_SPI_CTRL0_SS_CTRL;
+ };
+}
+
+static void spi_max32_iodev_complete(const struct device *dev, int status)
+{
+ struct max32_spi_data *data = dev->data;
+ struct spi_rtio *rtio_ctx = data->rtio_ctx;
+
+ if (!status && rtio_ctx->txn_curr->sqe.flags & RTIO_SQE_TRANSACTION) {
+ rtio_ctx->txn_curr = rtio_txn_next(rtio_ctx->txn_curr);
+ spi_max32_iodev_start(dev);
+ } else {
+ struct max32_spi_config *cfg = (struct max32_spi_config *)dev->config;
+ bool hw_cs_ctrl = true;
+
+ if (!hw_cs_ctrl) {
+ spi_context_cs_control(&data->ctx, false);
+ } else {
+ cfg->regs->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | MXC_F_SPI_CTRL0_SS_CTRL |
+ MXC_F_SPI_CTRL0_EN);
+ cfg->regs->ctrl0 |= MXC_F_SPI_CTRL0_EN;
+ }
+
+ if (spi_rtio_complete(rtio_ctx, status)) {
+ spi_max32_iodev_prepare_start(dev);
+ spi_max32_iodev_start(dev);
+ }
+ }
+}
+
+static void api_iodev_submit(const struct device *dev, struct rtio_iodev_sqe *iodev_sqe)
+{
+ struct max32_spi_data *data = dev->data;
+ struct spi_rtio *rtio_ctx = data->rtio_ctx;
+
+ if (spi_rtio_submit(rtio_ctx, iodev_sqe)) {
+ spi_max32_iodev_prepare_start(dev);
+ spi_max32_iodev_start(dev);
+ }
+}
+#endif
+
static int api_transceive(const struct device *dev, const struct spi_config *config,
const struct spi_buf_set *tx_bufs, const struct spi_buf_set *rx_bufs)
{
@@ -596,6 +746,13 @@
const struct device *dev = data->dev;
uint32_t len;
+#ifdef CONFIG_SPI_RTIO
+ struct spi_rtio *rtio_ctx = data->rtio_ctx;
+
+ if (rtio_ctx->txn_head != NULL) {
+ spi_max32_iodev_complete(data->dev, 0);
+ }
+#endif
len = spi_context_max_continuous_chunk(ctx);
spi_context_update_tx(ctx, 1, len);
spi_context_update_rx(ctx, 1, len);
@@ -685,12 +842,12 @@
{
struct max32_spi_data *data = dev->data;
+#ifndef CONFIG_SPI_RTIO
if (!spi_context_configured(&data->ctx, config)) {
return -EINVAL;
}
-
+#endif
spi_context_unlock_unconditionally(&data->ctx);
-
return 0;
}
@@ -724,6 +881,10 @@
data->dev = dev;
+#ifdef CONFIG_SPI_RTIO
+ spi_rtio_init(data->rtio_ctx, dev);
+#endif
+
#ifdef CONFIG_SPI_MAX32_INTERRUPT
cfg->irq_config_func(dev);
#ifdef CONFIG_SPI_ASYNC
@@ -743,8 +904,8 @@
.transceive_async = api_transceive_async,
#endif /* CONFIG_SPI_ASYNC */
#ifdef CONFIG_SPI_RTIO
- .iodev_submit = spi_rtio_iodev_default_submit,
-#endif
+ .iodev_submit = api_iodev_submit,
+#endif /* CONFIG_SPI_RTIO */
.release = api_release,
};
@@ -784,9 +945,14 @@
#define MAX32_SPI_DMA_INIT(n)
#endif
+#define DEFINE_SPI_MAX32_RTIO(_num) SPI_RTIO_DEFINE(max32_spi_rtio_##_num, \
+ CONFIG_SPI_MAX32_RTIO_SQ_SIZE, \
+ CONFIG_SPI_MAX32_RTIO_CQ_SIZE)
+
#define DEFINE_SPI_MAX32(_num) \
PINCTRL_DT_INST_DEFINE(_num); \
SPI_MAX32_IRQ_CONFIG_FUNC(_num) \
+ COND_CODE_1(CONFIG_SPI_RTIO, (DEFINE_SPI_MAX32_RTIO(_num)), ()); \
static const struct max32_spi_config max32_spi_config_##_num = { \
.regs = (mxc_spi_regs_t *)DT_INST_REG_ADDR(_num), \
.pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(_num), \
@@ -797,7 +963,8 @@
static struct max32_spi_data max32_spi_data_##_num = { \
SPI_CONTEXT_INIT_LOCK(max32_spi_data_##_num, ctx), \
SPI_CONTEXT_INIT_SYNC(max32_spi_data_##_num, ctx), \
- SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(_num), ctx)}; \
+ SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(_num), ctx) \
+ IF_ENABLED(CONFIG_SPI_RTIO, (.rtio_ctx = &max32_spi_rtio_##_num))}; \
DEVICE_DT_INST_DEFINE(_num, spi_max32_init, NULL, &max32_spi_data_##_num, \
&max32_spi_config_##_num, PRE_KERNEL_2, CONFIG_SPI_INIT_PRIORITY, \
&spi_max32_api);