spi: spidev: Add support for Dual/Quad SPI Transfers
authorGeert Uytterhoeven <geert+renesas@linux-m68k.org>
Tue, 25 Feb 2014 10:40:17 +0000 (11:40 +0100)
committerMark Brown <broonie@linaro.org>
Thu, 27 Feb 2014 04:51:29 +0000 (13:51 +0900)
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>
Documentation/spi/spidev
drivers/spi/spidev.c
include/uapi/linux/spi/spidev.h

index ed2da5e5b28a4490a3b03787b02df66d083692be..3d14035b1766994b537fb273d20dffc92d9554d9 100644 (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
        (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
        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
        which will return (RD) or assign (WR) the bit justification used to
index 2abc0f5a82beb3ddea77b8557fc8fa242125d1d2..e3bc23bb588340f6856efe33e2d26fc4f6156ea4 100644 (file)
@@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS);
  */
 #define SPI_MODE_MASK          (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
                                | 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 {
        dev_t                   devt;
@@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev,
                buf += k_tmp->len;
 
                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->delay_usecs = u_tmp->delay_usecs;
                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,
                                        (__u8 __user *)arg);
                break;
+       case SPI_IOC_RD_MODE32:
+               retval = __put_user(spi->mode & SPI_MODE_MASK,
+                                       (__u32 __user *)arg);
+               break;
        case SPI_IOC_RD_LSB_FIRST:
                retval = __put_user((spi->mode & SPI_LSB_FIRST) ?  1 : 0,
                                        (__u8 __user *)arg);
@@ -372,7 +379,11 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 
        /* write requests */
        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) {
                        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;
-                       spi->mode = (u8)tmp;
+                       spi->mode = (u16)tmp;
                        retval = spi_setup(spi);
                        if (retval < 0)
                                spi->mode = save;
                        else
-                               dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
+                               dev_dbg(&spi->dev, "spi mode %x\n", tmp);
                }
                break;
        case SPI_IOC_WR_LSB_FIRST:
index 52d9ed01855fe4c67a5ab1d3b4908efc7eb66a8a..dd5f21e758057f0f3ac98ee0f04823aaffeaa53f 100644 (file)
 #define SPI_LOOP               0x20
 #define SPI_NO_CS              0x40
 #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;
        __u8            bits_per_word;
        __u8            cs_change;
-       __u32           pad;
+       __u8            tx_nbits;
+       __u8            rx_nbits;
+       __u16           pad;
 
        /* If the contents of 'struct spi_ioc_transfer' ever 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)])
 
 
-/* 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_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_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 */