Fix 8 and 16-bit transfers in mxc_spi driver and a wrong pointer in the free routine.
Signed-off-by: Guennadi Liakhovetski <l...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot