Skip to content

Commit 14741d1

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 14741d1

File tree

1 file changed

+62
-37
lines changed

1 file changed

+62
-37
lines changed

drivers/spi/spi_max32.c

Lines changed: 62 additions & 37 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
*/
@@ -163,18 +163,21 @@ static inline int spi_max32_get_dfs_shift(const struct spi_context *ctx)
163163
return 1;
164164
}
165165

166-
static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req)
166+
static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req, uint8_t dfs_shift)
167167
{
168168
req->rxCnt = 0;
169169
req->txCnt = 0;
170170

171+
spi->ctrl0 &= ~ADI_MAX32_SPI_CTRL_EN;
172+
171173
if (spi->ctrl0 & ADI_MAX32_SPI_CTRL_MASTER_MODE) {
172174
MXC_SPI_SetSlave(spi, req->ssIdx);
173175
}
174176

177+
/* SPI_CTRL1 holds the number of words so apply dfs_shift first */
175178
if (req->rxData && req->rxLen) {
176179
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_RX_NUM_CHAR,
177-
req->rxLen << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
180+
(req->rxLen >> dfs_shift) << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
178181
spi->dma |= MXC_F_SPI_DMA_RX_FIFO_EN;
179182
} else {
180183
spi->ctrl1 &= ~MXC_F_SPI_CTRL1_RX_NUM_CHAR;
@@ -183,7 +186,7 @@ static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req)
183186

184187
if (req->txLen) {
185188
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_TX_NUM_CHAR,
186-
req->txLen << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS);
189+
(req->txLen >> dfs_shift) << MXC_F_SPI_CTRL1_TX_NUM_CHAR_POS);
187190
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
188191
} else {
189192
spi->ctrl1 &= ~MXC_F_SPI_CTRL1_TX_NUM_CHAR;
@@ -206,8 +209,8 @@ static int spi_max32_transceive_sync(mxc_spi_regs_t *spi, struct max32_spi_data
206209
MXC_SPI_ClearTXFIFO(spi);
207210
MXC_SPI_ClearRXFIFO(spi);
208211

209-
tx_len = req->txLen << dfs_shift;
210-
rx_len = req->rxLen << dfs_shift;
212+
tx_len = req->txLen;
213+
rx_len = req->rxLen;
211214
do {
212215
remain = tx_len - req->txCnt;
213216
if (remain > 0) {
@@ -251,8 +254,6 @@ static int spi_max32_transceive(const struct device *dev)
251254
uint32_t len;
252255
uint8_t dfs_shift;
253256

254-
MXC_SPI_ClearTXFIFO(cfg->regs);
255-
256257
dfs_shift = spi_max32_get_dfs_shift(ctx);
257258

258259
len = spi_context_max_continuous_chunk(ctx);
@@ -291,36 +292,46 @@ static int spi_max32_transceive(const struct device *dev)
291292
break;
292293
}
293294
#else
294-
data->req.txLen = len >> dfs_shift;
295+
data->req.txLen = len;
295296
data->req.txData = (uint8_t *)ctx->tx_buf;
296-
data->req.rxLen = len >> dfs_shift;
297-
data->req.rxData = ctx->rx_buf;
298-
297+
data->req.rxLen = len;
299298
data->req.rxData = ctx->rx_buf;
300299

301-
data->req.rxLen = len >> dfs_shift;
302300
if (!data->req.rxData) {
303301
/* Pass a dummy buffer to HAL if receive buffer is NULL, otherwise
304302
* corrupt data is read during subsequent transactions.
305303
*/
306304
data->req.rxData = data->dummy;
307305
data->req.rxLen = 0;
306+
307+
if (!data->req.txData && !data->req.txLen) {
308+
/* Both RX and TX are NULL, nothing to do */
309+
spi_context_update_tx(&data->ctx, dfs_shift ? 2 : 1, len);
310+
spi_context_update_rx(&data->ctx, dfs_shift ? 2 : 1, len);
311+
if (!spi_context_tx_on(ctx) && !spi_context_rx_on(ctx)) {
312+
spi_context_complete(ctx, dev, 0);
313+
}
314+
315+
return 0;
316+
}
308317
}
309318
#endif
310319
data->req.spi = cfg->regs;
311320
data->req.ssIdx = ctx->config->slave;
312321
data->req.ssDeassert = 0;
313322
data->req.txCnt = 0;
314323
data->req.rxCnt = 0;
315-
spi_max32_setup(cfg->regs, &data->req);
324+
spi_max32_setup(cfg->regs, &data->req, dfs_shift);
316325
#ifdef CONFIG_SPI_MAX32_INTERRUPT
317-
MXC_SPI_SetTXThreshold(cfg->regs, 1);
326+
MXC_SPI_SetTXThreshold(cfg->regs, 1 << dfs_shift);
318327
if (data->req.rxLen) {
319-
MXC_SPI_SetRXThreshold(cfg->regs, 2);
328+
MXC_SPI_SetRXThreshold(cfg->regs, 2 << dfs_shift);
320329
MXC_SPI_EnableInt(cfg->regs, ADI_MAX32_SPI_INT_EN_RX_THD);
321330
}
322331
MXC_SPI_EnableInt(cfg->regs, ADI_MAX32_SPI_INT_EN_TX_THD | ADI_MAX32_SPI_INT_EN_MST_DONE);
323332

333+
MXC_SPI_ClearTXFIFO(cfg->regs);
334+
MXC_SPI_ClearRXFIFO(cfg->regs);
324335
if (!data->req.txData) {
325336
data->req.txCnt =
326337
MXC_SPI_WriteTXFIFO(cfg->regs, data->dummy, MIN(len, sizeof(data->dummy)));
@@ -334,8 +345,8 @@ static int spi_max32_transceive(const struct device *dev)
334345
if (ret) {
335346
ret = -EIO;
336347
} else {
337-
spi_context_update_tx(ctx, 1, len);
338-
spi_context_update_rx(ctx, 1, len);
348+
spi_context_update_tx(ctx, dfs_shift ? 2 : 1, len);
349+
spi_context_update_rx(ctx, dfs_shift ? 2 : 1, len);
339350
}
340351
#endif
341352

@@ -434,9 +445,10 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
434445
const struct device *spi_dev = data->dev;
435446
const struct max32_spi_config *config = spi_dev->config;
436447
uint32_t len;
448+
uint8_t dfs = spi_max32_get_dfs_shift(&data->ctx) ? 2 : 1;
437449

438450
if (status < 0) {
439-
LOG_ERR("DMA callback error with channel %d.", channel);
451+
LOG_ERR("DMA callback error for channel %u: %d", channel, status);
440452
} else {
441453
/* identify the origin of this callback */
442454
if (channel == config->tx_dma.channel) {
@@ -447,14 +459,14 @@ static void spi_max32_dma_callback(const struct device *dev, void *arg, uint32_t
447459
}
448460
if ((data->dma_stat & SPI_MAX32_DMA_DONE_FLAG) == SPI_MAX32_DMA_DONE_FLAG) {
449461
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);
462+
spi_context_update_tx(&data->ctx, dfs, len);
463+
spi_context_update_rx(&data->ctx, dfs, len);
452464
spi_context_complete(&data->ctx, spi_dev, status == 0 ? 0 : -EIO);
453465
}
454466
}
455467

456468
static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
457-
uint8_t word_shift)
469+
uint8_t dfs_shift)
458470
{
459471
int ret;
460472
const struct max32_spi_config *config = dev->config;
@@ -467,9 +479,9 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
467479
dma_cfg.user_data = (void *)data;
468480
dma_cfg.dma_slot = config->tx_dma.slot;
469481
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;
482+
dma_cfg.source_data_size = 1U << dfs_shift;
483+
dma_cfg.source_burst_length = 1U << dfs_shift;
484+
dma_cfg.dest_data_size = 1U << dfs_shift;
473485
dma_cfg.head_block = &dma_blk;
474486
dma_blk.block_size = len;
475487
if (buf) {
@@ -489,7 +501,7 @@ static int spi_max32_tx_dma_load(const struct device *dev, const uint8_t *buf, u
489501
}
490502

491503
static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, uint32_t len,
492-
uint8_t word_shift)
504+
uint8_t dfs_shift)
493505
{
494506
int ret;
495507
const struct max32_spi_config *config = dev->config;
@@ -502,9 +514,9 @@ static int spi_max32_rx_dma_load(const struct device *dev, const uint8_t *buf, u
502514
dma_cfg.user_data = (void *)data;
503515
dma_cfg.dma_slot = config->rx_dma.slot;
504516
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;
517+
dma_cfg.source_data_size = 1U << dfs_shift;
518+
dma_cfg.source_burst_length = 1U << dfs_shift;
519+
dma_cfg.dest_data_size = 1U << dfs_shift;
508520
dma_cfg.head_block = &dma_blk;
509521
dma_blk.block_size = len;
510522
if (buf) {
@@ -540,6 +552,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
540552
spi_context_lock(ctx, async, cb, userdata, config);
541553

542554
MXC_SPI_ClearTXFIFO(spi);
555+
MXC_SPI_ClearRXFIFO(spi);
543556

544557
ret = dma_get_status(cfg->tx_dma.dev, cfg->tx_dma.channel, &status);
545558
if (ret < 0 || status.busy) {
@@ -553,6 +566,12 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
553566
goto unlock;
554567
}
555568

569+
/* Word sizes less than 8-bits are not supported in DMA mode */
570+
if (SPI_WORD_SIZE_GET(config->operation) < 8) {
571+
ret = -ENOTSUP;
572+
goto unlock;
573+
}
574+
556575
ret = spi_configure(dev, config);
557576
if (ret != 0) {
558577
ret = -EIO;
@@ -581,12 +600,17 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
581600
dfs_shift = spi_max32_get_dfs_shift(ctx);
582601
word_count = len >> dfs_shift;
583602

603+
if (word_count == 0) {
604+
/* Nothing to do, continue */
605+
continue;
606+
}
607+
584608
MXC_SETFIELD(spi->ctrl1, MXC_F_SPI_CTRL1_RX_NUM_CHAR,
585609
word_count << MXC_F_SPI_CTRL1_RX_NUM_CHAR_POS);
586610
spi->dma |= ADI_MAX32_SPI_DMA_RX_FIFO_CLEAR;
587611
spi->dma |= MXC_F_SPI_DMA_RX_FIFO_EN;
588612
spi->dma |= ADI_MAX32_SPI_DMA_RX_DMA_EN;
589-
MXC_SPI_SetRXThreshold(spi, 0);
613+
MXC_SPI_SetRXThreshold(spi, dfs_shift ? 1 : 0);
590614

591615
ret = spi_max32_rx_dma_load(dev, ctx->rx_buf, len, dfs_shift);
592616
if (ret < 0) {
@@ -598,7 +622,7 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
598622
spi->dma |= ADI_MAX32_SPI_DMA_TX_FIFO_CLEAR;
599623
spi->dma |= MXC_F_SPI_DMA_TX_FIFO_EN;
600624
spi->dma |= ADI_MAX32_SPI_DMA_TX_DMA_EN;
601-
MXC_SPI_SetTXThreshold(spi, 1);
625+
MXC_SPI_SetTXThreshold(spi, 2);
602626

603627
ret = spi_max32_tx_dma_load(dev, ctx->tx_buf, len, dfs_shift);
604628
if (ret < 0) {
@@ -754,6 +778,7 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
754778
struct spi_context *ctx = &data->ctx;
755779
const struct device *dev = data->dev;
756780
uint32_t len;
781+
uint8_t dfs;
757782

758783
#ifdef CONFIG_SPI_RTIO
759784
struct spi_rtio *rtio_ctx = data->rtio_ctx;
@@ -762,9 +787,10 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
762787
spi_max32_iodev_complete(data->dev, 0);
763788
}
764789
#endif
790+
dfs = spi_max32_get_dfs_shift(ctx) ? 2 : 1;
765791
len = spi_context_max_continuous_chunk(ctx);
766-
spi_context_update_tx(ctx, 1, len);
767-
spi_context_update_rx(ctx, 1, len);
792+
spi_context_update_tx(ctx, dfs, len);
793+
spi_context_update_rx(ctx, dfs, len);
768794
#ifdef CONFIG_SPI_ASYNC
769795
if (ctx->asynchronous && ((spi_context_tx_on(ctx) || spi_context_rx_on(ctx)))) {
770796
k_work_submit(&data->async_work);
@@ -804,12 +830,11 @@ static void spi_max32_isr(const struct device *dev)
804830
mxc_spi_req_t *req = &data->req;
805831
mxc_spi_regs_t *spi = cfg->regs;
806832
uint32_t flags, remain;
807-
uint8_t dfs_shift = spi_max32_get_dfs_shift(&data->ctx);
808833

809834
flags = MXC_SPI_GetFlags(spi);
810835
MXC_SPI_ClearFlags(spi);
811836

812-
remain = (req->txLen << dfs_shift) - req->txCnt;
837+
remain = req->txLen - req->txCnt;
813838
if (flags & ADI_MAX32_SPI_INT_FL_TX_THD) {
814839
if (remain) {
815840
if (!data->req.txData) {
@@ -824,10 +849,10 @@ static void spi_max32_isr(const struct device *dev)
824849
}
825850
}
826851

827-
remain = (req->rxLen << dfs_shift) - req->rxCnt;
852+
remain = req->rxLen - req->rxCnt;
828853
if (remain) {
829854
req->rxCnt += MXC_SPI_ReadRXFIFO(spi, &req->rxData[req->rxCnt], remain);
830-
remain = (req->rxLen << dfs_shift) - req->rxCnt;
855+
remain = req->rxLen - req->rxCnt;
831856
if (remain >= MXC_SPI_FIFO_DEPTH) {
832857
MXC_SPI_SetRXThreshold(spi, 2);
833858
} else {

0 commit comments

Comments
 (0)