瀏覽代碼

spi/rockchip: fix bug that cause spi transfer timed out in DMA duplex mode

In rx mode, dma must be prepared before spi is enabled.
But in tx and tr mode, spi must be enabled first.

Signed-off-by: Addy Ke <addy.ke@rock-chips.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Addy Ke 10 年之前
父節點
當前提交
c28be31b11
共有 1 個文件被更改,包括 23 次插入11 次删除
  1. 23 11
      drivers/spi/spi-rockchip.c

+ 23 - 11
drivers/spi/spi-rockchip.c

@@ -328,6 +328,8 @@ static int rockchip_spi_unprepare_message(struct spi_master *master,
 
 
 	spin_unlock_irqrestore(&rs->lock, flags);
 	spin_unlock_irqrestore(&rs->lock, flags);
 
 
+	spi_enable_chip(rs, 0);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -384,6 +386,8 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
 	if (rs->tx)
 	if (rs->tx)
 		wait_for_idle(rs);
 		wait_for_idle(rs);
 
 
+	spi_enable_chip(rs, 0);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -395,8 +399,10 @@ static void rockchip_spi_dma_rxcb(void *data)
 	spin_lock_irqsave(&rs->lock, flags);
 	spin_lock_irqsave(&rs->lock, flags);
 
 
 	rs->state &= ~RXBUSY;
 	rs->state &= ~RXBUSY;
-	if (!(rs->state & TXBUSY))
+	if (!(rs->state & TXBUSY)) {
+		spi_enable_chip(rs, 0);
 		spi_finalize_current_transfer(rs->master);
 		spi_finalize_current_transfer(rs->master);
+	}
 
 
 	spin_unlock_irqrestore(&rs->lock, flags);
 	spin_unlock_irqrestore(&rs->lock, flags);
 }
 }
@@ -512,8 +518,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
 	div = max_t(u32, rs->max_freq / rs->speed, 1);
 	div = max_t(u32, rs->max_freq / rs->speed, 1);
 	div = (div + 1) & 0xfffe;
 	div = (div + 1) & 0xfffe;
 
 
-	spi_enable_chip(rs, 0);
-
 	writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
 	writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
 
 
 	writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
 	writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
@@ -527,8 +531,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
 	spi_set_clk(rs, div);
 	spi_set_clk(rs, div);
 
 
 	dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
 	dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
-
-	spi_enable_chip(rs, 1);
 }
 }
 
 
 static int rockchip_spi_transfer_one(
 static int rockchip_spi_transfer_one(
@@ -536,7 +538,7 @@ static int rockchip_spi_transfer_one(
 		struct spi_device *spi,
 		struct spi_device *spi,
 		struct spi_transfer *xfer)
 		struct spi_transfer *xfer)
 {
 {
-	int ret = 0;
+	int ret = 1;
 	struct rockchip_spi *rs = spi_master_get_devdata(master);
 	struct rockchip_spi *rs = spi_master_get_devdata(master);
 
 
 	WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
 	WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
@@ -568,17 +570,27 @@ static int rockchip_spi_transfer_one(
 		rs->tmode = CR0_XFM_RO;
 		rs->tmode = CR0_XFM_RO;
 
 
 	/* we need prepare dma before spi was enabled */
 	/* we need prepare dma before spi was enabled */
-	if (master->can_dma && master->can_dma(master, spi, xfer)) {
+	if (master->can_dma && master->can_dma(master, spi, xfer))
 		rs->use_dma = 1;
 		rs->use_dma = 1;
-		rockchip_spi_prepare_dma(rs);
-	} else {
+	else
 		rs->use_dma = 0;
 		rs->use_dma = 0;
-	}
 
 
 	rockchip_spi_config(rs);
 	rockchip_spi_config(rs);
 
 
-	if (!rs->use_dma)
+	if (rs->use_dma) {
+		if (rs->tmode == CR0_XFM_RO) {
+			/* rx: dma must be prepared first */
+			rockchip_spi_prepare_dma(rs);
+			spi_enable_chip(rs, 1);
+		} else {
+			/* tx or tr: spi must be enabled first */
+			spi_enable_chip(rs, 1);
+			rockchip_spi_prepare_dma(rs);
+		}
+	} else {
+		spi_enable_chip(rs, 1);
 		ret = rockchip_spi_pio_transfer(rs);
 		ret = rockchip_spi_pio_transfer(rs);
+	}
 
 
 	return ret;
 	return ret;
 }
 }