From: Antonio Borneo <[email protected]>
The spi disable could potentially require some time to finish.
It has to be executed at the end of a transfer, but there is
no reason to call it in the irq handler.
Simplify the irq handler by moving out the spi disable. The
synchronization through xfer_completion is used to defer the
execution of spi disable.
Signed-off-by: Antonio Borneo <[email protected]>
Signed-off-by: Alain Volmat <[email protected]>
---
drivers/spi/spi-stm32.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c
index 0eda9903e11e..1a703c4a65db 100644
--- a/drivers/spi/spi-stm32.c
+++ b/drivers/spi/spi-stm32.c
@@ -874,7 +874,6 @@ static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id)
struct spi_master *master = dev_id;
struct stm32_spi *spi = spi_master_get_devdata(master);
- stm32f4_spi_disable(spi);
complete(&spi->xfer_completion);
return IRQ_HANDLED;
@@ -963,15 +962,18 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id)
if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0)))
stm32h7_spi_read_rxfifo(spi);
- writel_relaxed(ifcr, spi->base + STM32H7_SPI_IFCR);
-
- spin_unlock_irqrestore(&spi->lock, flags);
-
if (end) {
- stm32h7_spi_disable(spi);
+ /* Disable interrupts and clear status flags */
+ writel_relaxed(0, spi->base + STM32H7_SPI_IER);
+ writel_relaxed(STM32H7_SPI_IFCR_ALL,
+ spi->base + STM32H7_SPI_IFCR);
+
complete(&spi->xfer_completion);
+ } else {
+ writel_relaxed(ifcr, spi->base + STM32H7_SPI_IFCR);
}
+ spin_unlock_irqrestore(&spi->lock, flags);
return IRQ_HANDLED;
}
@@ -1039,10 +1041,8 @@ static void stm32f4_spi_dma_tx_cb(void *data)
{
struct stm32_spi *spi = data;
- if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) {
- stm32f4_spi_disable(spi);
+ if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX)
complete(&spi->xfer_completion);
- }
}
/**
@@ -1055,7 +1055,6 @@ static void stm32f4_spi_dma_rx_cb(void *data)
{
struct stm32_spi *spi = data;
- stm32f4_spi_disable(spi);
complete(&spi->xfer_completion);
}
@@ -1697,9 +1696,10 @@ static int stm32_spi_transfer_one(struct spi_master *master,
if (!ret) {
dev_err(spi->dev, "SPI transfer timeout (%u ms)\n", xfer_time);
spi->xfer_status = -ETIMEDOUT;
- spi->cfg->disable(spi);
}
+ spi->cfg->disable(spi);
+
spi_finalize_current_transfer(master);
return spi->xfer_status;
--
2.7.4
On Wed, Aug 05, 2020 at 09:02:07AM +0200, Alain Volmat wrote:
> From: Antonio Borneo <[email protected]>
>
> The spi disable could potentially require some time to finish.
> It has to be executed at the end of a transfer, but there is
> no reason to call it in the irq handler.
>
> Simplify the irq handler by moving out the spi disable. The
> synchronization through xfer_completion is used to defer the
> execution of spi disable.
Should this be an unprepare_transfer_hardware() operation? That would
allow the framework to take care of scheduling this in an appropriate
context with the added advantage of not needing to do it when there's
another message scheduled immediately.