These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / spi / spi-omap2-mcspi.c
index d1a5b9f..ed8283e 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/gcd.h>
 
 #include <linux/spi/spi.h>
+#include <linux/gpio.h>
 
 #include <linux/platform_data/spi-omap2-mcspi.h>
 
@@ -242,17 +243,37 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
        mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
 }
 
-static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
+static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
 {
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
        u32 l;
 
-       l = mcspi_cached_chconf0(spi);
-       if (cs_active)
-               l |= OMAP2_MCSPI_CHCONF_FORCE;
-       else
-               l &= ~OMAP2_MCSPI_CHCONF_FORCE;
+       /* The controller handles the inverted chip selects
+        * using the OMAP2_MCSPI_CHCONF_EPOL bit so revert
+        * the inversion from the core spi_set_cs function.
+        */
+       if (spi->mode & SPI_CS_HIGH)
+               enable = !enable;
 
-       mcspi_write_chconf0(spi, l);
+       if (spi->controller_state) {
+               int err = pm_runtime_get_sync(mcspi->dev);
+               if (err < 0) {
+                       dev_err(mcspi->dev, "failed to get sync: %d\n", err);
+                       return;
+               }
+
+               l = mcspi_cached_chconf0(spi);
+
+               if (enable)
+                       l &= ~OMAP2_MCSPI_CHCONF_FORCE;
+               else
+                       l |= OMAP2_MCSPI_CHCONF_FORCE;
+
+               mcspi_write_chconf0(spi, l);
+
+               pm_runtime_mark_last_busy(mcspi->dev);
+               pm_runtime_put_autosuspend(mcspi->dev);
+       }
 }
 
 static void omap2_mcspi_set_master_mode(struct spi_master *master)
@@ -1003,6 +1024,16 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                spi->controller_state = cs;
                /* Link this to context save list */
                list_add_tail(&cs->node, &ctx->cs);
+
+               if (gpio_is_valid(spi->cs_gpio)) {
+                       ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev));
+                       if (ret) {
+                               dev_err(&spi->dev, "failed to request gpio\n");
+                               return ret;
+                       }
+                       gpio_direction_output(spi->cs_gpio,
+                                        !(spi->mode & SPI_CS_HIGH));
+               }
        }
 
        if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
@@ -1050,9 +1081,13 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
                        mcspi_dma->dma_tx = NULL;
                }
        }
+
+       if (gpio_is_valid(spi->cs_gpio))
+               gpio_free(spi->cs_gpio);
 }
 
-static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
+static int omap2_mcspi_work_one(struct omap2_mcspi *mcspi,
+               struct spi_device *spi, struct spi_transfer *t)
 {
 
        /* We only enable one channel at a time -- the one whose message is
@@ -1062,18 +1097,14 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
         * chipselect with the FORCE bit ... CS != channel enable.
         */
 
-       struct spi_device               *spi;
-       struct spi_transfer             *t = NULL;
        struct spi_master               *master;
        struct omap2_mcspi_dma          *mcspi_dma;
-       int                             cs_active = 0;
        struct omap2_mcspi_cs           *cs;
        struct omap2_mcspi_device_config *cd;
        int                             par_override = 0;
        int                             status = 0;
        u32                             chconf;
 
-       spi = m->spi;
        master = spi->master;
        mcspi_dma = mcspi->dma_channels + spi->chip_select;
        cs = spi->controller_state;
@@ -1090,103 +1121,84 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
                par_override = 1;
 
        omap2_mcspi_set_enable(spi, 0);
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-                       status = -EINVAL;
-                       break;
-               }
-               if (par_override ||
-                   (t->speed_hz != spi->max_speed_hz) ||
-                   (t->bits_per_word != spi->bits_per_word)) {
-                       par_override = 1;
-                       status = omap2_mcspi_setup_transfer(spi, t);
-                       if (status < 0)
-                               break;
-                       if (t->speed_hz == spi->max_speed_hz &&
-                           t->bits_per_word == spi->bits_per_word)
-                               par_override = 0;
-               }
-               if (cd && cd->cs_per_word) {
-                       chconf = mcspi->ctx.modulctrl;
-                       chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
-                       mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
-                       mcspi->ctx.modulctrl =
-                               mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
-               }
 
+       if (gpio_is_valid(spi->cs_gpio))
+               omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH);
 
