drivers/spi/spi-qup.c | 95 ++++++++++++++++++++++++++++++++++-----------------
1 file changed, 63 insertions(+), 32 deletions(-)
-diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
-index fe629f2..089c5e8 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -143,6 +143,7 @@ struct spi_qup {
-
+
struct spi_transfer *xfer;
struct completion done;
+ struct completion dma_tx_done;
int error;
int w_size; /* bytes per SPI word */
int n_words;
-@@ -285,16 +286,16 @@ static void spi_qup_fifo_write(struct spi_qup *controller,
-
+@@ -285,16 +286,16 @@ static void spi_qup_fifo_write(struct sp
+
static void spi_qup_dma_done(void *data)
{
- struct spi_qup *qup = data;
+ struct completion *done = data;
-
+
- complete(&qup->done);
+ complete(done);
}
-
+
static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
enum dma_transfer_direction dir,
- dma_async_tx_callback callback)
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
struct dma_async_tx_descriptor *desc;
struct scatterlist *sgl;
-@@ -313,11 +314,11 @@ static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
+@@ -313,11 +314,11 @@ static int spi_qup_prep_sg(struct spi_ma
}
-
+
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
- if (!desc)
- return -EINVAL;
+ if (IS_ERR_OR_NULL(desc))
+ return desc ? PTR_ERR(desc) : -EINVAL;
-
+
desc->callback = callback;
- desc->callback_param = qup;
+ desc->callback_param = data;
-
+
cookie = dmaengine_submit(desc);
-
-@@ -333,18 +334,29 @@ static void spi_qup_dma_terminate(struct spi_master *master,
+
+@@ -333,18 +334,29 @@ static void spi_qup_dma_terminate(struct
dmaengine_terminate_all(master->dma_rx);
}
-
+
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+unsigned long timeout)
+ struct spi_qup *qup = spi_master_get_devdata(master);
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
int ret;
-
+
+ /* before issuing the descriptors, set the QUP to run */
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+
+ if (xfer->tx_buf)
tx_done = spi_qup_dma_done;
-
+
if (xfer->rx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
+ ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done,
+ &qup->done);
if (ret)
return ret;
-
-@@ -352,17 +364,26 @@ static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
+
+@@ -352,17 +364,26 @@ static int spi_qup_do_dma(struct spi_mas
}
-
+
if (xfer->tx_buf) {
- ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
+ ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done,
+ &qup->dma_tx_done);
if (ret)
return ret;
-
+
dma_async_issue_pending(master->dma_tx);
}
-
+
- return 0;
+ if (xfer->rx_buf && !wait_for_completion_timeout(&qup->done, timeout))
+ return -ETIMEDOUT;
+
+ return ret;
}
-
+
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
+static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+ unsigned long timeout)
{
struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
-@@ -382,6 +403,15 @@ static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
+@@ -382,6 +403,15 @@ static int spi_qup_do_pio(struct spi_mas
if (qup->mode == QUP_IO_M_MODE_FIFO)
spi_qup_fifo_write(qup, xfer);
-
+
+ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+ if (ret) {
+ dev_warn(qup->dev, "cannot set RUN state\n");
+
return 0;
}
-
-@@ -430,7 +460,6 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
+
+@@ -430,7 +460,6 @@ static irqreturn_t spi_qup_qup_irq(int i
dev_warn(controller->dev, "CLK_OVER_RUN\n");
if (spi_err & SPI_ERROR_CLK_UNDER_RUN)
dev_warn(controller->dev, "CLK_UNDER_RUN\n");
-
error = -EIO;
}
-
-@@ -619,6 +648,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
+
+@@ -619,6 +648,7 @@ static int spi_qup_transfer_one(struct s
timeout = 100 * msecs_to_jiffies(timeout);
-
+
reinit_completion(&controller->done);
+ reinit_completion(&controller->dma_tx_done);
-
+
spin_lock_irqsave(&controller->lock, flags);
controller->xfer = xfer;
-@@ -628,21 +658,13 @@ static int spi_qup_transfer_one(struct spi_master *master,
+@@ -628,21 +658,13 @@ static int spi_qup_transfer_one(struct s
spin_unlock_irqrestore(&controller->lock, flags);
-
+
if (spi_qup_is_dma_xfer(controller->mode))
- ret = spi_qup_do_dma(master, xfer);
+ ret = spi_qup_do_dma(master, xfer, timeout);
else
- ret = spi_qup_do_pio(master, xfer);
+ ret = spi_qup_do_pio(master, xfer, timeout);
-
+
if (ret)
goto exit;
-
+
- if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
- dev_warn(controller->dev, "cannot set EXECUTE state\n");
- goto exit;
exit:
spi_qup_set_state(controller, QUP_STATE_RESET);
spin_lock_irqsave(&controller->lock, flags);
-@@ -664,15 +686,23 @@ static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
+@@ -664,15 +686,23 @@ static bool spi_qup_can_dma(struct spi_m
size_t dma_align = dma_get_cache_alignment();
int n_words;
-
+
- if (xfer->rx_buf && (xfer->len % qup->in_blk_sz ||
- IS_ERR_OR_NULL(master->dma_rx) ||
- !IS_ALIGNED((size_t)xfer->rx_buf, dma_align)))
+ if (!IS_ALIGNED((size_t)xfer->rx_buf, dma_align) ||
+ IS_ERR_OR_NULL(master->dma_rx))
+ return false;
-
+
- if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
- IS_ERR_OR_NULL(master->dma_tx) ||
- !IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
+ if (qup->qup_v1 && (xfer->len % qup->out_blk_sz))
+ return false;
+ }
-
+
n_words = xfer->len / DIV_ROUND_UP(xfer->bits_per_word, 8);
if (n_words <= (qup->in_fifo_sz / sizeof(u32)))
-@@ -875,6 +905,7 @@ static int spi_qup_probe(struct platform_device *pdev)
-
+@@ -875,6 +905,7 @@ static int spi_qup_probe(struct platform
+
spin_lock_init(&controller->lock);
init_completion(&controller->done);
+ init_completion(&controller->dma_tx_done);
-
+
iomode = readl_relaxed(base + QUP_IO_M_MODES);
-
---
-2.7.2
-
+