Merge tag 'soc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[linux-2.6-microblaze.git] / drivers / spi / spi-omap2-mcspi.c
index d3d62f1..3542fdc 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/err.h>
 
 #include <linux/spi/spi.h>
 
@@ -139,13 +141,6 @@ struct omap2_mcspi_cs {
        u32                     chconf0;
 };
 
-#define MOD_REG_BIT(val, mask, set) do { \
-       if (set) \
-               val |= mask; \
-       else \
-               val &= ~mask; \
-} while (0)
-
 static inline void mcspi_write_reg(struct spi_master *master,
                int idx, u32 val)
 {
@@ -204,7 +199,11 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
        else
                rw = OMAP2_MCSPI_CHCONF_DMAW;
 
-       MOD_REG_BIT(l, rw, enable);
+       if (enable)
+               l |= rw;
+       else
+               l &= ~rw;
+
        mcspi_write_chconf0(spi, l);
 }
 
@@ -223,7 +222,11 @@ static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
        u32 l;
 
        l = mcspi_cached_chconf0(spi);
-       MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
+       if (cs_active)
+               l |= OMAP2_MCSPI_CHCONF_FORCE;
+       else
+               l &= ~OMAP2_MCSPI_CHCONF_FORCE;
+
        mcspi_write_chconf0(spi, l);
 }
 
@@ -238,9 +241,8 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
         * to single-channel master mode
         */
        l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
-       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
-       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
-       MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
+       l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS);
+       l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
        mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
 
        ctx->modulctrl = l;
@@ -259,16 +261,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
        list_for_each_entry(cs, &ctx->cs, node)
                __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
 }
-static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi)
-{
-       pm_runtime_mark_last_busy(mcspi->dev);
-       pm_runtime_put_autosuspend(mcspi->dev);
-}
-
-static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
-{
-       return pm_runtime_get_sync(mcspi->dev);
-}
 
 static int omap2_prepare_transfer(struct spi_master *master)
 {
@@ -324,49 +316,27 @@ static void omap2_mcspi_tx_callback(void *data)
        omap2_mcspi_set_dma_req(spi, 0, 0);
 }
 
-static unsigned
-omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
+static void omap2_mcspi_tx_dma(struct spi_device *spi,
+                               struct spi_transfer *xfer,
+                               struct dma_slave_config cfg)
 {
        struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_cs   *cs = spi->controller_state;
        struct omap2_mcspi_dma  *mcspi_dma;
        unsigned int            count;
-       int                     word_len, element_count;
-       int                     elements = 0;
-       u32                     l;
        u8                      * rx;
        const u8                * tx;
        void __iomem            *chstat_reg;
-       struct dma_slave_config cfg;
-       enum dma_slave_buswidth width;
-       unsigned es;
+       struct omap2_mcspi_cs   *cs = spi->controller_state;
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
-       l = mcspi_cached_chconf0(spi);
+       count = xfer->len;
 
+       rx = xfer->rx_buf;
+       tx = xfer->tx_buf;
        chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
 
-       if (cs->word_len <= 8) {
-               width = DMA_SLAVE_BUSWIDTH_1_BYTE;
-               es = 1;
-       } else if (cs->word_len <= 16) {
-               width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-               es = 2;
-       } else {
-               width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-               es = 4;
-       }
-
-       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;
-
-       if (xfer->tx_buf && mcspi_dma->dma_tx) {
+       if (mcspi_dma->dma_tx) {
                struct dma_async_tx_descriptor *tx;
                struct scatterlist sg;
 
@@ -377,7 +347,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                sg_dma_len(&sg) = xfer->len;
 
                tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1,
-                       DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
                if (tx) {
                        tx->callback = omap2_mcspi_tx_callback;
                        tx->callback_param = spi;
@@ -386,8 +356,50 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                        /* FIXME: fall back to PIO? */
                }
        }
+       dma_async_issue_pending(mcspi_dma->dma_tx);
+       omap2_mcspi_set_dma_req(spi, 0, 1);
+
+       wait_for_completion(&mcspi_dma->dma_tx_completion);
+       dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
+                        DMA_TO_DEVICE);
+
+       /* 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)
+                       dev_err(&spi->dev, "EOT timed out\n");
+       }
+}
+
+static unsigned
+omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
+                               struct dma_slave_config cfg,
+                               unsigned es)
+{
+       struct omap2_mcspi      *mcspi;
+       struct omap2_mcspi_dma  *mcspi_dma;
+       unsigned int            count;
+       u32                     l;
+       int                     elements = 0;
+       int                     word_len, element_count;
+       struct omap2_mcspi_cs   *cs = spi->controller_state;
+       mcspi = spi_master_get_devdata(spi->master);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+       count = xfer->len;
+       word_len = cs->word_len;
+       l = mcspi_cached_chconf0(spi);
 
-       if (xfer->rx_buf && mcspi_dma->dma_rx) {
+       if (word_len <= 8)
+               element_count = count;
+       else if (word_len <= 16)
+               element_count = count >> 1;
+       else /* word_len <= 32 */
+               element_count = count >> 2;
+
+       if (mcspi_dma->dma_rx) {
                struct dma_async_tx_descriptor *tx;
                struct scatterlist sg;
                size_t len = xfer->len - es;
@@ -402,108 +414,120 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                sg_dma_len(&sg) = len;
 
                tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1,
-                       DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+                               DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
+                               DMA_CTRL_ACK);
                if (tx) {
                        tx->callback = omap2_mcspi_rx_callback;
                        tx->callback_param = spi;
                        dmaengine_submit(tx);
                } else {
-                       /* FIXME: fall back to PIO? */
-               }
-       }
-
-       count = xfer->len;
-       word_len = cs->word_len;
-
-       rx = xfer->rx_buf;
-       tx = xfer->tx_buf;
-
-       if (word_len <= 8) {
-               element_count = count;
-       } else if (word_len <= 16) {
-               element_count = count >> 1;
-       } else /* word_len <= 32 */ {
-               element_count = count >> 2;
-       }
-
-       if (tx != NULL) {
-               dma_async_issue_pending(mcspi_dma->dma_tx);
-               omap2_mcspi_set_dma_req(spi, 0, 1);
-       }
-
-       if (rx != NULL) {
-               dma_async_issue_pending(mcspi_dma->dma_rx);
-               omap2_mcspi_set_dma_req(spi, 1, 1);
-       }
-
-       if (tx != NULL) {
-               wait_for_completion(&mcspi_dma->dma_tx_completion);
-               dma_unmap_single(mcspi->dev, xfer->tx_dma, count,
-                                DMA_TO_DEVICE);
-
-               /* 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)
-                               dev_err(&spi->dev, "EOT timed out\n");
+                               /* FIXME: fall back to PIO? */
                }
        }
 
-       if (rx != NULL) {
-               wait_for_completion(&mcspi_dma->dma_rx_completion);
-               dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
-                                DMA_FROM_DEVICE);
-               omap2_mcspi_set_enable(spi, 0);
+       dma_async_issue_pending(mcspi_dma->dma_rx);
+       omap2_mcspi_set_dma_req(spi, 1, 1);
 
-               elements = element_count - 1;
+       wait_for_completion(&mcspi_dma->dma_rx_completion);
+       dma_unmap_single(mcspi->dev, xfer->rx_dma, count,
+                        DMA_FROM_DEVICE);
+       omap2_mcspi_set_enable(spi, 0);
 
-               if (l & OMAP2_MCSPI_CHCONF_TURBO) {
-                       elements--;
+       elements = element_count - 1;
 
-                       if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
-                                  & OMAP2_MCSPI_CHSTAT_RXS)) {
-                               u32 w;
-
-                               w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
-                               if (word_len <= 8)
-                                       ((u8 *)xfer->rx_buf)[elements++] = w;
-                               else if (word_len <= 16)
-                                       ((u16 *)xfer->rx_buf)[elements++] = w;
-                               else /* word_len <= 32 */
-                                       ((u32 *)xfer->rx_buf)[elements++] = w;
-                       } else {
-                               dev_err(&spi->dev,
-                                       "DMA RX penultimate word empty");
-                               count -= (word_len <= 8)  ? 2 :
-                                       (word_len <= 16) ? 4 :
-                                       /* word_len <= 32 */ 8;
-                               omap2_mcspi_set_enable(spi, 1);
-                               return count;
-                       }
-               }
+       if (l & OMAP2_MCSPI_CHCONF_TURBO) {
+               elements--;
 
                if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
-                               & OMAP2_MCSPI_CHSTAT_RXS)) {
+                                  & OMAP2_MCSPI_CHSTAT_RXS)) {
                        u32 w;
 
                        w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
                        if (word_len <= 8)
-                               ((u8 *)xfer->rx_buf)[elements] = w;
+                               ((u8 *)xfer->rx_buf)[elements++] = w;
                        else if (word_len <= 16)
-                               ((u16 *)xfer->rx_buf)[elements] = w;
+                               ((u16 *)xfer->rx_buf)[elements++] = w;
                        else /* word_len <= 32 */
-                               ((u32 *)xfer->rx_buf)[elements] = w;
+                               ((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;
+                       dev_err(&spi->dev, "DMA RX penultimate word empty");
+                       count -= (word_len <= 8)  ? 2 :
+                               (word_len <= 16) ? 4 :
+                               /* word_len <= 32 */ 8;
+                       omap2_mcspi_set_enable(spi, 1);
+                       return count;
                }
-               omap2_mcspi_set_enable(spi, 1);
        }
+       if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
+                               & OMAP2_MCSPI_CHSTAT_RXS)) {
+               u32 w;
+
+               w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
+               if (word_len <= 8)
+                       ((u8 *)xfer->rx_buf)[elements] = w;
+               else if (word_len <= 16)
+                       ((u16 *)xfer->rx_buf)[elements] = w;
+               else /* word_len <= 32 */
+                       ((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;
+       }
+       omap2_mcspi_set_enable(spi, 1);
+       return count;
+}
+
+static unsigned
+omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
+{
+       struct omap2_mcspi      *mcspi;
+       struct omap2_mcspi_cs   *cs = spi->controller_state;
+       struct omap2_mcspi_dma  *mcspi_dma;
+       unsigned int            count;
+       u32                     l;
+       u8                      *rx;
+       const u8                *tx;
+       struct dma_slave_config cfg;
+       enum dma_slave_buswidth width;
+       unsigned es;
+
+       mcspi = spi_master_get_devdata(spi->master);
+       mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+       l = mcspi_cached_chconf0(spi);
+
+
+       if (cs->word_len <= 8) {
+               width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+               es = 1;
+       } else if (cs->word_len <= 16) {
+               width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               es = 2;
+       } else {
+               width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               es = 4;
+       }
+
+       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;
+
+       rx = xfer->rx_buf;
+       tx = xfer->tx_buf;
+
+       count = xfer->len;
+
+       if (tx != NULL)
+               omap2_mcspi_tx_dma(spi, xfer, cfg);
+
+       if (rx != NULL)
+               return omap2_mcspi_rx_dma(spi, xfer, cfg, es);
+
        return count;
 }
 
@@ -847,12 +871,13 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                        return ret;
        }
 
