Re: TI AM33x/AM43x SPI DRIVER

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

* Walter Wagner <walter.wagner@xxxxxxxxxx> [170209 00:40]:
> Dear Tony Lindgren,
> 
> I hope I'm right here and You are responsible for drivers/spi/spi-omap2-mcspi.c too.

Well I don't know much about the spi-omap2-mcspi.c driver.. But as
Franklin, Peter and Micheal have been patching it, they might have a
better idea what's going on. I've added them to Cc.

> To the history:
> 
> We use TI AM33xx/AM43xx SOCs, especially SPI interface under kernel 4.1.20.
> Testing a device with very low baudrate (1,5 KHz) I made following experience:
> 
> 1.       The last byte was not always sure received --> sometimes I got timeout
> 
> 2.       The telegrams we have contain < 160 bytes, but we need DMA mode and not PIO (because CPU load)
> 
> Therefore I've changed the driver.
> I hope these changes help other developer.
> 
> I've attached the patch and the files itself for simple comparing.

Please check Documentation/SubmittingPatches and CodingStyle etc,
also note that with git you can easily generate patches :)

I've attached your diff below for easier reading.

Regards,

Tony

8< --------------------
--- a/drivers/spi/spi-omap2-mcspi.c	2016-03-17 19:11:03.000000000 +0100
+++ b/drivers/spi/spi-omap2-mcspi.c	2017-02-06 10:35:02.518061500 +0100
@@ -116,6 +116,11 @@
  */
 #define DMA_MIN_BYTES			160
 
+/* Default value of delay at waiting for a bit in a register.
+ * Needed to avoid latency at waiting.
+ */
+#define BUSY_WAIT_DELAY			1	/* in ms */
+
 
 /*
  * Used for context save and restore, structure members to be updated whenever
@@ -138,6 +143,8 @@
 	struct omap2_mcspi_regs ctx;
 	int			fifo_depth;
 	unsigned int		pin_dir:1;
+	unsigned long		dma_min_bytes;
+	unsigned long		busy_wait_delay;
 };
 
 struct omap2_mcspi_cs {
@@ -363,6 +370,23 @@
 	return 0;
 }
 
+static int mcspi_wait_for_reg_bit_interruptible(void __iomem *reg, unsigned long bit, unsigned long delay)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + msecs_to_jiffies(1000);
+	while (!(readl_relaxed(reg) & bit)) {
+		if (time_after(jiffies, timeout)) {
+			if (!(readl_relaxed(reg) & bit))
+				return -ETIMEDOUT;
+			else
+				return 0;
+		}
+		msleep_interruptible(delay);
+	}
+	return 0;
+}
+
 static void omap2_mcspi_rx_callback(void *data)
 {
 	struct spi_device *spi = data;
@@ -496,8 +520,9 @@
 	if (l & OMAP2_MCSPI_CHCONF_TURBO) {
 		elements--;
 
-		if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
-				   & OMAP2_MCSPI_CHSTAT_RXS)) {
+		if (mcspi_wait_for_reg_bit_interruptible(cs->base + OMAP2_MCSPI_CHSTAT0,
+				OMAP2_MCSPI_CHSTAT_RXS, mcspi->busy_wait_delay) == 0) {
+			/* reading completed */
 			u32 w;
 
 			w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
@@ -508,6 +533,7 @@
 			else /* word_len <= 32 */
 				((u32 *)xfer->rx_buf)[elements++] = w;
 		} else {
+			/* timeout */
 			int bytes_per_word = mcspi_bytes_per_word(word_len);
 			dev_err(&spi->dev, "DMA RX penultimate word empty\n");
 			count -= (bytes_per_word << 1);
@@ -515,8 +541,9 @@
 			return count;
 		}
 	}
-	if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
-				& OMAP2_MCSPI_CHSTAT_RXS)) {
+	if (mcspi_wait_for_reg_bit_interruptible(cs->base + OMAP2_MCSPI_CHSTAT0,
+			OMAP2_MCSPI_CHSTAT_RXS, mcspi->busy_wait_delay) == 0) {
+		/* reading completed */
 		u32 w;
 
 		w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
@@ -527,6 +554,7 @@
 		else /* word_len <= 32 */
 			((u32 *)xfer->rx_buf)[elements] = w;
 	} else {
+		/* timeout */
 		dev_err(&spi->dev, "DMA RX last word empty\n");
 		count -= mcspi_bytes_per_word(word_len);
 	}
@@ -1141,7 +1169,7 @@
 			unsigned	count;
 
 			if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-			    (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
+			    (m->is_dma_mapped || t->len >= mcspi->dma_min_bytes))
 				omap2_mcspi_set_fifo(spi, t, 1);
 
 			omap2_mcspi_set_enable(spi, 1);
@@ -1152,7 +1180,7 @@
 						+ OMAP2_MCSPI_TX0);
 
 			if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-			    (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
+			    (m->is_dma_mapped || t->len >= mcspi->dma_min_bytes))
 				count = omap2_mcspi_txrx_dma(spi, t);
 			else
 				count = omap2_mcspi_txrx_pio(spi, t);
@@ -1234,7 +1262,7 @@
 			goto out;
 		}
 
-		if (m->is_dma_mapped || len < DMA_MIN_BYTES)
+		if (m->is_dma_mapped || len < mcspi->dma_min_bytes)
 			continue;
 
 		if (mcspi_dma->dma_tx && tx_buf != NULL) {
@@ -1375,6 +1403,11 @@
 			master->bus_num = pdev->id;
 		mcspi->pin_dir = pdata->pin_dir;
 	}
+	mcspi->dma_min_bytes = DMA_MIN_BYTES; /* default value */
+	of_property_read_u32(node, "ti,dma-min-bytes", &mcspi->dma_min_bytes);
+	mcspi->busy_wait_delay = BUSY_WAIT_DELAY; /* default value */
+	of_property_read_u32(node, "ti,busy-wait-delay", &mcspi->busy_wait_delay);
+
 	regs_offset = pdata->regs_offset;
 
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux