]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/spi/spi-omap2-mcspi.c
Merge tag 'arc-v3.11-rc1-part2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-artful-kernel.git] / drivers / spi / spi-omap2-mcspi.c
index 6246fb4557748c1264d806c4a10f1740fae0b7c9..5994039758debd91acd7fa1bd238cf3e85a8b790 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/pinctrl/consumer.h>
+#include <linux/gcd.h>
 
 #include <linux/spi/spi.h>
 
 #include <linux/platform_data/spi-omap2-mcspi.h>
 
 #define OMAP2_MCSPI_MAX_FREQ           48000000
+#define OMAP2_MCSPI_MAX_FIFODEPTH      64
+#define OMAP2_MCSPI_MAX_FIFOWCNT       0xFFFF
 #define SPI_AUTOSUSPEND_TIMEOUT                2000
 
 #define OMAP2_MCSPI_REVISION           0x00
@@ -54,6 +56,7 @@
 #define OMAP2_MCSPI_WAKEUPENABLE       0x20
 #define OMAP2_MCSPI_SYST               0x24
 #define OMAP2_MCSPI_MODULCTRL          0x28
+#define OMAP2_MCSPI_XFERLEVEL          0x7c
 
 /* per-channel banks, 0x14 bytes each, first is: */
 #define OMAP2_MCSPI_CHCONF0            0x2c
@@ -63,6 +66,7 @@
 #define OMAP2_MCSPI_RX0                        0x3c
 
 /* per-register bitmasks: */
+#define OMAP2_MCSPI_IRQSTATUS_EOW      BIT(17)
 
 #define OMAP2_MCSPI_MODULCTRL_SINGLE   BIT(0)
 #define OMAP2_MCSPI_MODULCTRL_MS       BIT(2)
 #define OMAP2_MCSPI_CHCONF_IS          BIT(18)
 #define OMAP2_MCSPI_CHCONF_TURBO       BIT(19)
 #define OMAP2_MCSPI_CHCONF_FORCE       BIT(20)
+#define OMAP2_MCSPI_CHCONF_FFET                BIT(27)
+#define OMAP2_MCSPI_CHCONF_FFER                BIT(28)
 
 #define OMAP2_MCSPI_CHSTAT_RXS         BIT(0)
 #define OMAP2_MCSPI_CHSTAT_TXS         BIT(1)
 #define OMAP2_MCSPI_CHSTAT_EOT         BIT(2)
+#define OMAP2_MCSPI_CHSTAT_TXFFE       BIT(3)
 
 #define OMAP2_MCSPI_CHCTRL_EN          BIT(0)
 
@@ -102,6 +109,9 @@ struct omap2_mcspi_dma {
 
        struct completion dma_tx_completion;
        struct completion dma_rx_completion;
+
+       char dma_rx_ch_name[14];
+       char dma_tx_ch_name[14];
 };
 
 /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
@@ -129,6 +139,7 @@ struct omap2_mcspi {
        struct omap2_mcspi_dma  *dma_channels;
        struct device           *dev;
        struct omap2_mcspi_regs ctx;
+       int                     fifo_depth;
        unsigned int            pin_dir:1;
 };
 
@@ -187,6 +198,16 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
        mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
 }
 
+static inline int mcspi_bytes_per_word(int word_len)
+{
+       if (word_len <= 8)
+               return 1;
+       else if (word_len <= 16)
+               return 2;
+       else /* word_len <= 32 */
+               return 4;
+}
+
 static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
                int is_read, int enable)
 {
@@ -248,6 +269,58 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
        ctx->modulctrl = l;
 }
 
