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>
This commit is contained in:
parent
e78811bcd6
commit
15ec1f2016
2 changed files with 198 additions and 7 deletions
|
|
@ -23,4 +23,28 @@ config SPI_MAX32_DMA
|
|||
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
|
||||
|
|
|
|||
|
|
@ -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 @@ struct max32_spi_data {
|
|||
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 @@ static int spi_max32_transceive(const struct device *dev)
|
|||
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 @@ static int spi_max32_transceive(const struct device *dev)
|
|||
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 @@ static int spi_max32_transceive(const struct device *dev)
|
|||
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 @@ static int transceive(const struct device *dev, const struct spi_config *config,
|
|||
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 @@ static int transceive(const struct device *dev, const struct spi_config *config,
|
|||
|
||||
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 @@ static int transceive(const struct device *dev, const struct spi_config *config,
|
|||
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 @@ unlock:
|
|||
}
|
||||
#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 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
|
|||
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 @@ static int api_release(const struct device *dev, const struct spi_config *config
|
|||
{
|
||||
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 @@ static int spi_max32_init(const struct device *dev)
|
|||
|
||||
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 @@ static const struct spi_driver_api spi_max32_api = {
|
|||
.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 @@ static const struct spi_driver_api spi_max32_api = {
|
|||
#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 const struct spi_driver_api spi_max32_api = {
|
|||
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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue