diff options
-rw-r--r-- | drivers/spi/spi-qup.c | 51 | ||||
-rw-r--r-- | drivers/spi/spi-stm32-qspi.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-uniphier.c | 17 |
3 files changed, 59 insertions, 13 deletions
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index f22dbb4b87a5..eb8a6a2e91c9 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -273,6 +273,9 @@ static void spi_qup_read(struct spi_qup *controller, u32 *opflags) writel_relaxed(QUP_OP_IN_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); + if (!remainder) + goto exit; + if (is_block_mode) { num_words = (remainder > words_per_block) ? words_per_block : remainder; @@ -302,11 +305,13 @@ static void spi_qup_read(struct spi_qup *controller, u32 *opflags) * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be * present and this is used to determine if transaction is complete */ - *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); - if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) - writel_relaxed(QUP_OP_IN_SERVICE_FLAG, - controller->base + QUP_OPERATIONAL); - +exit: + if (!remainder) { + *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); + if (is_block_mode && *opflags & QUP_OP_MAX_INPUT_DONE_FLAG) + writel_relaxed(QUP_OP_IN_SERVICE_FLAG, + controller->base + QUP_OPERATIONAL); + } } static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words) @@ -354,6 +359,10 @@ static void spi_qup_write(struct spi_qup *controller) writel_relaxed(QUP_OP_OUT_SERVICE_FLAG, controller->base + QUP_OPERATIONAL); + /* make sure the interrupt is valid */ + if (!remainder) + return; + if (is_block_mode) { num_words = (remainder > words_per_block) ? words_per_block : remainder; @@ -567,10 +576,24 @@ static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer, return 0; } +static bool spi_qup_data_pending(struct spi_qup *controller) +{ + unsigned int remainder_tx, remainder_rx; + + remainder_tx = DIV_ROUND_UP(spi_qup_len(controller) - + controller->tx_bytes, controller->w_size); + + remainder_rx = DIV_ROUND_UP(spi_qup_len(controller) - + controller->rx_bytes, controller->w_size); + + return remainder_tx || remainder_rx; +} + static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) { struct spi_qup *controller = dev_id; u32 opflags, qup_err, spi_err; + unsigned long flags; int error = 0; qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); @@ -602,6 +625,11 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) error = -EIO; } + spin_lock_irqsave(&controller->lock, flags); + if (!controller->error) + controller->error = error; + spin_unlock_irqrestore(&controller->lock, flags); + if (spi_qup_is_dma_xfer(controller->mode)) { writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); } else { @@ -610,11 +638,22 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) if (opflags & QUP_OP_OUT_SERVICE_FLAG) spi_qup_write(controller); + + if (!spi_qup_data_pending(controller)) + complete(&controller->done); } - if ((opflags & QUP_OP_MAX_INPUT_DONE_FLAG) || error) + if (error) complete(&controller->done); + if (opflags & QUP_OP_MAX_INPUT_DONE_FLAG) { + if (!spi_qup_is_dma_xfer(controller->mode)) { + if (spi_qup_data_pending(controller)) + return IRQ_HANDLED; + } + complete(&controller->done); + } + return IRQ_HANDLED; } diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c index 42f8e3c6aa1f..5dbb6a8e893c 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -29,7 +29,7 @@ #define CR_SSHIFT BIT(4) #define CR_DFM BIT(6) #define CR_FSEL BIT(7) -#define CR_FTHRES_MASK GENMASK(12, 8) +#define CR_FTHRES_SHIFT 8 #define CR_TEIE BIT(16) #define CR_TCIE BIT(17) #define CR_FTIE BIT(18) @@ -463,7 +463,7 @@ static int stm32_qspi_setup(struct spi_device *spi) flash->presc = presc; mutex_lock(&qspi->lock); - qspi->cr_reg = FIELD_PREP(CR_FTHRES_MASK, 3) | CR_SSHIFT | CR_EN; + qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); /* set dcr fsize to max address */ diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index 5a6137fe172d..b32c77df5d49 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -328,7 +328,12 @@ static int uniphier_spi_transfer_one(struct spi_master *master, struct spi_transfer *t) { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); - int status; + struct device *dev = master->dev.parent; + unsigned long time_left; + + /* Terminate and return success for 0 byte length transfer */ + if (!t->len) + return 0; uniphier_spi_setup_transfer(spi, t); @@ -338,13 +343,15 @@ static int uniphier_spi_transfer_one(struct spi_master *master, uniphier_spi_irq_enable(spi, SSI_IE_RCIE | SSI_IE_RORIE); - status = wait_for_completion_timeout(&priv->xfer_done, - msecs_to_jiffies(SSI_TIMEOUT_MS)); + time_left = wait_for_completion_timeout(&priv->xfer_done, + msecs_to_jiffies(SSI_TIMEOUT_MS)); uniphier_spi_irq_disable(spi, SSI_IE_RCIE | SSI_IE_RORIE); - if (status < 0) - return status; + if (!time_left) { + dev_err(dev, "transfer timeout.\n"); + return -ETIMEDOUT; + } return priv->error; } |