+static void omap2_mcspi_set_fifo(const struct spi_device *spi,
+                               struct spi_transfer *t, int enable)
+{
+       struct spi_master *master = spi->master;
+       struct omap2_mcspi_cs *cs = spi->controller_state;
+       struct omap2_mcspi *mcspi;
+       unsigned int wcnt;
+       int fifo_depth, bytes_per_word;
+       u32 chconf, xferlevel;
+
+       mcspi = spi_master_get_devdata(master);
+
+       chconf = mcspi_cached_chconf0(spi);
+       if (enable) {
+               bytes_per_word = mcspi_bytes_per_word(cs->word_len);
+               if (t->len % bytes_per_word != 0)
+                       goto disable_fifo;
+
+               fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH);
+               if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0)
+                       goto disable_fifo;
+
+               wcnt = t->len / bytes_per_word;
+               if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
+                       goto disable_fifo;
+
+               xferlevel = wcnt << 16;
+               if (t->rx_buf != NULL) {
+                       chconf |= OMAP2_MCSPI_CHCONF_FFER;
+                       xferlevel |= (fifo_depth - 1) << 8;
+               } else {
+                       chconf |= OMAP2_MCSPI_CHCONF_FFET;
+                       xferlevel |= fifo_depth - 1;
+               }
+
+               mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
+               mcspi_write_chconf0(spi, chconf);
+               mcspi->fifo_depth = fifo_depth;
+
+               return;
+       }
+
+disable_fifo:
+       if (t->rx_buf != NULL)
+               chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
+       else
+               chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
+
+       mcspi_write_chconf0(spi, chconf);
+       mcspi->fifo_depth = 0;
+}
+
 static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
 {
        struct spi_master       *spi_cntrl = mcspi->master;
@@ -364,7 +437,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 {
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *mcspi_dma;
-       unsigned int            count;
+       unsigned int            count, dma_count;
        u32                     l;
        int                     elements = 0;
        int                     word_len, element_count;
@@ -372,6 +445,11 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
        count = xfer->len;
+       dma_count = xfer->len;
+
+       if (mcspi->fifo_depth == 0)
+               dma_count -= es;
+
        word_len = cs->word_len;
        l = mcspi_cached_chconf0(spi);
 
@@ -385,16 +463,15 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
        if (mcspi_dma->dma_rx) {
                struct dma_async_tx_descriptor *tx;
                struct scatterlist sg;
-               size_t len = xfer->len - es;
 
                dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
 
-               if (l & OMAP2_MCSPI_CHCONF_TURBO)
-                       len -= es;
+               if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
+                       dma_count -= es;
 
                sg_init_table(&sg, 1);
                sg_dma_address(&sg) = xfer->rx_dma;
-               sg_dma_len(&sg) = len;
+               sg_dma_len(&sg) = dma_count;
 
                tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
                                DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
@@ -414,6 +491,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
        wait_for_completion(&mcspi_dma->dma_rx_completion);
        dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
                         DMA_FROM_DEVICE);
+
+       if (mcspi->fifo_depth > 0)
+               return count;
+
        omap2_mcspi_set_enable(spi, 0);
 
        elements = element_count - 1;
@@ -433,10 +514,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
                        else /* word_len <= 32 */
                                ((u32 *)xfer->rx_buf)[elements++] = w;
                } else {
+                       int bytes_per_word = mcspi_bytes_per_word(word_len);
                        dev_err(&spi->dev, "DMA RX penultimate word empty");
-                       count -= (word_len <= 8)  ? 2 :
-                               (word_len <= 16) ? 4 :
-                               /* word_len <= 32 */ 8;
+                       count -= (bytes_per_word << 1);
                        omap2_mcspi_set_enable(spi, 1);
                        return count;
                }
@@ -454,9 +534,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
                        ((u32 *)xfer->rx_buf)[elements] = w;
        } else {
                dev_err(&spi->dev, "DMA RX last word empty");
-               count -= (word_len <= 8)  ? 1 :
-                        (word_len <= 16) ? 2 :
-                      /* word_len <= 32 */ 4;
+               count -= mcspi_bytes_per_word(word_len);
        }
        omap2_mcspi_set_enable(spi, 1);
        return count;
@@ -475,7 +553,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        struct dma_slave_config cfg;
        enum dma_slave_buswidth width;
        unsigned es;
+       u32                     burst;
        void __iomem            *chstat_reg;
+       void __iomem            *irqstat_reg;
+       int                     wait_res;
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -493,19 +574,27 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                es = 4;
        }
 
+       count = xfer->len;
+       burst = 1;
+
+       if (mcspi->fifo_depth > 0) {
+               if (count > mcspi->fifo_depth)
+                       burst = mcspi->fifo_depth / es;
+               else
+                       burst = count / es;
+       }
+
        memset(&cfg, 0, sizeof(cfg));
        cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
        cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
        cfg.src_addr_width = width;
        cfg.dst_addr_width = width;
-       cfg.src_maxburst = 1;
-       cfg.dst_maxburst = 1;
+       cfg.src_maxburst = burst;
+       cfg.dst_maxburst = burst;
 
        rx = xfer->rx_buf;
        tx = xfer->tx_buf;
 
-       count = xfer->len;
-
        if (tx != NULL)
                omap2_mcspi_tx_dma(spi, xfer, cfg);
 
@@ -513,18 +602,38 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
 
        if (tx != NULL) {
-               chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
                wait_for_completion(&mcspi_dma->dma_tx_completion);
                dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len,
                                 DMA_TO_DEVICE);
 
+               if (mcspi->fifo_depth > 0) {
+                       irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
+
+                       if (mcspi_wait_for_reg_bit(irqstat_reg,
+                                               OMAP2_MCSPI_IRQSTATUS_EOW) < 0)
+                               dev_err(&spi->dev, "EOW timed out\n");
+
+                       mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS,
+                                       OMAP2_MCSPI_IRQSTATUS_EOW);
+               }
+
                /* for TX_ONLY mode, be sure all words have shifted out */
                if (rx == NULL) {
-                       if (mcspi_wait_for_reg_bit(chstat_reg,
-                                               OMAP2_MCSPI_CHSTAT_TXS) < 0)
-                               dev_err(&spi->dev, "TXS timed out\n");
-                       else if (mcspi_wait_for_reg_bit(chstat_reg,
-                                               OMAP2_MCSPI_CHSTAT_EOT) < 0)
+                       chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
+                       if (mcspi->fifo_depth > 0) {
+                               wait_res = mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXFFE);
+                               if (wait_res < 0)
+                                       dev_err(&spi->dev, "TXFFE timed out\n");
+                       } else {
+                               wait_res = mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXS);
+                               if (wait_res < 0)
+                                       dev_err(&spi->dev, "TXS timed out\n");
+                       }
+                       if (wait_res >= 0 &&
+                               (mcspi_wait_for_reg_bit(chstat_reg,
+                                       OMAP2_MCSPI_CHSTAT_EOT) < 0))
                                dev_err(&spi->dev, "EOT timed out\n");
                }
        }
@@ -830,12 +939,20 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
        sig = mcspi_dma->dma_rx_sync_dev;
-       mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
+
+       mcspi_dma->dma_rx =
+               dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
+                                                &sig, &master->dev,
+                                                mcspi_dma->dma_rx_ch_name);
        if (!mcspi_dma->dma_rx)
                goto no_dma;
 
        sig = mcspi_dma->dma_tx_sync_dev;
-       mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
+       mcspi_dma->dma_tx =
+               dma_request_slave_channel_compat(mask, omap_dma_filter_fn,
+                                                &sig, &master->dev,
+                                                mcspi_dma->dma_tx_ch_name);
+
        if (!mcspi_dma->dma_tx) {
                dma_release_channel(mcspi_dma->dma_rx);
                mcspi_dma->dma_rx = NULL;
@@ -945,7 +1062,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
        cs = spi->controller_state;
        cd = spi->controller_data;
 
-       omap2_mcspi_set_enable(spi, 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;
@@ -993,6 +1110,12 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
                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);
+
+                       omap2_mcspi_set_enable(spi, 1);
+
                        /* RX_ONLY mode needs dummy data in TX reg */
                        if (t->tx_buf == NULL)
                                __raw_writel(0, cs->base
@@ -1019,6 +1142,11 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
                        omap2_mcspi_force_cs(spi, 0);
                        cs_active = 0;
                }
+
+               omap2_mcspi_set_enable(spi, 0);
+
+               if (mcspi->fifo_depth > 0)
+                       omap2_mcspi_set_fifo(spi, t, 0);
        }
        /* Restore defaults if they were overriden */
        if (par_override) {
@@ -1039,8 +1167,10 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
 
        omap2_mcspi_set_enable(spi, 0);
 
-       m->status = status;
+       if (mcspi->fifo_depth > 0 && t)
+               omap2_mcspi_set_fifo(spi, t, 0);
 
+       m->status = status;
 }
 
 static int omap2_mcspi_transfer_one_message(struct spi_master *master,
@@ -1177,7 +1307,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        static int              bus_num = 1;
        struct device_node      *node = pdev->dev.of_node;
        const struct of_device_id *match;
-       struct pinctrl *pinctrl;
 
        master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
        if (master == NULL) {
@@ -1195,7 +1324,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        master->cleanup = omap2_mcspi_cleanup;
        master->dev.of_node = node;
 
-       dev_set_drvdata(&pdev->dev, master);
+       platform_set_drvdata(pdev, master);
 
        mcspi = spi_master_get_devdata(master);
        mcspi->master = master;
@@ -1247,39 +1376,47 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
                goto free_master;
 
        for (i = 0; i < master->num_chipselect; i++) {
-               char dma_ch_name[14];
+               char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name;
+               char *dma_tx_ch_name = mcspi->dma_channels[i].dma_tx_ch_name;
                struct resource *dma_res;
 
-               sprintf(dma_ch_name, "rx%d", i);
-               dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-                               dma_ch_name);
-               if (!dma_res) {
-                       dev_dbg(&pdev->dev, "cannot get DMA RX channel\n");
-                       status = -ENODEV;
-                       break;
-               }
+               sprintf(dma_rx_ch_name, "rx%d", i);
+               if (!pdev->dev.of_node) {
+                       dma_res =
+                               platform_get_resource_byname(pdev,
+                                                            IORESOURCE_DMA,
+                                                            dma_rx_ch_name);
+                       if (!dma_res) {
+                               dev_dbg(&pdev->dev,
+                                       "cannot get DMA RX channel\n");
+                               status = -ENODEV;
+                               break;
+                       }
 
-               mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start;
-               sprintf(dma_ch_name, "tx%d", i);
-               dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
-                               dma_ch_name);
-               if (!dma_res) {
-                       dev_dbg(&pdev->dev, "cannot get DMA TX channel\n");
-                       status = -ENODEV;
-                       break;
+                       mcspi->dma_channels[i].dma_rx_sync_dev =
+                               dma_res->start;
                }
+               sprintf(dma_tx_ch_name, "tx%d", i);
+               if (!pdev->dev.of_node) {
+                       dma_res =
+                               platform_get_resource_byname(pdev,
+                                                            IORESOURCE_DMA,
+                                                            dma_tx_ch_name);
+                       if (!dma_res) {
+                               dev_dbg(&pdev->dev,
+                                       "cannot get DMA TX channel\n");
+                               status = -ENODEV;
+                               break;
+                       }
 
-               mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start;
+                       mcspi->dma_channels[i].dma_tx_sync_dev =
+                               dma_res->start;
+               }
        }
 
        if (status < 0)
                goto dma_chnl_free;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl))
-               dev_warn(&pdev->dev,
-                               "pins are not configured from the driver\n");
-
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
        pm_runtime_enable(&pdev->dev);
@@ -1309,7 +1446,7 @@ static int omap2_mcspi_remove(struct platform_device *pdev)
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *dma_channels;
 
-       master = dev_get_drvdata(&pdev->dev);
+       master = platform_get_drvdata(pdev);
        mcspi = spi_master_get_devdata(master);
        dma_channels = mcspi->dma_channels;