spi: spidev: Add support for Dual/Quad SPI Transfers

Add support for Dual/Quad SPI Transfers to the spidev API.
As this uses SPI mode bits that don't fit in a single byte, two new
ioctls (SPI_IOC_RD_MODE32 and SPI_IOC_WR_MODE32) are introduced.

Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
This commit is contained in:
Geert Uytterhoeven 2014-02-25 11:40:17 +01:00 committed by Mark Brown
parent e6456186ca
commit dc64d39b54
3 changed files with 33 additions and 6 deletions

View file

@ -85,6 +85,12 @@ settings for data transfer parameters:
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase, (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags. sample on trailing edge iff this is set) flags.
Note that this request is limited to SPI mode flags that fit in a
single byte.
SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t
which will return (RD) or assign (WR) the full SPI transfer mode,
not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to which will return (RD) or assign (WR) the bit justification used to

View file

@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
*/ */
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY) | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)
struct spidev_data { struct spidev_data {
dev_t devt; dev_t devt;
@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev,
buf += k_tmp->len; buf += k_tmp->len;
k_tmp->cs_change = !!u_tmp->cs_change; k_tmp->cs_change = !!u_tmp->cs_change;
k_tmp->tx_nbits = u_tmp->tx_nbits;
k_tmp->rx_nbits = u_tmp->rx_nbits;
k_tmp->bits_per_word = u_tmp->bits_per_word; k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs; k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz; k_tmp->speed_hz = u_tmp->speed_hz;
@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = __put_user(spi->mode & SPI_MODE_MASK, retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u8 __user *)arg); (__u8 __user *)arg);
break; break;
case SPI_IOC_RD_MODE32:
retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u32 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST: case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
(__u8 __user *)arg); (__u8 __user *)arg);
@ -372,7 +379,11 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
/* write requests */ /* write requests */
case SPI_IOC_WR_MODE: case SPI_IOC_WR_MODE:
retval = __get_user(tmp, (u8 __user *)arg); case SPI_IOC_WR_MODE32:
if (cmd == SPI_IOC_WR_MODE)
retval = __get_user(tmp, (u8 __user *)arg);
else
retval = __get_user(tmp, (u32 __user *)arg);
if (retval == 0) { if (retval == 0) {
u32 save = spi->mode; u32 save = spi->mode;
@ -382,12 +393,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
} }
tmp |= spi->mode & ~SPI_MODE_MASK; tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u8)tmp; spi->mode = (u16)tmp;
retval = spi_setup(spi); retval = spi_setup(spi);
if (retval < 0) if (retval < 0)
spi->mode = save; spi->mode = save;
else else
dev_dbg(&spi->dev, "spi mode %02x\n", tmp); dev_dbg(&spi->dev, "spi mode %x\n", tmp);
} }
break; break;
case SPI_IOC_WR_LSB_FIRST: case SPI_IOC_WR_LSB_FIRST:

View file

@ -42,6 +42,10 @@
#define SPI_LOOP 0x20 #define SPI_LOOP 0x20
#define SPI_NO_CS 0x40 #define SPI_NO_CS 0x40
#define SPI_READY 0x80 #define SPI_READY 0x80
#define SPI_TX_DUAL 0x100
#define SPI_TX_QUAD 0x200
#define SPI_RX_DUAL 0x400
#define SPI_RX_QUAD 0x800
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -92,7 +96,9 @@ struct spi_ioc_transfer {
__u16 delay_usecs; __u16 delay_usecs;
__u8 bits_per_word; __u8 bits_per_word;
__u8 cs_change; __u8 cs_change;
__u32 pad; __u8 tx_nbits;
__u8 rx_nbits;
__u16 pad;
/* If the contents of 'struct spi_ioc_transfer' ever change /* If the contents of 'struct spi_ioc_transfer' ever change
* incompatibly, then the ioctl number (currently 0) must change; * incompatibly, then the ioctl number (currently 0) must change;
@ -110,7 +116,7 @@ struct spi_ioc_transfer {
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */ /* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) (limited to 8 bits) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8) #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) #define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8)
@ -126,6 +132,10 @@ struct spi_ioc_transfer {
#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
/* Read / Write of the SPI mode field */
#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, __u32)
#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32)
#endif /* SPIDEV_H */ #endif /* SPIDEV_H */