Some SPI devices have special requirements on chip-select handling. With this patch we can use a GPIO as a chip-select and strictly follow the SPI_XFER_BEGIN and SPI_XFER_END flags.
Signed-off-by: Guennadi Liakhovetski <l...@denx.de> --- Jean-Christophe: one more for you to ack. drivers/spi/mxc_spi.c | 35 +++++++++++++++++++++++++++++------ 1 files changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 9267341..eacd36c 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -32,6 +32,8 @@ #else +#include <asm/arch/mx31.h> + #define MXC_CSPIRXDATA 0x00 #define MXC_CSPITXDATA 0x04 #define MXC_CSPICTRL 0x08 @@ -68,6 +70,7 @@ struct mxc_spi_slave { struct spi_slave slave; unsigned long base; u32 ctrl_reg; + int gpio; }; static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) @@ -91,6 +94,9 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL); + if (mxcs->gpio > 0 && (flags & SPI_XFER_BEGIN)) + mx31_gpio_set(mxcs->gpio, !!(mxcs->ctrl_reg & MXC_CSPICTRL_SSPOL)); + reg_write(mxcs->base + MXC_CSPITXDATA, data); cfg_reg |= MXC_CSPICTRL_XCH; @@ -100,6 +106,9 @@ static u32 spi_xchg_single(struct spi_slave *slave, u32 data, while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH) ; + if (mxcs->gpio > 0 && (flags & SPI_XFER_END)) + mx31_gpio_set(mxcs->gpio, !(mxcs->ctrl_reg & MXC_CSPICTRL_SSPOL)); + return reg_read(mxcs->base + MXC_CSPIRXDATA); } @@ -175,10 +184,28 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int ctrl_reg; struct mxc_spi_slave *mxcs; - if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) || - cs > 3) + if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0])) + return NULL; + + mxcs = malloc(sizeof(struct mxc_spi_slave)); + if (!mxcs) return NULL; + /* + * Some SPI devices require active chip-select over multiple + * transactions, we achieve this using a GPIO. Still, the SPI + * controller has to be configured to use one of its own chipselects. + * To use this feature you have to call spi_setup_slave() with + * cs = internal_cs | (gpio << 8), and you have to use some unused + * on this SPI controller cs between 0 and 3. + */ + if (cs > 3) { + mxcs->gpio = cs >> 8; + cs &= 3; + mx31_gpio_direction(mxcs->gpio, MX31_GPIO_DIRECTION_OUT); + } else + mxcs->gpio = -1; + ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) | MXC_CSPICTRL_BITCOUNT(31) | MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ @@ -192,10 +219,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, if (mode & SPI_CS_HIGH) ctrl_reg |= MXC_CSPICTRL_SSPOL; - mxcs = malloc(sizeof(struct mxc_spi_slave)); - if (!mxcs) - return NULL; - mxcs->slave.bus = bus; mxcs->slave.cs = cs; mxcs->base = spi_bases[bus]; -- 1.5.4 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot