Skip to content

Commit e24c0f7

Browse files
committed
drivers: spi: spi_max32: Fix word size support
Driver was not handling SPI word sizes other than 8 bits. Apply DFS shift wherever necessary to support non 8-bit transfers. DMA mode cannot support word sizes that are less than 8 bits so return -ENOTSUP if word size less than 8-bits is required. Signed-off-by: Tahsin Mutlugun <Tahsin.Mutlugun@analog.com>
1 parent f4a0beb commit e24c0f7

File tree

1 file changed

+91
-44
lines changed

1 file changed

+91
-44
lines changed

drivers/spi/spi_max32.c

Lines changed: 91 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Analog Devices, Inc.
2+
* Copyright (c) 2024-2025 Analog Devices, Inc.
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -27,6 +27,9 @@
2727
LOG_MODULE_REGISTER(spi_max32, CONFIG_SPI_LOG_LEVEL);
2828
#include "spi_context.h"
2929

30+
#define SPI_MAX32_MIN_WORD_BITS 2
31+
#define SPI_MAX32_MAX_WORD_BITS 16
32+
3033
#ifdef CONFIG_SPI_MAX32_DMA
3134
struct max32_spi_dma_config {
3235
const struct device *dev;
@@ -87,9 +90,11 @@ static int spi_configure(const struct device *dev, const struct spi_config *conf
8790
mxc_spi_regs_t *regs = cfg->regs;
8891
struct max32_spi_data *data = dev->data;
8992

93+
#ifndef CONFIG_SPI_RTIO
9094
if (spi_context_configured(&data->ctx, config)) {
9195
return 0;
9296
}
97+
#endif
9398

9499
if (SPI_OP_MODE_GET(config->operation) & SPI_OP_MODE_SLAVE) {
95100
return -ENOTSUP;
@@ -163,18 +168,21 @@ static inline int spi_max32_get_dfs_shift(const struct spi_context *ctx)
163168
return 1;
164169
}
165170

166-
static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req)
171+
static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req, uint8_t dfs_shift)
167172
{
168173
req->rxCnt = 0;
169174
req->txCnt = 0;
170175

176+
spi->ctrl0 &= ~ADI_MAX32_SPI_CTRL_EN;
177+
171178
if (spi->ctrl0 & ADI_MAX32_SPI_CTRL_MASTER_MODE) {
172179
MXC_SPI_SetSlave(spi, req->ssIdx);
173180
}
174181

182+
/* SPI_CTRL1 holds the number of words so apply dfs_shift first */
175183
if (req->rxData && req->rxLen) {
176184
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_RX_NUM_CHAR,
177-
req->rxLen << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
185+
(req->rxLen >> dfs_shift) << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
178186
spi->dma |= MXC_F_SPI_DMA_RX_FIFO_EN;
179187
} else {
180188
spi->ctrl1 &= ~MXC_F_SPI_CTRL1_RX_NUM_CHAR;
@@ -183,7 +191,7 @@ static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req)
183191

184192
if (req->txLen) {
185193
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_TX_NUM_CHAR,
186-
req->txLen << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS);
194+
(req->txLen >> dfs_shift) << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS);
187195
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
188196
} else {
189197
spi->ctrl1 &= ~MXC_F_SPI_CTRL1_TX_NUM_CHAR;
@@ -206,8 +214,8 @@ static int spi_max32_transceive_sync(mxc_spi_regs_t *spi, struct max32_spi_data
206214
MXC_SPI_ClearTXFIFO(spi);
207215
MXC_SPI_ClearRXFIFO(spi);
208216

209-
tx_len = req->txLen << dfs_shift;
210-
rx_len = req->rxLen << dfs_shift;
217+
tx_len = req->txLen;
218+
rx_len = req->rxLen;
211219
do {
212220
remain = tx_len - req->txCnt;
213221
if (remain > 0) {
@@ -251,8 +259,6 @@ static int spi_max32_transceive(const struct device *dev)
251259
uint32_t len;
252260
uint8_t dfs_shift;
253261

254-
MXC_SPI_ClearTXFIFO(cfg->regs);
255-
256262
dfs_shift = spi_max32_get_dfs_shift(ctx);
257263

258264
len = spi_context_max_continuous_chunk(ctx);
@@ -263,64 +269,82 @@ static int spi_max32_transceive(const struct device *dev)
263269
len = sqe->rx.buf_len;
264270
data->req.rxData = sqe->rx.buf;
265271
data->req.rxLen = sqe->rx.buf_len;
272+
if (data->req.rxData == NULL) {
273+
data->req.rxData = data->dummy;
274+
data->req.rxLen = 0;
275+
}
266276
data->req.txData = NULL;
267-
data->req.txLen = len >> dfs_shift;
277+
data->req.txLen = len;
268278
break;
269279
case RTIO_OP_TX:
270280
len = sqe->tx.buf_len;
271281
data->req.rxLen = 0;
272282
data->req.rxData = data->dummy;
273283
data->req.txData = (uint8_t *)sqe->tx.buf;
274-
data->req.txLen = len >> dfs_shift;
284+
data->req.txLen = len;
275285
break;
276286
case RTIO_OP_TINY_TX:
277287
len = sqe->tiny_tx.buf_len;
278288
data->req.txData = (uint8_t *)sqe->tiny_tx.buf;
279289
data->req.rxData = data->dummy;
280-
data->req.txLen = len >> dfs_shift;
290+
data->req.txLen = len;
281291
data->req.rxLen = 0;
282292
break;
283293
case RTIO_OP_TXRX:
284294
len = sqe->txrx.buf_len;
285295
data->req.txData = (uint8_t *)sqe->txrx.tx_buf;
286296
data->req.rxData = sqe->txrx.rx_buf;
287-
data->req.txLen = len >> dfs_shift;
288-
data->req.rxLen = len >> dfs_shift;
297+
data->req.txLen = len;
298+
data->req.rxLen = len;
299+
if (data->req.rxData == NULL) {
300+
data->req.rxData = data->dummy;
301+
data->req.rxLen = 0;
302+
}
289303
break;
290304
default:
291305
break;
292306
}
293307
#else
294-
data->req.txLen = len >> dfs_shift;
308+
data->req.txLen = len;
295309
data->req.txData = (uint8_t *)ctx->tx_buf;
296-
data->req.rxLen = len >> dfs_shift;
297-
data->req.rxData = ctx->rx_buf;
298-
310+
data->req.rxLen = len;
299311
data->req.rxData = ctx->rx_buf;
300312

301-
data->req.rxLen = len >> dfs_shift;
302313
if (!data->req.rxData) {
303314
/* Pass a dummy buffer to HAL if receive buffer is NULL, otherwise
304315
* corrupt data is read during subsequent transactions.
305316
*/
306317
data->req.rxData = data->dummy;
307318
data->req.rxLen = 0;
319+
320+
if (!data->req.txData && !data->req.txLen) {
321+
/* Both RX and TX are NULL, nothing to do */
322+
spi_context_update_tx(&data->ctx, dfs_shift ? 2 : 1, len);
323+
spi_context_update_rx(&data->ctx, dfs_shift ? 2 : 1, len);
324+
if (!spi_context_tx_on(ctx) && !spi_context_rx_on(ctx)) {
325+
spi_context_complete(ctx, dev, 0);
326+
}
327+
328+
return 0;
329+
}
308330
}
309331
#endif
310332
data->req.spi = cfg->regs;
311333
data->req.ssIdx = ctx->config->slave;
312334
data->req.ssDeassert = 0;
313335
data->req.txCnt = 0;
314336
data->req.rxCnt = 0;
315-
spi_max32_setup(cfg->regs, &data->req);
337+
spi_max32_setup(cfg->regs, &data->req, dfs_shift);
316338
#ifdef CONFIG_SPI_MAX32_INTERRUPT
317-
MXC_SPI_SetTXThreshold(cfg->regs, 1);
339+
MXC_SPI_SetTXThreshold(cfg->regs, 1 << dfs_shift);
318340
if (data->req.rxLen) {
319-
MXC_SPI_SetRXThreshold(cfg->regs, 2);
341+
MXC_SPI_SetRXThreshold(cfg->regs, 2 << dfs_shift);
320342
MXC_SPI_EnableInt(cfg->regs, ADI_MAX32_SPI_INT_EN_RX_THD);
321343
}
322344
MXC_SPI_EnableInt(cfg->regs, ADI_MAX32_SPI_INT_EN_TX_THD | ADI_MAX32_SPI_INT_EN_MST_DONE);
323345

346+
MXC_SPI_ClearTXFIFO(cfg->regs);
347+
MXC_SPI_ClearRXFIFO(cfg->regs);
324348
if (!data->req.txData) {
325349
data->req.txCnt =
326350
MXC_SPI_WriteTXFIFO(cfg->regs, data->dummy, MIN(len, sizeof(data->dummy)));
@@ -334,8 +358,8 @@ static int spi_max32_transceive(const struct device *dev)
334358
if (ret) {
335359
ret = -EIO;
336360
} else {
337-
spi_context_update_tx(ctx, 1, len);
338-
spi_context_update_rx(ctx, 1, len);
361+
spi_context_update_tx(ctx, dfs_shift ? 2 : 1, len);
362+
spi_context_update_rx(ctx, dfs_shift ? 2 : 1, len);
339363
}
340364
#endif
341365

@@ -418,9 +442,18 @@ static int transceive(const struct device *dev, const struct spi_config *config,
418442
}
419443
}
420444
#else
421-
struct spi_rtio *rtio_ctx = data->rtio_ctx;
445+
/* Guard against unsupported word lengths here, as spi_configure is
446+
* called at a later stage */
447+
if ((SPI_WORD_SIZE_GET(config->operation) < SPI_MAX32_MIN_WORD_BITS) ||
448+
(SPI_WORD_SIZE_GET(config->operation) > SPI_MAX32_MAX_WORD_BITS)) {
449+
ret = -ENOTSUP;
450+
} else {
451+
if (tx_bufs || rx_bufs) {
452+
struct spi_rtio *rtio_ctx = data->rtio_ctx;
453+
ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs);
454+
}
455+
}
422456

423-
ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs);
424457
#endif
425458
spi_context_release(ctx, ret);
426459
return ret;
@@ -434,9 +467,10 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
434467
const struct device *spi_dev = data->dev;
435468
const struct max32_spi_config *config = spi_dev->config;
436469
uint32_t len;
470+
uint8_t dfs = spi_max32_get_dfs_shift(&data->ctx) ? 2 : 1;
437471

438472
if (status < 0) {
439-
LOG_ERR("DMA callback error with channel %d.", channel);
473+
LOG_ERR("DMA callback error for channel %u: %d", channel, status);
440474
} else {
441475
/* identify the origin of this callback */
442476
if (channel == config->tx_dma.channel) {
@@ -447,14 +481,14 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
447481
}
448482
if ((data->dma_stat & SPI_MAX32_DMA_DONE_FLAG) == SPI_MAX32_DMA_DONE_FLAG) {
449483
len = spi_context_max_continuous_chunk(&data->ctx);
450-
spi_context_update_tx(&data->ctx, 1, len);
451-
spi_context_update_rx(&data->ctx, 1, len);
484+
spi_context_update_tx(&data->ctx, dfs, len);
485+
spi_context_update_rx(&data->ctx, dfs, len);
452486
spi_context_complete(&data->ctx, spi_dev, status == 0 ? 0 : -EIO);
453487
}
454488
}
455489

456490
static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
457-
uint8_t word_shift)
491+
uint8_t dfs_shift)
458492
{
459493
int ret;
460494
const struct max32_spi_config *config = dev->config;
@@ -467,9 +501,9 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
467501
dma_cfg.user_data = (void *)data;
468502
dma_cfg.dma_slot = config->tx_dma.slot;
469503
dma_cfg.block_count = 1;
470-
dma_cfg.source_data_size = 1U << word_shift;
471-
dma_cfg.source_burst_length = 1U;
472-
dma_cfg.dest_data_size = 1U << word_shift;
504+
dma_cfg.source_data_size = 1U << dfs_shift;
505+
dma_cfg.source_burst_length = 1U << dfs_shift;
506+
dma_cfg.dest_data_size = 1U << dfs_shift;
473507
dma_cfg.head_block = &dma_blk;
474508
dma_blk.block_size = len;
475509
if (buf) {
@@ -489,7 +523,7 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
489523
}
490524

491525
static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
492-
uint8_t word_shift)
526+
uint8_t dfs_shift)
493527
{
494528
int ret;
495529
const struct max32_spi_config *config = dev->config;
@@ -502,9 +536,9 @@ static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, u
502536
dma_cfg.user_data = (void *)data;
503537
dma_cfg.dma_slot = config->rx_dma.slot;
504538
dma_cfg.block_count = 1;
505-
dma_cfg.source_data_size = 1U << word_shift;
506-
dma_cfg.source_burst_length = 1U;
507-
dma_cfg.dest_data_size = 1U << word_shift;
539+
dma_cfg.source_data_size = 1U << dfs_shift;
540+
dma_cfg.source_burst_length = 1U << dfs_shift;
541+
dma_cfg.dest_data_size = 1U << dfs_shift;
508542
dma_cfg.head_block = &dma_blk;
509543
dma_blk.block_size = len;
510544
if (buf) {
@@ -540,6 +574,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
540574
spi_context_lock(ctx, async, cb, userdata, config);
541575

542576
MXC_SPI_ClearTXFIFO(spi);
577+
MXC_SPI_ClearRXFIFO(spi);
543578

544579
ret = dma_get_status(cfg->tx_dma.dev, cfg->tx_dma.channel, &status);
545580
if (ret < 0 || status.busy) {
@@ -553,6 +588,12 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
553588
goto unlock;
554589
}
555590

591+
/* Word sizes less than 8-bits are not supported in DMA mode */
592+
if (SPI_WORD_SIZE_GET(config->operation) < 8) {
593+
ret = -ENOTSUP;
594+
goto unlock;
595+
}
596+
556597
ret = spi_configure(dev, config);
557598
if (ret != 0) {
558599
ret = -EIO;
@@ -581,12 +622,17 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
581622
dfs_shift = spi_max32_get_dfs_shift(ctx);
582623
word_count = len >> dfs_shift;
583624

625+
if (word_count == 0) {
626+
/* Nothing to do, continue */
627+
continue;
628+
}
629+
584630
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_RX_NUM_CHAR,
585631
word_count << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
586632
spi->dma |= ADI_MAX32_SPI_DMA_RX_FIFO_CLEAR;
587633
spi->dma |= MXC_F_SPI_DMA_RX_FIFO_EN;
588634
spi->dma |= ADI_MAX32_SPI_DMA_RX_DMA_EN;
589-
MXC_SPI_SetRXThreshold(spi, 0);
635+
MXC_SPI_SetRXThreshold(spi, dfs_shift ? 1 : 0);
590636

591637
ret = spi_max32_rx_dma_load(dev, ctx->rx_buf, len, dfs_shift);
592638
if (ret < 0) {
@@ -598,7 +644,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
598644
spi->dma |= ADI_MAX32_SPI_DMA_TX_FIFO_CLEAR;
599645
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
600646
spi->dma |= ADI_MAX32_SPI_DMA_TX_DMA_EN;
601-
MXC_SPI_SetTXThreshold(spi, 1);
647+
MXC_SPI_SetTXThreshold(spi, 2);
602648

603649
ret = spi_max32_tx_dma_load(dev, ctx->tx_buf, len, dfs_shift);
604650
if (ret < 0) {
@@ -754,6 +800,7 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
754800
struct spi_context *ctx = &data->ctx;
755801
const struct device *dev = data->dev;
756802
uint32_t len;
803+
uint8_t dfs;
757804

758805
#ifdef CONFIG_SPI_RTIO
759806
struct spi_rtio *rtio_ctx = data->rtio_ctx;
@@ -762,9 +809,10 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
762809
spi_max32_iodev_complete(data->dev, 0);
763810
}
764811
#endif
812+
dfs = spi_max32_get_dfs_shift(ctx) ? 2 : 1;
765813
len = spi_context_max_continuous_chunk(ctx);
766-
spi_context_update_tx(ctx, 1, len);
767-
spi_context_update_rx(ctx, 1, len);
814+
spi_context_update_tx(ctx, dfs, len);
815+
spi_context_update_rx(ctx, dfs, len);
768816
#ifdef CONFIG_SPI_ASYNC
769817
if (ctx->asynchronous && ((spi_context_tx_on(ctx) || spi_context_rx_on(ctx)))) {
770818
k_work_submit(&data->async_work);
@@ -804,12 +852,11 @@ static void spi_max32_isr(const struct device *dev)
804852
mxc_spi_req_t *req = &data->req;
805853
mxc_spi_regs_t *spi = cfg->regs;
806854
uint32_t flags, remain;
807-
uint8_t dfs_shift = spi_max32_get_dfs_shift(&data->ctx);
808855

809856
flags = MXC_SPI_GetFlags(spi);
810857
MXC_SPI_ClearFlags(spi);
811858

812-
remain = (req->txLen << dfs_shift) - req->txCnt;
859+
remain = req->txLen - req->txCnt;
813860
if (flags & ADI_MAX32_SPI_INT_FL_TX_THD) {
814861
if (remain) {
815862
if (!data->req.txData) {
@@ -824,10 +871,10 @@ static void spi_max32_isr(const struct device *dev)
824871
}
825872
}
826873

827-
remain = (req->rxLen << dfs_shift) - req->rxCnt;
874+
remain = req->rxLen - req->rxCnt;
828875
if (remain) {
829876
req->rxCnt += MXC_SPI_ReadRXFIFO(spi, &req->rxData[req->rxCnt], remain);
830-
remain = (req->rxLen << dfs_shift) - req->rxCnt;
877+
remain = req->rxLen - req->rxCnt;
831878
if (remain >= MXC_SPI_FIFO_DEPTH) {
832879
MXC_SPI_SetRXThreshold(spi, 2);
833880
} else {

0 commit comments

Comments
 (0)