These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / spi / spi-bitbang.c
index 840a498..3aa9e6e 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 
+#define SPI_BITBANG_CS_DELAY   100
+
 
 /*----------------------------------------------------------------------*/
 
@@ -180,7 +182,6 @@ int spi_bitbang_setup(struct spi_device *spi)
 {
        struct spi_bitbang_cs   *cs = spi->controller_state;
        struct spi_bitbang      *bitbang;
-       unsigned long           flags;
 
        bitbang = spi_master_get_devdata(spi->master);
 
@@ -210,12 +211,12 @@ int spi_bitbang_setup(struct spi_device *spi)
         */
 
        /* deselect chip (low or high) */
-       spin_lock_irqsave(&bitbang->lock, flags);
+       mutex_lock(&bitbang->lock);
        if (!bitbang->busy) {
                bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
                ndelay(cs->nsecs);
        }
-       spin_unlock_irqrestore(&bitbang->lock, flags);
+       mutex_unlock(&bitbang->lock);
 
        return 0;
 }
@@ -255,122 +256,39 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
 static int spi_bitbang_prepare_hardware(struct spi_master *spi)
 {
        struct spi_bitbang      *bitbang;
-       unsigned long           flags;
 
        bitbang = spi_master_get_devdata(spi);
 
-       spin_lock_irqsave(&bitbang->lock, flags);
+       mutex_lock(&bitbang->lock);
        bitbang->busy = 1;
-       spin_unlock_irqrestore(&bitbang->lock, flags);
+       mutex_unlock(&bitbang->lock);
 
        return 0;
 }
 
 static int spi_bitbang_transfer_one(struct spi_master *master,
-                                   struct spi_message *m)
+                                   struct spi_device *spi,
+                                   struct spi_transfer *transfer)
 {
-       struct spi_bitbang      *bitbang;
-       unsigned                nsecs;
-       struct spi_transfer     *t = NULL;
-       unsigned                cs_change;
-       int                     status;
-       int                     do_setup = -1;
-       struct spi_device       *spi = m->spi;
-
-       bitbang = spi_master_get_devdata(master);
-
-       /* FIXME this is made-up ... the correct value is known to
-        * word-at-a-time bitbang code, and presumably chipselect()
-        * should enforce these requirements too?
-        */
-       nsecs = 100;
-
-       cs_change = 1;
-       status = 0;
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-
-               /* override speed or wordsize? */
-               if (t->speed_hz || t->bits_per_word)
-                       do_setup = 1;
-
-               /* init (-1) or override (1) transfer params */
-               if (do_setup != 0) {
-                       if (bitbang->setup_transfer) {
-                               status = bitbang->setup_transfer(spi, t);
-                               if (status < 0)
-                                       break;
-                       }
-                       if (do_setup == -1)
-                               do_setup = 0;
-               }
-
-               /* set up default clock polarity, and activate chip;
-                * this implicitly updates clock and spi modes as
-                * previously recorded for this device via setup().
-                * (and also deselects any other chip that might be
-                * selected ...)
-                */
-               if (cs_change) {
-                       bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
-                       ndelay(nsecs);
-               }
-               cs_change = t->cs_change;
-               if (!t->tx_buf && !t->rx_buf && t->len) {
-                       status = -EINVAL;
-                       break;
-               }
-
-               /* transfer data.  the lower level code handles any
-                * new dma mappings it needs. our caller always gave
-                * us dma-safe buffers.
-                */
-               if (t->len) {
-                       /* REVISIT dma API still needs a designated
-                        * DMA_ADDR_INVALID; ~0 might be better.
-                        */
-                       if (!m->is_dma_mapped)
-                               t->rx_dma = t->tx_dma = 0;
-                       status = bitbang->txrx_bufs(spi, t);
-               }
-               if (status > 0)
-                       m->actual_length += status;
-               if (status != t->len) {
-                       /* always report some kind of error */
-                       if (status >= 0)
-                               status = -EREMOTEIO;
-                       break;
-               }
-               status = 0;
+       struct spi_bitbang *bitbang = spi_master_get_devdata(master);
+       int status = 0;
 
-               /* protocol tweaks before next transfer */
-               if (t->delay_usecs)
-                       udelay(t->delay_usecs);
-
-               if (cs_change &&
-                   !list_is_last(&t->transfer_list, &m->transfers)) {
-                       /* sometimes a short mid-message deselect of the chip
-                        * may be needed to terminate a mode or command
-                        */
-                       ndelay(nsecs);
-                       bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-                       ndelay(nsecs);
-               }
+       if (bitbang->setup_transfer) {
+               status = bitbang->setup_transfer(spi, transfer);
+               if (status < 0)
+                       goto out;
        }
 
-       m->status = status;
+       if (transfer->len)
+               status = bitbang->txrx_bufs(spi, transfer);
 
-       /* normally deactivate chipselect ... unless no error and
-        * cs_change has hinted that the next message will probably
-        * be for this chip too.
-        */
-       if (!(status == 0 && cs_change)) {
-               ndelay(nsecs);
-               bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
-               ndelay(nsecs);
-       }
+       if (status == transfer->len)
+               status = 0;
+       else if (status >= 0)
+               status = -EREMOTEIO;
 
-       spi_finalize_current_message(master);
+out:
+       spi_finalize_current_transfer(master);
 
        return status;
 }
@@ -378,17 +296,32 @@ static int spi_bitbang_transfer_one(struct spi_master *master,
 static int spi_bitbang_unprepare_hardware(struct spi_master *spi)
 {
        struct spi_bitbang      *bitbang;
-       unsigned long           flags;
 
        bitbang = spi_master_get_devdata(spi);
 
-       spin_lock_irqsave(&bitbang->lock, flags);
+       mutex_lock(&bitbang->lock);
        bitbang->busy = 0;
-       spin_unlock_irqrestore(&bitbang->lock, flags);
+       mutex_unlock(&bitbang->lock);
 
        return 0;
 }
 
+static void spi_bitbang_set_cs(struct spi_device *spi, bool enable)
+{
+       struct spi_bitbang *bitbang = spi_master_get_devdata(spi->master);
+
+       /* SPI core provides CS high / low, but bitbang driver
+        * expects CS active
+        * spi device driver takes care of handling SPI_CS_HIGH
+        */
+       enable = (!!(spi->mode & SPI_CS_HIGH) == enable);
+
+       ndelay(SPI_BITBANG_CS_DELAY);
+       bitbang->chipselect(spi, enable ? BITBANG_CS_ACTIVE :
+                           BITBANG_CS_INACTIVE);
+       ndelay(SPI_BITBANG_CS_DELAY);
+}
+
 /*----------------------------------------------------------------------*/
 
 /**
@@ -427,7 +360,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
        if (!master || !bitbang->chipselect)
                return -EINVAL;
 
-       spin_lock_init(&bitbang->lock);
+       mutex_init(&bitbang->lock);
 
        if (!master->mode_bits)
                master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
@@ -437,7 +370,8 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
 
        master->prepare_transfer_hardware = spi_bitbang_prepare_hardware;
        master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware;
-       master->transfer_one_message = spi_bitbang_transfer_one;
+       master->transfer_one = spi_bitbang_transfer_one;
+       master->set_cs = spi_bitbang_set_cs;
 
        if (!bitbang->txrx_bufs) {
                bitbang->use_dma = 0;