-               if (!cs_active) {
-                       omap2_mcspi_force_cs(spi, 1);
-                       cs_active = 1;
-               }
-
-               chconf = mcspi_cached_chconf0(spi);
-               chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
-               chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+       if (par_override ||
+           (t->speed_hz != spi->max_speed_hz) ||
+           (t->bits_per_word != spi->bits_per_word)) {
+               par_override = 1;
+               status = omap2_mcspi_setup_transfer(spi, t);
+               if (status < 0)
+                       goto out;
+               if (t->speed_hz == spi->max_speed_hz &&
+                   t->bits_per_word == spi->bits_per_word)
+                       par_override = 0;
+       }
+       if (cd && cd->cs_per_word) {
+               chconf = mcspi->ctx.modulctrl;
+               chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
+               mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
+               mcspi->ctx.modulctrl =
+                       mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
+       }
 
-               if (t->tx_buf == NULL)
-                       chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
-               else if (t->rx_buf == NULL)
-                       chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
-
-               if (cd && cd->turbo_mode && t->tx_buf == NULL) {
-                       /* Turbo mode is for more than one word */
-                       if (t->len > ((cs->word_len + 7) >> 3))
-                               chconf |= OMAP2_MCSPI_CHCONF_TURBO;
-               }
+       chconf = mcspi_cached_chconf0(spi);
+       chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+       chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+
+       if (t->tx_buf == NULL)
+               chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+       else if (t->rx_buf == NULL)
+               chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+
+       if (cd && cd->turbo_mode && t->tx_buf == NULL) {
+               /* Turbo mode is for more than one word */
+               if (t->len > ((cs->word_len + 7) >> 3))
+                       chconf |= OMAP2_MCSPI_CHCONF_TURBO;
+       }
 
-               mcspi_write_chconf0(spi, chconf);
+       mcspi_write_chconf0(spi, chconf);
 
-               if (t->len) {
-                       unsigned        count;
+       if (t->len) {
+               unsigned        count;
 
-                       if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-                           (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
-                               omap2_mcspi_set_fifo(spi, t, 1);
+               if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+                   (t->len >= DMA_MIN_BYTES))
+                       omap2_mcspi_set_fifo(spi, t, 1);
 
-                       omap2_mcspi_set_enable(spi, 1);
+               omap2_mcspi_set_enable(spi, 1);
 
-                       /* RX_ONLY mode needs dummy data in TX reg */
-                       if (t->tx_buf == NULL)
-                               writel_relaxed(0, cs->base
-                                               + OMAP2_MCSPI_TX0);
+               /* RX_ONLY mode needs dummy data in TX reg */
+               if (t->tx_buf == NULL)
+                       writel_relaxed(0, cs->base
+                                       + OMAP2_MCSPI_TX0);
 
-                       if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
-                           (m->is_dma_mapped || t->len >= DMA_MIN_BYTES))
-                               count = omap2_mcspi_txrx_dma(spi, t);
-                       else
-                               count = omap2_mcspi_txrx_pio(spi, t);
-                       m->actual_length += count;
+               if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
+                   (t->len >= DMA_MIN_BYTES))
+                       count = omap2_mcspi_txrx_dma(spi, t);
+               else
+                       count = omap2_mcspi_txrx_pio(spi, t);
 
-                       if (count != t->len) {
-                               status = -EIO;
-                               break;
-                       }
+               if (count != t->len) {
+                       status = -EIO;
+                       goto out;
                }
+       }
 
-               if (t->delay_usecs)
-                       udelay(t->delay_usecs);
-
-               /* ignore the "leave it on after last xfer" hint */
-               if (t->cs_change) {
-                       omap2_mcspi_force_cs(spi, 0);
-                       cs_active = 0;
-               }
+       omap2_mcspi_set_enable(spi, 0);
 
-               omap2_mcspi_set_enable(spi, 0);
+       if (mcspi->fifo_depth > 0)
+               omap2_mcspi_set_fifo(spi, t, 0);
 
-               if (mcspi->fifo_depth > 0)
-                       omap2_mcspi_set_fifo(spi, t, 0);
-       }
+out:
        /* Restore defaults if they were overriden */
        if (par_override) {
                par_override = 0;
                status = omap2_mcspi_setup_transfer(spi, NULL);
        }
 
-       if (cs_active)
-               omap2_mcspi_force_cs(spi, 0);
-
        if (cd && cd->cs_per_word) {
                chconf = mcspi->ctx.modulctrl;
                chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
@@ -1197,78 +1209,91 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
 
        omap2_mcspi_set_enable(spi, 0);
 
+       if (gpio_is_valid(spi->cs_gpio))
+               omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH));
+
        if (mcspi->fifo_depth > 0 && t)
                omap2_mcspi_set_fifo(spi, t, 0);
 
-       m->status = status;
+       return status;
 }
 
