From 5753d09b1064a669e3be8f27e0f1fd008b96934a Mon Sep 17 00:00:00 2001 From: Nikita Kiryanov Date: Wed, 16 Oct 2013 17:23:25 +0300 Subject: spi: omap3: add support for more word lengths 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 Cc: Jagannadha Sutradharudu Teki Cc: Igor Grinberg Signed-off-by: Nikita Kiryanov --- drivers/spi/omap3_spi.c | 69 +++++++++++++++++++++++++++++++++++-------------- drivers/spi/omap3_spi.h | 8 +++--- drivers/spi/spi.c | 13 ++++++++++ 3 files changed, 66 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 116276c..a3ad056 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,6 @@ #include #include "omap3_spi.h" -#define WORD_LEN 8 #define SPI_WAIT_TIMEOUT 3000000 static void spi_reset(struct omap3_spi_slave *ds) @@ -185,7 +184,7 @@ int spi_claim_bus(struct spi_slave *slave) /* wordlength */ conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; - conf |= (WORD_LEN - 1) << 7; + conf |= (ds->slave.wordlen - 1) << 7; /* set chipselect polarity; manage with FORCE */ if (!(ds->mode & SPI_CS_HIGH)) @@ -223,7 +222,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); @@ -234,7 +233,8 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, /* Enable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); - chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; + chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); + chconf |= (ds->slave.wordlen - 1) << 7; chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY; chconf |= OMAP3_MCSPI_CHCONF_FORCE; omap3_spi_write_chconf(ds,chconf); @@ -250,7 +250,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->slave.wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->slave.wordlen > 8) + writel(((u16 *)txp)[i], tx); + else + writel(((u8 *)txp)[i], tx); } /* wait to finish of transfer */ @@ -268,7 +274,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); @@ -279,7 +285,8 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, /* Enable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); - chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; + chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); + chconf |= (ds->slave.wordlen - 1) << 7; chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY; chconf |= OMAP3_MCSPI_CHCONF_FORCE; omap3_spi_write_chconf(ds,chconf); @@ -302,7 +309,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->slave.wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->slave.wordlen > 8) + ((u16 *)rxp)[i] = (u16)readl(rx); + else + ((u8 *)rxp)[i] = (u8)readl(rx); } if (flags & SPI_XFER_END) { @@ -314,8 +327,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; @@ -327,7 +340,8 @@ int omap3_spi_txrx(struct spi_slave *slave, omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_EN); /*set TRANSMIT-RECEIVE Mode*/ - chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK; + chconf &= ~(OMAP3_MCSPI_CHCONF_TRM_MASK | OMAP3_MCSPI_CHCONF_WL_MASK); + chconf |= (ds->slave.wordlen - 1) << 7; chconf |= OMAP3_MCSPI_CHCONF_FORCE; omap3_spi_write_chconf(ds,chconf); @@ -344,7 +358,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->slave.wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->slave.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 +376,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->slave.wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->slave.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 +401,17 @@ 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 (ds->slave.wordlen < 4 || ds->slave.wordlen > 32) { + printf("omap3_spi: invalid wordlen %d\n", ds->slave.wordlen); + return -1; + } + + if (bitlen % ds->slave.wordlen) return -1; - len = bitlen / 8; + len = bitlen / ds->slave.wordlen; if (bitlen == 0) { /* only change CS */ int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); @@ -400,11 +429,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..ab7cd84 100644 --- a/drivers/spi/omap3_spi.h +++ b/drivers/spi/omap3_spi.h @@ -99,11 +99,11 @@ 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_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/drivers/spi/spi.c b/drivers/spi/spi.c index ea39d1a..b76a26c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -8,6 +8,18 @@ #include #include +int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) +{ + if (wordlen == 0 || wordlen > 32) { + printf("spi: invalid wordlen %d\n", wordlen); + return -1; + } + + slave->wordlen = wordlen; + + return 0; +} + void *spi_do_alloc_slave(int offset, int size, unsigned int bus, unsigned int cs) { @@ -20,6 +32,7 @@ void *spi_do_alloc_slave(int offset, int size, unsigned int bus, slave = (struct spi_slave *)(ptr + offset); slave->bus = bus; slave->cs = cs; + slave->wordlen = SPI_DEFAULT_WORDLEN; } return ptr; -- cgit v1.1