[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