Merge remote-tracking branch 'spi/topic/quad' into spi-qspi
authorMark Brown <broonie@linaro.org>
Fri, 23 Aug 2013 11:00:15 +0000 (12:00 +0100)
committerMark Brown <broonie@linaro.org>
Fri, 23 Aug 2013 11:00:15 +0000 (12:00 +0100)
drivers/spi/spi.c
include/linux/spi/spi.h

index 361cced..76e6ddf 100644 (file)
@@ -885,6 +885,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)) {
@@ -1332,6 +1377,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
         */
@@ -1367,6 +1425,11 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
        struct spi_master *master = spi->master;
        struct spi_transfer *xfer;
 
+       if (list_empty(&message->transfers))
+               return -EINVAL;
+       if (!message->complete)
+               return -EINVAL;
+
        /* Half-duplex links include original MicroWire, and ones with
         * only one data pin like SPI_3WIRE (switches direction) or where
         * either MOSI or MISO is missing.  They can also be caused by
@@ -1389,12 +1452,19 @@ 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)
+               if (!xfer->speed_hz) {
                        xfer->speed_hz = spi->max_speed_hz;
+                       if (master->max_speed_hz &&
+                           xfer->speed_hz > master->max_speed_hz)
+                               xfer->speed_hz = master->max_speed_hz;
+               }
+
                if (master->bits_per_word_mask) {
                        /* Only 32 bits fit in the mask */
                        if (xfer->bits_per_word > 32)
@@ -1403,6 +1473,53 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
                                        BIT(xfer->bits_per_word - 1)))
                                return -EINVAL;
                }
+
+               if (xfer->speed_hz && master->min_speed_hz &&
+                   xfer->speed_hz < master->min_speed_hz)
+                       return -EINVAL;
+               if (xfer->speed_hz && master->max_speed_hz &&
+                   xfer->speed_hz > master->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
+                */
+               if (xfer->tx_buf) {
+                       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;
+               }
+               /* check transfer rx_nbits */
+               if (xfer->rx_buf) {
+                       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;
+               }
        }
 
        message->spi = spi;
index bf0204c..d4a16a6 100644 (file)
@@ -74,7 +74,7 @@ struct spi_device {
        struct spi_master       *master;
        u32                     max_speed_hz;
        u8                      chip_select;
-       u                     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;
@@ -233,6 +237,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  *     suported. If set, the SPI core will reject any transfer with an
  *     unsupported bits_per_word. If not set, this value is simply ignored,
  *     and it's up to the individual driver to perform any validation.
+ * @min_speed_hz: Lowest supported transfer speed
+ * @max_speed_hz: Highest supported transfer speed
  * @flags: other constraints relevant to this driver
  * @bus_lock_spinlock: spinlock for SPI bus locking
  * @bus_lock_mutex: mutex for SPI bus locking
@@ -315,6 +321,10 @@ struct spi_master {
 #define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0UL : (BIT(bits) - 1))
 #define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))
 
+       /* limits on transfer speed */
+       u32                     min_speed_hz;
+       u32                     max_speed_hz;
+
        /* other constraints relevant to this driver */
        u16                     flags;
 #define SPI_MASTER_HALF_DUPLEX BIT(0)          /* can't do full duplex */
@@ -453,6 +463,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.
@@ -507,6 +521,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
@@ -527,6 +546,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;
@@ -874,7 +898,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.
         */
-       u             mode;
+       u16             mode;
 
        /* ... may need additional spi_device chip config data here.
         * avoid stuff protocol drivers can set; but include stuff