From 3ba131b1c13edb1291e686e11ea5b8ebf0d6dde3 Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Wed, 21 Jun 2023 17:42:42 -0700 Subject: [PATCH] drivers: spi: mcux_flexcomm: fix chip select bug w/ dma transfers Fix for bug: https://github.com/zephyrproject-rtos/zephyr/issues/59575 The dma version of the version of the driver can invoke multiple intermediate dma transfers, like when the spi_buf_set count is greater than one. However, there is a bug where chip select is not kept asserted for all intermediate dma transfers required to process the entire spi_buf_set. Signed-off-by: Mike J. Chen --- drivers/spi/spi_mcux_flexcomm.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/spi/spi_mcux_flexcomm.c b/drivers/spi/spi_mcux_flexcomm.c index 427704892ce..3667849c8c3 100644 --- a/drivers/spi/spi_mcux_flexcomm.c +++ b/drivers/spi/spi_mcux_flexcomm.c @@ -610,6 +610,10 @@ static int transceive_dma(const struct device *dev, while (data->ctx.rx_len > 0 || data->ctx.tx_len > 0) { size_t dma_len; + + /* last is used to deassert chip select if this + * is the last transfer in the set. + */ bool last = false; if (data->ctx.rx_len == 0) { @@ -626,6 +630,34 @@ static int transceive_dma(const struct device *dev, last = false; } + /* at this point, last just means whether or not + * this transfer will completely cover + * the current tx/rx buffer in data->ctx + * or require additional transfers because the + * the two buffers are not the same size. + * + * if it covers the current ctx tx/rx buffers, then + * we'll move to the next pair of buffers (if any) + * after the transfer, but if there are + * no more buffer pairs, then this is the last + * transfer in the set and we need to deassert CS. + */ + if (last) { + /* this dma transfer should cover + * the entire current data->ctx set + * of buffers. if there are more + * buffers in the set, then we don't + * want to deassert CS. + */ + if ((data->ctx.tx_count > 1) || + (data->ctx.rx_count > 1)) { + /* more buffers to transfer so + * this isn't last + */ + last = false; + } + } + data->status_flags = 0; ret = spi_mcux_dma_move_buffers(dev, dma_len, spi_cfg, last);