summaryrefslogtreecommitdiff
path: root/drivers/spi/spi-img-spfi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/spi-img-spfi.c')
-rw-r--r--drivers/spi/spi-img-spfi.c94
1 files changed, 61 insertions, 33 deletions
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index 99a3f7c0c7ff..dedb7d880ccc 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -134,7 +134,6 @@ static inline void spfi_stop(struct img_spfi *spfi)
static inline void spfi_reset(struct img_spfi *spfi)
{
spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL);
- udelay(1);
spfi_writel(spfi, 0, SPFI_CONTROL);
}
@@ -271,7 +270,6 @@ static int img_spfi_start_pio(struct spi_master *master,
if (rx_bytes > 0 || tx_bytes > 0) {
dev_err(spfi->dev, "PIO transfer timed out\n");
- spfi_reset(spfi);
return -ETIMEDOUT;
}
@@ -397,6 +395,56 @@ stop_dma:
return -EIO;
}
+static void img_spfi_handle_err(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(master);
+ unsigned long flags;
+
+ /*
+ * Stop all DMA and reset the controller if the previous transaction
+ * timed-out and never completed it's DMA.
+ */
+ spin_lock_irqsave(&spfi->lock, flags);
+ if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
+ spfi->tx_dma_busy = false;
+ spfi->rx_dma_busy = false;
+
+ dmaengine_terminate_all(spfi->tx_ch);
+ dmaengine_terminate_all(spfi->rx_ch);
+ }
+ spin_unlock_irqrestore(&spfi->lock, flags);
+}
+
+static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(master);
+ u32 val;
+
+ val = spfi_readl(spfi, SPFI_PORT_STATE);
+ if (msg->spi->mode & SPI_CPHA)
+ val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
+ else
+ val &= ~SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
+ if (msg->spi->mode & SPI_CPOL)
+ val |= SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
+ else
+ val &= ~SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
+ spfi_writel(spfi, val, SPFI_PORT_STATE);
+
+ return 0;
+}
+
+static int img_spfi_unprepare(struct spi_master *master,
+ struct spi_message *msg)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(master);
+
+ spfi_reset(spfi);
+
+ return 0;
+}
+
static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
struct spi_transfer *xfer)
{
@@ -416,6 +464,9 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT;
spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select));
+ spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
+ SPFI_TRANSACTION);
+
val = spfi_readl(spfi, SPFI_CONTROL);
val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA);
if (xfer->tx_buf)
@@ -434,20 +485,6 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
&master->cur_msg->transfers))
val |= SPFI_CONTROL_CONTINUE;
spfi_writel(spfi, val, SPFI_CONTROL);
-
- val = spfi_readl(spfi, SPFI_PORT_STATE);
- if (spi->mode & SPI_CPHA)
- val |= SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
- else
- val &= ~SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
- if (spi->mode & SPI_CPOL)
- val |= SPFI_PORT_STATE_CK_POL(spi->chip_select);
- else
- val &= ~SPFI_PORT_STATE_CK_POL(spi->chip_select);
- spfi_writel(spfi, val, SPFI_PORT_STATE);
-
- spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
- SPFI_TRANSACTION);
}
static int img_spfi_transfer_one(struct spi_master *master,
@@ -455,25 +492,13 @@ static int img_spfi_transfer_one(struct spi_master *master,
struct spi_transfer *xfer)
{
struct img_spfi *spfi = spi_master_get_devdata(spi->master);
- bool dma_reset = false;
- unsigned long flags;
int ret;
- /*
- * Stop all DMA and reset the controller if the previous transaction
- * timed-out and never completed it's DMA.
- */
- spin_lock_irqsave(&spfi->lock, flags);
- if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
- dev_err(spfi->dev, "SPI DMA still busy\n");
- dma_reset = true;
- }
- spin_unlock_irqrestore(&spfi->lock, flags);
-
- if (dma_reset) {
- dmaengine_terminate_all(spfi->tx_ch);
- dmaengine_terminate_all(spfi->rx_ch);
- spfi_reset(spfi);
+ if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
+ dev_err(spfi->dev,
+ "Transfer length (%d) is greater than the max supported (%d)",
+ xfer->len, SPFI_TRANSACTION_TSIZE_MASK);
+ return -EINVAL;
}
img_spfi_config(master, spi, xfer);
@@ -592,6 +617,9 @@ static int img_spfi_probe(struct platform_device *pdev)
master->set_cs = img_spfi_set_cs;
master->transfer_one = img_spfi_transfer_one;
+ master->prepare_message = img_spfi_prepare;
+ master->unprepare_message = img_spfi_unprepare;
+ master->handle_err = img_spfi_handle_err;
spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx");
spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx");