[U-Boot] [PATCH 1/3] spi: omap3: add support for more word lengths

Nikita Kiryanov nikita at compulab.co.il
Wed Oct 9 16:46:03 CEST 2013


Current implementation only supports 8 bit word lengths, even though
omap3 can handle anything between 4 and 32.

Update the spi interface to support changing the SPI word length,
and implement it in omap3_spi driver to support the full range of
possible word lengths.
This implementation is backwards compatible by defaulting to the old
behavior of 8 bit word lengths.
Also, it required a change to the omap3_spi non static I/O functions,
but since they are not used anywhere else, no collateral changes are required.

Cc: Tom Rini <trini at ti.com>
Cc: Igor Grinberg <grinberg at compulab.co.il>
Cc: Jagannadha Sutradharudu Teki <jagannadh.teki at gmail.com>
Signed-off-by: Nikita Kiryanov <nikita at compulab.co.il>
---
 drivers/spi/omap3_spi.c | 78 ++++++++++++++++++++++++++++++++++++++-----------
 drivers/spi/omap3_spi.h | 11 ++++---
 include/spi.h           | 13 +++++++++
 3 files changed, 81 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 6bac245..add98e1 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -20,7 +20,7 @@
 #include <asm/io.h>
 #include "omap3_spi.h"
 
-#define WORD_LEN	8
+#define SPI_DEFAULT_WORDLEN 8;
 #define SPI_WAIT_TIMEOUT 3000000;
 
 static void spi_reset(struct omap3_spi_slave *ds)
@@ -128,10 +128,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 	ds->regs = regs;
 	ds->freq = max_hz;
 	ds->mode = mode;
+	ds->wordlen = SPI_DEFAULT_WORDLEN;
 
 	return &ds->slave;
 }
 
+int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen)
+{
+	struct omap3_spi_slave *ds;
+	int chconf;
+
+	if (wordlen < 4 || wordlen > 32) {
+		printf("SPI error: unsupported wordlen %d\n", wordlen);
+		return -1;
+	}
+
+	ds = to_omap3_spi(slave);
+	ds->wordlen = wordlen;
+
+	chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
+	chconf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
+	chconf |= (wordlen - 1) << 7;
+	omap3_spi_write_chconf(ds, chconf);
+
+	return 0;
+}
+
 void spi_free_slave(struct spi_slave *slave)
 {
 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
@@ -185,7 +207,7 @@ int spi_claim_bus(struct spi_slave *slave)
 
 	/* wordlength */
 	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
-	conf |= (WORD_LEN - 1) << 7;
+	conf |= (ds->wordlen - 1) << 7;
 
 	/* set chipselect polarity; manage with FORCE */
 	if (!(ds->mode & SPI_CS_HIGH))
@@ -223,7 +245,7 @@ void spi_release_bus(struct spi_slave *slave)
 	spi_reset(ds);
 }
 
-int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
+int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
 		    unsigned long flags)
 {
 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
@@ -250,7 +272,13 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
 			}
 		}
 		/* Write the data */
-		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
+		unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
+		if (ds->wordlen > 16)
+			writel(((u32 *)txp)[i], tx);
+		else if (ds->wordlen > 8)
+			writel(((u16 *)txp)[i], tx);
+		else
+			writel(((u8 *)txp)[i], tx);
 	}
 
         /* wait to finish of transfer */
@@ -268,7 +296,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
 	return 0;
 }
 
-int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
+int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
 		   unsigned long flags)
 {
 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
@@ -302,7 +330,13 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
 			omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
 
 		/* Read the data */
-		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
+		unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
+		if (ds->wordlen > 16)
+			((u32 *)rxp)[i] = readl(rx);
+		else if (ds->wordlen > 8)
+			((u16 *)rxp)[i] = (u16)readl(rx);
+		else
+			((u8 *)rxp)[i] = (u8)readl(rx);
 	}
 
 	if (flags & SPI_XFER_END) {
@@ -314,8 +348,8 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
 }
 
 /*McSPI Transmit Receive Mode*/
-int omap3_spi_txrx(struct spi_slave *slave,
-		unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
+int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
+		   const void *txp, void *rxp, unsigned long flags)
 {
 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
 	int timeout = SPI_WAIT_TIMEOUT;
@@ -344,7 +378,13 @@ int omap3_spi_txrx(struct spi_slave *slave,
 			}
 		}
 		/* Write the data */
-		writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
+		unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx;
+		if (ds->wordlen > 16)
+			writel(((u32 *)txp)[i], tx);
+		else if (ds->wordlen > 8)
+			writel(((u16 *)txp)[i], tx);
+		else
+			writel(((u8 *)txp)[i], tx);
 
 		/*Read: wait for RX containing data (RXS == 1)*/
 		while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
@@ -356,7 +396,13 @@ int omap3_spi_txrx(struct spi_slave *slave,
 			}
 		}
 		/* Read the data */
-		rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
+		unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx;
+		if (ds->wordlen > 16)
+			((u32 *)rxp)[i] = readl(rx);
+		else if (ds->wordlen > 8)
+			((u16 *)rxp)[i] = (u16)readl(rx);
+		else
+			((u8 *)rxp)[i] = (u8)readl(rx);
 	}
 	/* Disable the channel */
         omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS);
@@ -375,14 +421,12 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 {
 	struct omap3_spi_slave *ds = to_omap3_spi(slave);
 	unsigned int	len;
-	const u8	*txp = dout;
-	u8		*rxp = din;
 	int ret = -1;
 
-	if (bitlen % 8)
+	if (bitlen % ds->wordlen)
 		return -1;
 
-	len = bitlen / 8;
+	len = bitlen / ds->wordlen;
 
 	if (bitlen == 0) {	 /* only change CS */
 		int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
@@ -400,11 +444,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 		ret = 0;
 	} else {
 		if (dout != NULL && din != NULL)
-			ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
+			ret = omap3_spi_txrx(slave, len, dout, din, flags);
 		else if (dout != NULL)
-			ret = omap3_spi_write(slave, len, txp, flags);
+			ret = omap3_spi_write(slave, len, dout, flags);
 		else if (din != NULL)
-			ret = omap3_spi_read(slave, len, rxp, flags);
+			ret = omap3_spi_read(slave, len, din, flags);
 	}
 	return ret;
 }
diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h
index 01537b6..aeddb53 100644
--- a/drivers/spi/omap3_spi.h
+++ b/drivers/spi/omap3_spi.h
@@ -92,6 +92,7 @@ struct omap3_spi_slave {
 	struct mcspi *regs;
 	unsigned int freq;
 	unsigned int mode;
+	unsigned int wordlen;
 };
 
 static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave)
@@ -99,11 +100,13 @@ static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave)
 	return container_of(slave, struct omap3_spi_slave, slave);
 }
 
-int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const u8 *txp,
-			u8 *rxp, unsigned long flags);
-int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
+int omap3_spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
+
+int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const void *txp,
+			void *rxp, unsigned long flags);
+int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
 		    unsigned long flags);
-int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
+int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
 		   unsigned long flags);
 
 #endif /* _OMAP3_SPI_H_ */
diff --git a/include/spi.h b/include/spi.h
index c0dab57..ae318ff 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -149,6 +149,19 @@ int spi_claim_bus(struct spi_slave *slave);
 void spi_release_bus(struct spi_slave *slave);
 
 /*-----------------------------------------------------------------------
+ * Set the word length for SPI transactions
+ *
+ * Set the word length (number of bits per word) for SPI transactions.
+ * This setting is persistent until changed.
+ *
+ *   slave:	The SPI slave
+ *   wordlen:	The number of bits in a word
+ *
+ *   Returns: 0 on success, -1 on failure.
+ */
+int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
+
+/*-----------------------------------------------------------------------
  * SPI transfer
  *
  * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
-- 
1.8.1.2



More information about the U-Boot mailing list