Skip to content

Commit e69ae4e

Browse files
benjamin-santon-adicfriedt
authored andcommitted
drivers: spi: spi_max32: Fix QSPI and half duplex, support hold on CS
Fix QSPI and half duplex Support hold on CS flag Create functions to assert and deassert CS Signed-off-by: Benjamin Santon <benjamin.santon@analog.com>
1 parent fff3257 commit e69ae4e

File tree

1 file changed

+72
-84
lines changed

1 file changed

+72
-84
lines changed

drivers/spi/spi_max32.c

Lines changed: 72 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,37 @@ static void spi_max32_setup(mxc_spi_regs_t *spi, mxc_spi_req_t *req, uint8_t dfs
205205
MXC_SPI_ClearFlags(spi);
206206
}
207207

208+
static void spi_cs_assert(const struct device *dev)
209+
{
210+
const struct max32_spi_config *cfg = dev->config;
211+
struct max32_spi_data *data = dev->data;
212+
struct spi_context *ctx = &data->ctx;
213+
214+
if (spi_cs_is_gpio(ctx->config)) {
215+
MXC_SPI_HWSSControl(cfg->regs, false);
216+
spi_context_cs_control(ctx, true);
217+
} else {
218+
MXC_SPI_HWSSControl(cfg->regs, true);
219+
cfg->regs->ctrl0 = (cfg->regs->ctrl0 & ~MXC_F_SPI_CTRL0_START) |
220+
ADI_MAX32_SPI_CTRL0_SS_CTRL;
221+
}
222+
}
223+
224+
static void spi_cs_deassert(const struct device *dev)
225+
{
226+
const struct max32_spi_config *cfg = dev->config;
227+
struct max32_spi_data *data = dev->data;
228+
struct spi_context *ctx = &data->ctx;
229+
230+
if (spi_cs_is_gpio(ctx->config)) {
231+
spi_context_cs_control(ctx, false);
232+
} else {
233+
cfg->regs->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL |
234+
ADI_MAX32_SPI_CTRL_EN);
235+
cfg->regs->ctrl0 |= ADI_MAX32_SPI_CTRL_EN;
236+
}
237+
}
238+
208239
#ifndef CONFIG_SPI_MAX32_INTERRUPT
209240
static int spi_max32_transceive_sync(mxc_spi_regs_t *spi, struct max32_spi_data *data,
210241
uint8_t dfs_shift)
@@ -228,15 +259,23 @@ static int spi_max32_transceive_sync(mxc_spi_regs_t *spi, struct max32_spi_data
228259
req->txCnt +=
229260
MXC_SPI_WriteTXFIFO(spi, &req->txData[req->txCnt], remain);
230261
}
231-
if (!(spi->ctrl0 & MXC_F_SPI_CTRL0_START)) {
232-
spi->ctrl0 |= MXC_F_SPI_CTRL0_START;
233-
}
234262
}
235263

236264
if (req->rxCnt < rx_len) {
237265
req->rxCnt += MXC_SPI_ReadRXFIFO(spi, &req->rxData[req->rxCnt],
238266
rx_len - req->rxCnt);
239267
}
268+
269+
if (!(spi->ctrl0 & MXC_F_SPI_CTRL0_START)) {
270+
/* Transfer not started */
271+
if ((MXC_SPI_GetTXFIFOAvailable(spi) - MXC_SPI_FIFO_DEPTH) > 0) {
272+
/* Data remaining in the TX FIFO, ensure TX started */
273+
spi->ctrl0 |= MXC_F_SPI_CTRL0_START;
274+
} else if (MXC_SPI_GetRXFIFOAvailable(spi) < (rx_len - req->rxCnt)) {
275+
/* Not enough data into the RX FIFO */
276+
spi->ctrl0 |= MXC_F_SPI_CTRL0_START;
277+
}
278+
}
240279
} while ((req->txCnt < tx_len) || (req->rxCnt < rx_len));
241280

