[U-Boot] [PATCH 1/9] i.MX31: fix SPI driver for shorter than 32 bit transfers

Guennadi Liakhovetski lg at denx.de
Wed Feb 4 17:59:17 CET 2009


Fix 8 and 16-bit transfers in mxc_spi driver and a wrong pointer in the 
free routine.

Signed-off-by: Guennadi Liakhovetski <lg at denx.de>
---

No SPI custodian, so, Jean-Christophe will have to Ack it?

 drivers/spi/mxc_spi.c |   62 +++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index 5957ada..9267341 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -85,17 +85,12 @@ static inline void reg_write(unsigned long addr, u32 val)
 	*(volatile unsigned long*)addr = val;
 }
 
-static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen)
+static u32 spi_xchg_single(struct spi_slave *slave, u32 data,
+			   unsigned long flags)
 {
 	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
 	unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL);
 
-	if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) {
-		cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |
-			MXC_CSPICTRL_BITCOUNT(bitlen - 1);
-		reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg);
-	}
-
 	reg_write(mxcs->base + MXC_CSPITXDATA, data);
 
 	cfg_reg |= MXC_CSPICTRL_XCH;
@@ -108,13 +103,46 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen)
 	return reg_read(mxcs->base + MXC_CSPIRXDATA);
 }
 
+/*
+ * bitlen is the total number of bits to be sent. Therefore, if you have to send
+ * using < 32-bit words, you have to send each single word individually. If
+ * bitlen > 32 we assume you meant to send 32-bit words...
+ */
 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-		void *din, unsigned long flags)
+	     void *din, unsigned long flags)
 {
-	int n_blks = (bitlen + 31) / 32;
+	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
+	int n_blks = bitlen / 32;
 	u32 *out_l, *in_l;
 	int i;
 
+	mxcs->ctrl_reg = (mxcs->ctrl_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |
+		MXC_CSPICTRL_BITCOUNT(bitlen - 1);
+
+	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg);
+
+	if (bitlen <= 8) {
+		u32 iword, oword = *(const u8 *)dout;
+
+		iword = spi_xchg_single(slave, oword, flags);
+		*(u8 *)din = iword;
+		return 0;
+	}
+
+	if (bitlen <= 16) {
+		u32 iword, oword = *(const u16 *)dout;
+
+		if ((int)dout & 1 || (int)din & 1) {
+			printf("Error: unaligned buffers in: %p, out: %p\n",
+			       din, dout);
+			return 1;
+		}
+
+		iword = spi_xchg_single(slave, oword, flags);
+		*(u16 *)din = iword;
+		return 0;
+	}
+
 	if ((int)dout & 3 || (int)din & 3) {
 		printf("Error: unaligned buffers in: %p, out: %p\n", din, dout);
 		return 1;
@@ -122,8 +150,17 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 
 	for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout;
 	     i < n_blks;
-	     i++, in_l++, out_l++, bitlen -= 32)
-		*in_l = spi_xchg_single(slave, *out_l, bitlen);
+	     i++, in_l++, out_l++)
+		*in_l = spi_xchg_single(slave, *out_l, flags);
+
+	if (bitlen & 31) {
+		/* Exchange the residue, treat data as 32 bits */
+		mxcs->ctrl_reg = (mxcs->ctrl_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |
+			MXC_CSPICTRL_BITCOUNT((bitlen & 31) - 1);
+		reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg);
+
+		*in_l = spi_xchg_single(slave, *out_l, flags);
+	}
 
 	return 0;
 }
@@ -169,7 +206,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
 
 void spi_free_slave(struct spi_slave *slave)
 {
-	free(slave);
+	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
+	free(mxcs);
 }
 
 int spi_claim_bus(struct spi_slave *slave)
-- 
1.5.4



More information about the U-Boot mailing list