[PATCH v3 1/2]spi: DUAL and QUAD support
Sourav Poddar
sourav.poddar at ti.com
Thu Aug 22 08:35:11 EDT 2013
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<wangyuhang2014 at 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
More information about the linux-mtd
mailing list