-       ret = omap2_mcspi_enable_clocks(mcspi);
+       ret = pm_runtime_get_sync(mcspi->dev);
        if (ret < 0)
                return ret;
 
        ret = omap2_mcspi_setup_transfer(spi, NULL);
-       omap2_mcspi_disable_clocks(mcspi);
+       pm_runtime_mark_last_busy(mcspi->dev);
+       pm_runtime_put_autosuspend(mcspi->dev);
 
        return ret;
 }
@@ -1066,7 +1091,7 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
        struct omap2_mcspi_regs *ctx = &mcspi->ctx;
        int                     ret = 0;
 
-       ret = omap2_mcspi_enable_clocks(mcspi);
+       ret = pm_runtime_get_sync(mcspi->dev);
        if (ret < 0)
                return ret;
 
@@ -1075,7 +1100,8 @@ static int __devinit omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
        ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
 
        omap2_mcspi_set_master_mode(master);
-       omap2_mcspi_disable_clocks(mcspi);
+       pm_runtime_mark_last_busy(mcspi->dev);
+       pm_runtime_put_autosuspend(mcspi->dev);
        return 0;
 }
 
@@ -1115,7 +1141,7 @@ MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
 static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
 {
        struct spi_master       *master;
-       struct omap2_mcspi_platform_config *pdata;
+       const struct omap2_mcspi_platform_config *pdata;
        struct omap2_mcspi      *mcspi;
        struct resource         *r;
        int                     status = 0, i;
@@ -1123,6 +1149,7 @@ static int __devinit 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) {
@@ -1218,6 +1245,11 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
        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);
@@ -1237,7 +1269,6 @@ dma_chnl_free:
        kfree(mcspi->dma_channels);
 free_master:
        spi_master_put(master);
-       platform_set_drvdata(pdev, NULL);
        return status;
 }
 
@@ -1251,12 +1282,11 @@ static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
        mcspi = spi_master_get_devdata(master);
        dma_channels = mcspi->dma_channels;
 
-       omap2_mcspi_disable_clocks(mcspi);
+       pm_runtime_put_sync(mcspi->dev);
        pm_runtime_disable(&pdev->dev);
 
        spi_unregister_master(master);
        kfree(dma_channels);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
@@ -1277,20 +1307,21 @@ static int omap2_mcspi_resume(struct device *dev)
        struct omap2_mcspi_regs *ctx = &mcspi->ctx;
        struct omap2_mcspi_cs   *cs;
 
-       omap2_mcspi_enable_clocks(mcspi);
+       pm_runtime_get_sync(mcspi->dev);
        list_for_each_entry(cs, &ctx->cs, node) {
                if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
                        /*
                         * We need to toggle CS state for OMAP take this
                         * change in account.
                         */
-                       MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
+                       cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE;
                        __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
-                       MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
+                       cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
                        __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
                }
        }
-       omap2_mcspi_disable_clocks(mcspi);
+       pm_runtime_mark_last_busy(mcspi->dev);
+       pm_runtime_put_autosuspend(mcspi->dev);
        return 0;
 }
 #else