Skip to content

Commit 6b36211

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 6b36211

File tree

1 file changed

+93
-44
lines changed

1 file changed

+93
-44
lines changed

drivers/spi/spi_max32.c

Lines changed: 93 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,20 @@ 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+
*/
448+
if ((SPI_WORD_SIZE_GET(config->operation) < SPI_MAX32_MIN_WORD_BITS) ||
449+
(SPI_WORD_SIZE_GET(config->operation) > SPI_MAX32_MAX_WORD_BITS)) {
450+
ret = -ENOTSUP;
451+
} else {
452+
if (tx_bufs || rx_bufs) {
453+
struct spi_rtio *rtio_ctx = data->rtio_ctx;
454+
455+
ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs);
456+
}
457+
}
422458

423-
ret = spi_rtio_transceive(rtio_ctx, config, tx_bufs, rx_bufs);
424459
#endif
425460
spi_context_release(ctx, ret);
426461
return ret;
@@ -434,9 +469,10 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
434469
const struct device *spi_dev = data->dev;
435470
const struct max32_spi_config *config = spi_dev->config;
436471
uint32_t len;
472+
uint8_t dfs = spi_max32_get_dfs_shift(&data->ctx) ? 2 : 1;
437473

438474
if (status < 0) {
439-
LOG_ERR("DMA callback error with channel %d.", channel);
475+
LOG_ERR("DMA callback error for channel %u: %d", channel, status);
440476
} else {
441477
/* identify the origin of this callback */
442478
if (channel == config->tx_dma.channel) {
@@ -447,14 +483,14 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
447483
}
448484
if ((data->dma_stat & SPI_MAX32_DMA_DONE_FLAG) == SPI_MAX32_DMA_DONE_FLAG) {
449485
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);
486+
spi_context_update_tx(&data->ctx, dfs, len);
487+
spi_context_update_rx(&data->ctx, dfs, len);
452488
spi_context_complete(&data->ctx, spi_dev, status == 0 ? 0 : -EIO);
453489
}
454490
}
455491