-static int omap2_mcspi_transfer_one_message(struct spi_master *master,
-               struct spi_message *m)
+static int omap2_mcspi_prepare_message(struct spi_master *master,
+                                      struct spi_message *msg)
+{
+       struct omap2_mcspi      *mcspi = spi_master_get_devdata(master);
+       struct omap2_mcspi_regs *ctx = &mcspi->ctx;
+       struct omap2_mcspi_cs   *cs;
+
+       /* Only a single channel can have the FORCE bit enabled
+        * in its chconf0 register.
+        * Scan all channels and disable them except the current one.
+        * A FORCE can remain from a last transfer having cs_change enabled
+        */
+       list_for_each_entry(cs, &ctx->cs, node) {
+               if (msg->spi->controller_state == cs)
+                       continue;
+
+               if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) {
+                       cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
+                       writel_relaxed(cs->chconf0,
+                                       cs->base + OMAP2_MCSPI_CHCONF0);
+                       readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0);
+               }
+       }
+
+       return 0;
+}
+
+static int omap2_mcspi_transfer_one(struct spi_master *master,
+               struct spi_device *spi, struct spi_transfer *t)
 {
-       struct spi_device       *spi;
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *mcspi_dma;
-       struct spi_transfer     *t;
-       int status;
+       const void      *tx_buf = t->tx_buf;
+       void            *rx_buf = t->rx_buf;
+       unsigned        len = t->len;
 
-       spi = m->spi;
        mcspi = spi_master_get_devdata(master);
        mcspi_dma = mcspi->dma_channels + spi->chip_select;
-       m->actual_length = 0;
-       m->status = 0;
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               const void      *tx_buf = t->tx_buf;
-               void            *rx_buf = t->rx_buf;
-               unsigned        len = t->len;
-
-               if ((len && !(rx_buf || tx_buf))) {
-                       dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
-                                       t->speed_hz,
-                                       len,
-                                       tx_buf ? "tx" : "",
-                                       rx_buf ? "rx" : "",
-                                       t->bits_per_word);
-                       status = -EINVAL;
-                       goto out;
-               }
 
-               if (m->is_dma_mapped || len < DMA_MIN_BYTES)
-                       continue;
+       if ((len && !(rx_buf || tx_buf))) {
+               dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
+                               t->speed_hz,
+                               len,
+                               tx_buf ? "tx" : "",
+                               rx_buf ? "rx" : "",
+                               t->bits_per_word);
+               return -EINVAL;
+       }
 
-               if (mcspi_dma->dma_tx && tx_buf != NULL) {
-                       t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
-                                       len, DMA_TO_DEVICE);
-                       if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
-                               dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
-                                               'T', len);
-                               status = -EINVAL;
-                               goto out;
-                       }
+       if (len < DMA_MIN_BYTES)
+               goto skip_dma_map;
+
+       if (mcspi_dma->dma_tx && tx_buf != NULL) {
+               t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
+                               len, DMA_TO_DEVICE);
+               if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
+                       dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
+                                       'T', len);
+                       return -EINVAL;
                }
-               if (mcspi_dma->dma_rx && rx_buf != NULL) {
-                       t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
-                                       DMA_FROM_DEVICE);
-                       if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
-                               dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
-                                               'R', len);
-                               if (tx_buf != NULL)
-                                       dma_unmap_single(mcspi->dev, t->tx_dma,
-                                                       len, DMA_TO_DEVICE);
-                               status = -EINVAL;
-                               goto out;
-                       }
+       }
+       if (mcspi_dma->dma_rx && rx_buf != NULL) {
+               t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
+                               DMA_FROM_DEVICE);
+               if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
+                       dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
+                                       'R', len);
+                       if (tx_buf != NULL)
+                               dma_unmap_single(mcspi->dev, t->tx_dma,
+                                               len, DMA_TO_DEVICE);
+                       return -EINVAL;
                }
        }
 
-       omap2_mcspi_work(mcspi, m);
-       /* spi_finalize_current_message() changes the status inside the
-        * spi_message, save the status here. */
-       status = m->status;
-out:
-       spi_finalize_current_message(master);
-       return status;
+skip_dma_map:
+       return omap2_mcspi_work_one(mcspi, spi, t);
 }
 
 static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
@@ -1347,7 +1372,9 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
        master->setup = omap2_mcspi_setup;
        master->auto_runtime_pm = true;
-       master->transfer_one_message = omap2_mcspi_transfer_one_message;
+       master->prepare_message = omap2_mcspi_prepare_message;
+       master->transfer_one = omap2_mcspi_transfer_one;
+       master->set_cs = omap2_mcspi_set_cs;
        master->cleanup = omap2_mcspi_cleanup;
        master->dev.of_node = node;
        master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;