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
|
help
|
||||||
Enable DMA support for MAX32 MCU SPI driver.
|
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
|
endif # SPI_MAX32
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@
|
||||||
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
|
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
#include <zephyr/irq.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>
|
#include <wrap_max32_spi.h>
|
||||||
|
|
||||||
|
|
@ -51,12 +55,18 @@ struct max32_spi_data {
|
||||||
const struct device *dev;
|
const struct device *dev;
|
||||||
mxc_spi_req_t req;
|
mxc_spi_req_t req;
|
||||||
uint8_t dummy[2];
|
uint8_t dummy[2];
|
||||||
|
|
||||||
#ifdef CONFIG_SPI_MAX32_DMA
|
#ifdef CONFIG_SPI_MAX32_DMA
|
||||||
volatile uint8_t dma_stat;
|
volatile uint8_t dma_stat;
|
||||||
#endif /* CONFIG_SPI_MAX32_DMA */
|
#endif /* CONFIG_SPI_MAX32_DMA */
|
||||||
|
|
||||||
#ifdef CONFIG_SPI_ASYNC
|
#ifdef CONFIG_SPI_ASYNC
|
||||||
struct k_work async_work;
|
struct k_work async_work;
|
||||||
#endif /* CONFIG_SPI_ASYNC */
|
#endif /* CONFIG_SPI_ASYNC */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_RTIO
|
||||||
|
struct spi_rtio *rtio_ctx;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SPI_MAX32_DMA
|
#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;
|
const struct max32_spi_config *cfg = dev->config;
|
||||||
struct max32_spi_data *data = dev->data;
|
struct max32_spi_data *data = dev->data;
|
||||||
struct spi_context *ctx = &data->ctx;
|
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;
|
uint32_t len;
|
||||||
uint8_t dfs_shift;
|
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);
|
dfs_shift = spi_max32_get_dfs_shift(ctx);
|
||||||
|
|
||||||
len = spi_context_max_continuous_chunk(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.txLen = len >> dfs_shift;
|
||||||
data->req.txData = (uint8_t *)ctx->tx_buf;
|
data->req.txData = (uint8_t *)ctx->tx_buf;
|
||||||
data->req.rxLen = len >> dfs_shift;
|
data->req.rxLen = len >> dfs_shift;
|
||||||
data->req.rxData = ctx->rx_buf;
|
data->req.rxData = ctx->rx_buf;
|
||||||
|
|
||||||
data->req.rxData = ctx->rx_buf;
|
data->req.rxData = ctx->rx_buf;
|
||||||
|
|
||||||
data->req.rxLen = len >> dfs_shift;
|
data->req.rxLen = len >> dfs_shift;
|
||||||
if (!data->req.rxData) {
|
if (!data->req.rxData) {
|
||||||
/* Pass a dummy buffer to HAL if receive buffer is NULL, otherwise
|
/* 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.rxData = data->dummy;
|
||||||
data->req.rxLen = 0;
|
data->req.rxLen = 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
data->req.spi = cfg->regs;
|
data->req.spi = cfg->regs;
|
||||||
data->req.ssIdx = ctx->config->slave;
|
data->req.ssIdx = ctx->config->slave;
|
||||||
data->req.ssDeassert = 0;
|
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)
|
bool async, spi_callback_t cb, void *userdata)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const struct max32_spi_config *cfg = dev->config;
|
|
||||||
struct max32_spi_data *data = dev->data;
|
struct max32_spi_data *data = dev->data;
|
||||||
struct spi_context *ctx = &data->ctx;
|
struct spi_context *ctx = &data->ctx;
|
||||||
|
#ifndef CONFIG_SPI_RTIO
|
||||||
|
const struct max32_spi_config *cfg = dev->config;
|
||||||
bool hw_cs_ctrl = true;
|
bool hw_cs_ctrl = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef CONFIG_SPI_MAX32_INTERRUPT
|
#ifndef CONFIG_SPI_MAX32_INTERRUPT
|
||||||
if (async) {
|
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);
|
spi_context_lock(ctx, async, cb, userdata, config);
|
||||||
|
|
||||||
|
#ifndef CONFIG_SPI_RTIO
|
||||||
ret = spi_configure(dev, config);
|
ret = spi_configure(dev, config);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
spi_context_release(ctx, ret);
|
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;
|
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);
|
spi_context_release(ctx, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -565,6 +622,99 @@ unlock:
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_SPI_MAX32_DMA */
|
#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,
|
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)
|
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;
|
const struct device *dev = data->dev;
|
||||||
uint32_t len;
|
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);
|
len = spi_context_max_continuous_chunk(ctx);
|
||||||
spi_context_update_tx(ctx, 1, len);
|
spi_context_update_tx(ctx, 1, len);
|
||||||
spi_context_update_rx(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;
|
struct max32_spi_data *data = dev->data;
|
||||||
|
|
||||||
|
#ifndef CONFIG_SPI_RTIO
|
||||||
if (!spi_context_configured(&data->ctx, config)) {
|
if (!spi_context_configured(&data->ctx, config)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
spi_context_unlock_unconditionally(&data->ctx);
|
spi_context_unlock_unconditionally(&data->ctx);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -724,6 +881,10 @@ static int spi_max32_init(const struct device *dev)
|
||||||
|
|
||||||
data->dev = dev;
|
data->dev = dev;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SPI_RTIO
|
||||||
|
spi_rtio_init(data->rtio_ctx, dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SPI_MAX32_INTERRUPT
|
#ifdef CONFIG_SPI_MAX32_INTERRUPT
|
||||||
cfg->irq_config_func(dev);
|
cfg->irq_config_func(dev);
|
||||||
#ifdef CONFIG_SPI_ASYNC
|
#ifdef CONFIG_SPI_ASYNC
|
||||||
|
|
@ -743,8 +904,8 @@ static const struct spi_driver_api spi_max32_api = {
|
||||||
.transceive_async = api_transceive_async,
|
.transceive_async = api_transceive_async,
|
||||||
#endif /* CONFIG_SPI_ASYNC */
|
#endif /* CONFIG_SPI_ASYNC */
|
||||||
#ifdef CONFIG_SPI_RTIO
|
#ifdef CONFIG_SPI_RTIO
|
||||||
.iodev_submit = spi_rtio_iodev_default_submit,
|
.iodev_submit = api_iodev_submit,
|
||||||
#endif
|
#endif /* CONFIG_SPI_RTIO */
|
||||||
.release = api_release,
|
.release = api_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -784,9 +945,14 @@ static const struct spi_driver_api spi_max32_api = {
|
||||||
#define MAX32_SPI_DMA_INIT(n)
|
#define MAX32_SPI_DMA_INIT(n)
|
||||||
#endif
|
#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) \
|
#define DEFINE_SPI_MAX32(_num) \
|
||||||
PINCTRL_DT_INST_DEFINE(_num); \
|
PINCTRL_DT_INST_DEFINE(_num); \
|
||||||
SPI_MAX32_IRQ_CONFIG_FUNC(_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 = { \
|
static const struct max32_spi_config max32_spi_config_##_num = { \
|
||||||
.regs = (mxc_spi_regs_t *)DT_INST_REG_ADDR(_num), \
|
.regs = (mxc_spi_regs_t *)DT_INST_REG_ADDR(_num), \
|
||||||
.pctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(_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 = { \
|
static struct max32_spi_data max32_spi_data_##_num = { \
|
||||||
SPI_CONTEXT_INIT_LOCK(max32_spi_data_##_num, ctx), \
|
SPI_CONTEXT_INIT_LOCK(max32_spi_data_##_num, ctx), \
|
||||||
SPI_CONTEXT_INIT_SYNC(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, \
|
DEVICE_DT_INST_DEFINE(_num, spi_max32_init, NULL, &max32_spi_data_##_num, \
|
||||||
&max32_spi_config_##_num, PRE_KERNEL_2, CONFIG_SPI_INIT_PRIORITY, \
|
&max32_spi_config_##_num, PRE_KERNEL_2, CONFIG_SPI_INIT_PRIORITY, \
|
||||||
&spi_max32_api);
|
&spi_max32_api);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue