Hi Mark, Wang, On Sunday 11 August 2013 03:45 PM, wangyuhang wrote: > fix the previous patch some mistake below: > 1. DT in slave node, use "spi-tx-nbits =<1/2/4>" in place of using > "spi-tx-dual, spi-tx-quad" directly, same to rx. So correct the > previous way to get the property in @of_register_spi_devices(). > 2. Change the value of transfer bit macro(SPI_NBITS_SINGLE, SPI_NBITS_DUAL > SPI_NBITS_QUAD) to 0x01, 0x02 and 0x04 to match the actual wires. > 3. Add the following check > (1)keep the tx_nbits and rx_nbits in spi_transfer is not beyond the > single, dual and quad. > (2)keep tx_nbits and rx_nbits are contained by @spi_device->mode > example: if @spi_device->mode = DUAL, then tx/rx_nbits can not be set > to QUAD(SPI_NBITS_QUAD) > (3)if "@spi_device->mode& SPI_3WIRE", then tx/rx_nbits should be in > single(SPI_NBITS_SINGLE) > > Signed-off-by: wangyuhang<wangyuhang2...@gmail.com> > --- > drivers/spi/spi.c | 96 > +++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/spi/spi.h | 22 ++++++++++- > 2 files changed, 116 insertions(+), 2 deletions(-) > > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c > index 004b10f..78f257a 100644 > --- a/drivers/spi/spi.c > +++ b/drivers/spi/spi.c > @@ -869,6 +869,51 @@ static void of_register_spi_devices(struct spi_master > *master) > if (of_find_property(nc, "spi-3wire", NULL)) > spi->mode |= SPI_3WIRE; > > + /* Device DUAL/QUAD mode */ > + prop = of_get_property(nc, "spi-tx-nbits",&len); > + if (!prop || len< sizeof(*prop)) { > + dev_err(&master->dev, "%s has no 'spi-tx-nbits' > property\n", > + nc->full_name); > + spi_dev_put(spi); > + continue; > + } > + switch(be32_to_cpup(prop)) { > + case SPI_NBITS_SINGLE: > + break; > + case SPI_NBITS_DUAL: > + spi->mode |= SPI_TX_DUAL; > + break; > + case SPI_NBITS_QUAD: > + spi->mode |= SPI_TX_QUAD; > + break; > + default: > + dev_err(&master->dev, "spi-tx-nbits value is not > supported\n"); > + spi_dev_put(spi); > + continue; > + } > + > + prop = of_get_property(nc, "spi-rx-nbits",&len); > + if (!prop || len< sizeof(*prop)) { > + dev_err(&master->dev, "%s has no 'spi-rx-nbits' > property\n", > + nc->full_name); > + spi_dev_put(spi); > + continue; > + } > + switch(be32_to_cpup(prop)) { > + case SPI_NBITS_SINGLE: > + break; > + case SPI_NBITS_DUAL: > + spi->mode |= SPI_RX_DUAL; > + break; > + case SPI_NBITS_QUAD: > + spi->mode |= SPI_RX_QUAD; > + break; > + default: > + dev_err(&master->dev, "spi-rx-nbits value is not > supported\n"); > + spi_dev_put(spi); > + continue; > + } > + > /* Device speed */ > prop = of_get_property(nc, "spi-max-frequency",&len); > if (!prop || len< sizeof(*prop)) { > @@ -1313,6 +1358,19 @@ int spi_setup(struct spi_device *spi) > unsigned bad_bits; > int status = 0; > > + /* check mode to prevent that DUAL and QUAD set at the same time > + */ > + if (((spi->mode& SPI_TX_DUAL)&& (spi->mode& SPI_TX_QUAD)) || > + ((spi->mode& SPI_RX_DUAL)&& (spi->mode& SPI_RX_QUAD))) { > + dev_err(&spi->dev, > + "setup: can not select dual and quad at the same time\n"); > + return -EINVAL; > + } > + /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden > + */ > + if ((spi->mode& SPI_3WIRE)&& (spi->mode& > + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD))) > + return -EINVAL; > /* help drivers fail *cleanly* when they need options > * that aren't supported with their current master > */ > @@ -1370,12 +1428,50 @@ static int __spi_async(struct spi_device *spi, struct > spi_message *message) > /** > * Set transfer bits_per_word and max speed as spi device default if > * it is not set for this transfer. > + * Set transfer tx_nbits and rx_nbits as single transfer default > + * (SPI_NBITS_SINGLE) if it is not set for this transfer. > */ > list_for_each_entry(xfer,&message->transfers, transfer_list) { > if (!xfer->bits_per_word) > xfer->bits_per_word = spi->bits_per_word; > if (!xfer->speed_hz) > xfer->speed_hz = spi->max_speed_hz; > + if (xfer->tx_buf&& !xfer->tx_nbits) > + xfer->tx_nbits = SPI_NBITS_SINGLE; > + if (xfer->rx_buf&& !xfer->rx_nbits) > + xfer->rx_nbits = SPI_NBITS_SINGLE; > + /* check transfer tx/rx_nbits: > + * 1. keep the value is not out of single, dual and quad > + * 2. keep tx/rx_nbits is contained by mode in spi_device > + * 3. if SPI_3WIRE, tx/rx_nbits should be in single > + */ Sorry for pitchin in a bit late on this. I was trying to use this for my use case today. I realise this check should be under...
> + if (xfer->tx_nbits != SPI_NBITS_SINGLE&& > + xfer->tx_nbits != SPI_NBITS_DUAL&& > + xfer->tx_nbits != SPI_NBITS_QUAD) > + return -EINVAL; > + if ((xfer->tx_nbits == SPI_NBITS_DUAL)&& > + !(spi->mode& (SPI_TX_DUAL | SPI_TX_QUAD))) > + return -EINVAL; > + if ((xfer->tx_nbits == SPI_NBITS_QUAD)&& > + !(spi->mode& SPI_TX_QUAD)) > + return -EINVAL; > + if ((spi->mode& SPI_3WIRE)&& > + (xfer->tx_nbits != SPI_NBITS_SINGLE)) > + return -EINVAL; if (xfer->tx_buf) { ...... } and > + /* check transfer rx_nbits */ > + if (xfer->rx_nbits != SPI_NBITS_SINGLE&& > + xfer->rx_nbits != SPI_NBITS_DUAL&& > + xfer->rx_nbits != SPI_NBITS_QUAD) > + return -EINVAL; > + if ((xfer->rx_nbits == SPI_NBITS_DUAL)&& > + !(spi->mode& (SPI_RX_DUAL | SPI_RX_QUAD))) > + return -EINVAL; > + if ((xfer->rx_nbits == SPI_NBITS_QUAD)&& > + !(spi->mode& SPI_RX_QUAD)) > + return -EINVAL; > + if ((spi->mode& SPI_3WIRE)&& > + (xfer->rx_nbits != SPI_NBITS_SINGLE)) > + return -EINVAL; this should be under if (xfer->rx_buf) { ..... } > } > > message->spi = spi; > diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h > index 38c2b92..3dc0a86 100644 > --- a/include/linux/spi/spi.h > +++ b/include/linux/spi/spi.h > @@ -74,7 +74,7 @@ struct spi_device { > struct spi_master *master; > u32 max_speed_hz; > u8 chip_select; > - u8 mode; > + u16 mode; > #define SPI_CPHA 0x01 /* clock phase */ > #define SPI_CPOL 0x02 /* clock polarity */ > #define SPI_MODE_0 (0|0) /* (original MicroWire) > */ > @@ -87,6 +87,10 @@ struct spi_device { > #define SPI_LOOP 0x20 /* loopback mode */ > #define SPI_NO_CS 0x40 /* 1 dev/bus, no > chipselect */ > #define SPI_READY 0x80 /* slave pulls low to > pause */ > +#define SPI_TX_DUAL 0x100 /* transmit with 2 > wires */ > +#define SPI_TX_QUAD 0x200 /* transmit with 4 > wires */ > +#define SPI_RX_DUAL 0x400 /* receive with 2 wires > */ > +#define SPI_RX_QUAD 0x800 /* receive with 4 wires > */ > u8 bits_per_word; > int irq; > void *controller_state; > @@ -437,6 +441,10 @@ extern struct spi_master *spi_busnum_to_master(u16 > busnum); > * @rx_buf: data to be read (dma-safe memory), or NULL > * @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped > * @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped > + * @tx_nbits: number of bits used for writting. If 0 the default > + * (SPI_NBITS_SINGLE) is used. > + * @rx_nbits: number of bits used for reading. If 0 the default > + * (SPI_NBITS_SINGLE) is used. > * @len: size of rx and tx buffers (in bytes) > * @speed_hz: Select a speed other than the device default for this > * transfer. If 0 the default (from @spi_device) is used. > @@ -491,6 +499,11 @@ extern struct spi_master *spi_busnum_to_master(u16 > busnum); > * by the results of previous messages and where the whole transaction > * ends when the chipselect goes intactive. > * > + * When SPI can transfer in 1x,2x or 4x. It can get this tranfer information > + * from device through @tx_nbits and @rx_nbits. In Bi-direction, these > + * two should both be set. User can set transfer mode with > SPI_NBITS_SINGLE(1x) > + * SPI_NBITS_DUAL(2x) and SPI_NBITS_QUAD(4x) to support these three transfer. > + * > * The code that submits an spi_message (and its spi_transfers) > * to the lower layers is responsible for managing its memory. > * Zero-initialize every field you don't set up explicitly, to > @@ -511,6 +524,11 @@ struct spi_transfer { > dma_addr_t rx_dma; > > unsigned cs_change:1; > + u8 tx_nbits; > + u8 rx_nbits; > +#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */ > +#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */ > +#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */ > u8 bits_per_word; > u16 delay_usecs; > u32 speed_hz; > @@ -858,7 +876,7 @@ struct spi_board_info { > /* mode becomes spi_device.mode, and is essential for chips > * where the default of SPI_CS_HIGH = 0 is wrong. > */ > - u8 mode; > + u16 mode; > > /* ... may need additional spi_device chip config data here. > * avoid stuff protocol drivers can set; but include stuff ------------------------------------------------------------------------------ Introducing Performance Central, a new site from SourceForge and AppDynamics. Performance Central is your source for news, insights, analysis and resources for efficient Application Performance Management. Visit us today! http://pubads.g.doubleclick.net/gampad/clk?id=48897511&iu=/4140/ostg.clktrk _______________________________________________ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general