242281
do {
@@ -307,7 +346,19 @@ static int spi_max32_transceive(const struct device *dev)
307346
break;
308347
}
309348
#else
310-
data->req.txLen = len;
349+
if ((ctx->config->operation & SPI_HALF_DUPLEX)
350+
#if defined(CONFIG_SPI_EXTENDED_MODES)
351+
|| (ctx->config->operation & SPI_LINES_DUAL)
352+
|| (ctx->config->operation & SPI_LINES_QUAD)
353+
|| (ctx->config->operation & SPI_LINES_OCTAL)
354+
#endif
355+
) {
356+
/* Half duplex mode, tx should be set only if no rx */
357+
data->req.txLen = ctx->tx_buf ? len : 0;
358+
} else {
359+
/* Full duplex mode, tx and rx can be set independently */
360+
data->req.txLen = len;
361+
}
311362
data->req.txData = (uint8_t *)ctx->tx_buf;
312363
data->req.rxLen = len;
313364
data->req.rxData = ctx->rx_buf;
@@ -375,10 +426,6 @@ static int transceive(const struct device *dev, const struct spi_config *config,
375426
int ret = 0;
376427
struct max32_spi_data *data = dev->data;
377428
struct spi_context *ctx = &data->ctx;
378-
#ifndef CONFIG_SPI_RTIO
379-
const struct max32_spi_config *cfg = dev->config;
380-
bool hw_cs_ctrl = true;
381-
#endif
382429

383430
#ifndef CONFIG_SPI_MAX32_INTERRUPT
384431
if (async) {
@@ -397,19 +444,8 @@ static int transceive(const struct device *dev, const struct spi_config *config,
397444

398445
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1);
399446

400-
/* Check if CS GPIO exists */
401-
if (spi_cs_is_gpio(config)) {
402-
hw_cs_ctrl = false;
403-
}
404-
MXC_SPI_HWSSControl(cfg->regs, hw_cs_ctrl);
405-
406-
/* Assert the CS line if HW control disabled */
407-
if (!hw_cs_ctrl) {
408-
spi_context_cs_control(ctx, true);
409-
} else {
410-
cfg->regs->ctrl0 =
411-
(cfg->regs->ctrl0 & ~MXC_F_SPI_CTRL0_START) | ADI_MAX32_SPI_CTRL0_SS_CTRL;
412-
}
447+
/* Assert the CS line */
448+
spi_cs_assert(dev);
413449

414450
#ifdef CONFIG_SPI_MAX32_INTERRUPT
415451
do {
@@ -433,15 +469,9 @@ static int transceive(const struct device *dev, const struct spi_config *config,
433469

434470
#endif /* CONFIG_SPI_MAX32_INTERRUPT */
435471

436-
/* Deassert the CS line if hw control disabled */
437-
if (!async) {
438-
if (!hw_cs_ctrl) {
439-
spi_context_cs_control(ctx, false);
440-
} else {
441-
cfg->regs->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL |
442-
ADI_MAX32_SPI_CTRL_EN);
443-
cfg->regs->ctrl0 |= ADI_MAX32_SPI_CTRL_EN;
444-
}
472+
/* Deassert the CS line if hold mode is not enabled */
473+
if (!async && !(ctx->config->operation & SPI_HOLD_ON_CS)) {
474+
spi_cs_deassert(dev);
445475
}
446476
#else
447477
/* Guard against unsupported word lengths here, as spi_configure is
@@ -573,8 +603,6 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
573603
uint32_t len, word_count;
574604
uint8_t dfs_shift;
575605

576-
bool hw_cs_ctrl = true;
577-
578606
spi_context_lock(ctx, async, cb, userdata, config);
579607

580608
MXC_SPI_ClearTXFIFO(spi);
@@ -605,18 +633,8 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
605633

606634
spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, 1);
607635

608-
/* Check if CS GPIO exists */
609-
if (spi_cs_is_gpio(config)) {
610-
hw_cs_ctrl = false;
611-
}
612-
MXC_SPI_HWSSControl(cfg->regs, hw_cs_ctrl);
613-
614-
/* Assert the CS line if HW control disabled */
615-
if (!hw_cs_ctrl) {
616-
spi_context_cs_control(ctx, true);
617-
} else {
618-
spi->ctrl0 = (spi->ctrl0 & ~MXC_F_SPI_CTRL0_START) | ADI_MAX32_SPI_CTRL0_SS_CTRL;
619-
}
636+
/* Assert the CS line */
637+
spi_cs_assert(dev);
620638

621639
MXC_SPI_SetSlave(cfg->regs, ctx->config->slave);
622640

@@ -665,14 +683,8 @@ static int transceive_dma(const struct device *dev, const struct spi_config *con
665683
}
666684

667685
unlock:
668-
/* Deassert the CS line if hw control disabled */
669-
if (!hw_cs_ctrl) {
670-
spi_context_cs_control(ctx, false);
671-
} else {
672-
spi->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL |
673-
ADI_MAX32_SPI_CTRL_EN);
674-
spi->ctrl0 |= ADI_MAX32_SPI_CTRL_EN;
675-
}
686+
/* Deassert the CS line */
687+
spi_cs_deassert(dev);
676688

677689
spi_context_release(ctx, ret);
678690

@@ -712,26 +724,12 @@ static inline void spi_max32_iodev_prepare_start(const struct device *dev)
712724
struct spi_rtio *rtio_ctx = data->rtio_ctx;
713725
struct spi_dt_spec *spi_dt_spec = rtio_ctx->txn_curr->sqe.iodev->data;
714726
struct spi_config *spi_config = &spi_dt_spec->config;
715-
struct max32_spi_config *cfg = (struct max32_spi_config *)dev->config;
716727
int ret;
717-
bool hw_cs_ctrl = true;
718728

719729
ret = spi_configure(dev, spi_config);
720730
__ASSERT(!ret, "%d", ret);
721731

722-
/* Check if CS GPIO exists */
723-
if (spi_cs_is_gpio(spi_config)) {
724-
hw_cs_ctrl = false;
725-
}
726-
MXC_SPI_HWSSControl(cfg->regs, hw_cs_ctrl);
727-
728-
/* Assert the CS line if HW control disabled */
729-
if (!hw_cs_ctrl) {
730-
spi_context_cs_control(&data->ctx, true);
731-
} else {
732-
cfg->regs->ctrl0 =
733-
(cfg->regs->ctrl0 & ~MXC_F_SPI_CTRL0_START) | MXC_F_SPI_CTRL0_SS_CTRL;
734-
};
732+
spi_cs_assert(dev);
735733
}
736734

737735
static void spi_max32_iodev_complete(const struct device *dev, int status)
@@ -743,16 +741,7 @@ static void spi_max32_iodev_complete(const struct device *dev, int status)
743741
rtio_ctx->txn_curr = rtio_txn_next(rtio_ctx->txn_curr);
744742
spi_max32_iodev_start(dev);
745743
} else {
746-
struct max32_spi_config *cfg = (struct max32_spi_config *)dev->config;
747-
bool hw_cs_ctrl = true;
748-
749-
if (!hw_cs_ctrl) {
750-
spi_context_cs_control(&data->ctx, false);
751-
} else {
752-
cfg->regs->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | MXC_F_SPI_CTRL0_SS_CTRL |
753-
ADI_MAX32_SPI_CTRL_EN);
754-
cfg->regs->ctrl0 |= ADI_MAX32_SPI_CTRL_EN;
755-
}
744+
spi_cs_deassert(dev);
756745

757746
if (spi_rtio_complete(rtio_ctx, status)) {
758747
spi_max32_iodev_prepare_start(dev);
@@ -820,13 +809,7 @@ static void spi_max32_callback(mxc_spi_req_t *req, int error)
820809
if (ctx->asynchronous && ((spi_context_tx_on(ctx) || spi_context_rx_on(ctx)))) {
821810
k_work_submit(&data->async_work);
822811
} else {
823-
if (spi_cs_is_gpio(ctx->config)) {
824-
spi_context_cs_control(ctx, false);
825-
} else {
826-
req->spi->ctrl0 &= ~(MXC_F_SPI_CTRL0_START | ADI_MAX32_SPI_CTRL0_SS_CTRL |
827-
ADI_MAX32_SPI_CTRL_EN);
828-
req->spi->ctrl0 |= ADI_MAX32_SPI_CTRL_EN;
829-
}
812+
spi_cs_deassert(dev);
830813
spi_context_complete(ctx, dev, error == E_NO_ERROR ? 0 : -EIO);
831814
}
832815
#else
@@ -900,12 +883,17 @@ static void spi_max32_isr(const struct device *dev)
900883
static int api_release(const struct device *dev, const struct spi_config *config)
901884
{
902885
struct max32_spi_data *data = dev->data;
886+
struct spi_context *ctx = &data->ctx;
903887

904888
#ifndef CONFIG_SPI_RTIO
905889
if (!spi_context_configured(&data->ctx, config)) {
906890
return -EINVAL;
907891
}
908892
#endif
893+
894+
if (ctx->config->operation & SPI_HOLD_ON_CS) {
895+
spi_cs_deassert(dev);
896+
}
909897
spi_context_unlock_unconditionally(&data->ctx);
910898
return 0;
911899
}

0 commit comments

Comments
 (0)