456492
static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
457-
uint8_t word_shift)
493+
uint8_t dfs_shift)
458494
{
459495
int ret;
460496
const struct max32_spi_config *config = dev->config;
@@ -467,9 +503,9 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
467503
dma_cfg.user_data = (void *)data;
468504
dma_cfg.dma_slot = config->tx_dma.slot;
469505
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;
506+
dma_cfg.source_data_size = 1U << dfs_shift;
507+
dma_cfg.source_burst_length = 1U << dfs_shift;
508+
dma_cfg.dest_data_size = 1U << dfs_shift;
473509
dma_cfg.head_block = &dma_blk;
474510
dma_blk.block_size = len;
475511
if (buf) {
@@ -489,7 +525,7 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
489525
}
490526

491527
static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
492-
uint8_t word_shift)
528+
uint8_t dfs_shift)
493529
{
494530
int ret;
495531
const struct max32_spi_config *config = dev->config;
@@ -502,9 +538,9 @@ static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, u
502538
dma_cfg.user_data = (void *)data;
503539
dma_cfg.dma_slot = config->rx_dma.slot;
504540
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;
541+
dma_cfg.source_data_size = 1U << dfs_shift;
542+
dma_cfg.source_burst_length = 1U << dfs_shift;
543+
dma_cfg.dest_data_size = 1U << dfs_shift;
508544
dma_cfg.head_block = &dma_blk;
509545
dma_blk.block_size = len;
510546
if (buf) {
@@ -540,6 +576,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
540576
spi_context_lock(ctx, async, cb, userdata, config);
541577

542578
MXC_SPI_ClearTXFIFO(spi);
579+
MXC_SPI_ClearRXFIFO(spi);
543580

544581
ret = dma_get_status(cfg->tx_dma.dev, cfg->tx_dma.channel, &status);
545582
if (ret < 0 || status.busy) {
@@ -553,6 +590,12 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
553590
goto unlock;
554591
}
555592

593+
/* Word sizes less than 8-bits are not supported in DMA mode */
594+
if (SPI_WORD_SIZE_GET(config->operation) < 8) {
595+
ret = -ENOTSUP;
596+
goto unlock;
597+
}
598+
556599
ret = spi_configure(dev, config);
557600
if (ret != 0) {
558601
ret = -EIO;
@@ -581,12 +624,17 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
581624
dfs_shift = spi_max32_get_dfs_shift(ctx);
582625
word_count = len >> dfs_shift;
583626

627+
if (word_count == 0) {
628+
/* Nothing to do, continue */
629+
continue;
630+
}
631+
584632
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_RX_NUM_CHAR,
585633
word_count << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
586634
spi->dma |= ADI_MAX32_SPI_DMA_RX_FIFO_CLEAR;
587635
spi->dma |= MXC_F_SPI_DMA_RX_FIFO_EN;
588636
spi->dma |= ADI_MAX32_SPI_DMA_RX_DMA_EN;
589-
MXC_SPI_SetRXThreshold(spi, 0);
637+
MXC_SPI_SetRXThreshold(spi, dfs_shift ? 1 : 0);
590638

591639
ret = spi_max32_rx_dma_load(dev, ctx->rx_buf, len, dfs_shift);
592640
if (ret < 0) {
@@ -598,7 +646,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
598646
spi->dma |= ADI_MAX32_SPI_DMA_TX_FIFO_CLEAR;
599647
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
600648
spi->dma |= ADI_MAX32_SPI_DMA_TX_DMA_EN;
601-
MXC_SPI_SetTXThreshold(spi, 1);
649+
MXC_SPI_SetTXThreshold(spi, 2);
602650

603651
ret = spi_max32_tx_dma_load(dev, ctx->tx_buf, len, dfs_shift);
604652
if (ret < 0) {
@@ -754,6 +802,7 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
754802
struct spi_context *ctx = &data->ctx;
755803
const struct device *dev = data->dev;
756804
uint32_t len;
805+
uint8_t dfs;
757806

758807
#ifdef CONFIG_SPI_RTIO
759808
struct spi_rtio *rtio_ctx = data->rtio_ctx;
@@ -762,9 +811,10 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
762811
spi_max32_iodev_complete(data->dev, 0);
763812
}
764813
#endif
814+
dfs = spi_max32_get_dfs_shift(ctx) ? 2 : 1;
765815
len = spi_context_max_continuous_chunk(ctx);
766-
spi_context_update_tx(ctx, 1, len);
767-
spi_context_update_rx(ctx, 1, len);
816+
spi_context_update_tx(ctx, dfs, len);
817+
spi_context_update_rx(ctx, dfs, len);
768818
#ifdef CONFIG_SPI_ASYNC
769819
if (ctx->asynchronous && ((spi_context_tx_on(ctx) || spi_context_rx_on(ctx)))) {
770820
k_work_submit(&data->async_work);
@@ -804,12 +854,11 @@ static void spi_max32_isr(const struct device *dev)
804854
mxc_spi_req_t *req = &data->req;
805855
mxc_spi_regs_t *spi = cfg->regs;
806856
uint32_t flags, remain;
807-
uint8_t dfs_shift = spi_max32_get_dfs_shift(&data->ctx);
808857

809858
flags = MXC_SPI_GetFlags(spi);
810859
MXC_SPI_ClearFlags(spi);
811860

812-
remain = (req->txLen << dfs_shift) - req->txCnt;
861+
remain = req->txLen - req->txCnt;
813862
if (flags & ADI_MAX32_SPI_INT_FL_TX_THD) {
814863
if (remain) {
815864
if (!data->req.txData) {
@@ -824,10 +873,10 @@ static void spi_max32_isr(const struct device *dev)
824873
}
825874
}
826875

827-
remain = (req->rxLen << dfs_shift) - req->rxCnt;
876+
remain = req->rxLen - req->rxCnt;
828877
if (remain) {
829878
req->rxCnt += MXC_SPI_ReadRXFIFO(spi, &req->rxData[req->rxCnt], remain);
830-
remain = (req->rxLen << dfs_shift) - req->rxCnt;
879+
remain = req->rxLen - req->rxCnt;
831880
if (remain >= MXC_SPI_FIFO_DEPTH) {
832881
MXC_SPI_SetRXThreshold(spi, 2);
833882
} else {

0 commit comments

Comments
 (0)