Merge branch 'dmaengine' of git://git.linaro.org/people/rmk/linux-arm
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / spi / spi-omap2-mcspi.c
index 7d46b15e1520d0613b02cca28a5206f5123db4db..bc4778175e343c6a9ebeceac09b0cc543c935bc2 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/omap-dma.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
 #include <linux/clk.h>
@@ -39,7 +41,6 @@
 
 #include <linux/spi/spi.h>
 
-#include <plat/dma.h>
 #include <plat/clock.h>
 #include <plat/mcspi.h>
 
@@ -93,8 +94,8 @@
 
 /* We have 2 DMA channels per CS, one for RX and one for TX */
 struct omap2_mcspi_dma {
-       int dma_tx_channel;
-       int dma_rx_channel;
+       struct dma_chan *dma_tx;
+       struct dma_chan *dma_rx;
 
        int dma_tx_sync_dev;
        int dma_rx_sync_dev;
@@ -300,20 +301,46 @@ static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
        return 0;
 }
 
+static void omap2_mcspi_rx_callback(void *data)
+{
+       struct spi_device *spi = data;
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+       struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       complete(&mcspi_dma->dma_rx_completion);
+
+       /* We must disable the DMA RX request */
+       omap2_mcspi_set_dma_req(spi, 1, 0);
+}
+
+static void omap2_mcspi_tx_callback(void *data)
+{
+       struct spi_device *spi = data;
+       struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+       struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+       complete(&mcspi_dma->dma_tx_completion);
+
+       /* We must disable the DMA TX request */
+       omap2_mcspi_set_dma_req(spi, 0, 0);
+}
+
 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, c;
-       unsigned long           base, tx_reg, rx_reg;
-       int                     word_len, data_type, element_count;
+       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;
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -321,68 +348,92 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 
        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) {
+               struct dma_async_tx_descriptor *tx;
+               struct scatterlist sg;
+
+               dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
+
+               sg_init_table(&sg, 1);
+               sg_dma_address(&sg) = xfer->tx_dma;
+               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);
+               if (tx) {
+                       tx->callback = omap2_mcspi_tx_callback;
+                       tx->callback_param = spi;
+                       dmaengine_submit(tx);
+               } else {
+                       /* FIXME: fall back to PIO? */
+               }
+       }
+
+       if (xfer->rx_buf && 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;
+
+               sg_init_table(&sg, 1);
+               sg_dma_address(&sg) = xfer->rx_dma;
+               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);
+               if (tx) {
+                       tx->callback = omap2_mcspi_rx_callback;
+                       tx->callback_param = spi;
+                       dmaengine_submit(tx);
+               } else {
+                       /* FIXME: fall back to PIO? */
+               }
+       }
+
        count = xfer->len;
-       c = count;
        word_len = cs->word_len;
 
-       base = cs->phys;
-       tx_reg = base + OMAP2_MCSPI_TX0;
-       rx_reg = base + OMAP2_MCSPI_RX0;
        rx = xfer->rx_buf;
        tx = xfer->tx_buf;
 
        if (word_len <= 8) {
-               data_type = OMAP_DMA_DATA_TYPE_S8;
                element_count = count;
        } else if (word_len <= 16) {
-               data_type = OMAP_DMA_DATA_TYPE_S16;
                element_count = count >> 1;
        } else /* word_len <= 32 */ {
-               data_type = OMAP_DMA_DATA_TYPE_S32;
                element_count = count >> 2;
        }
 
        if (tx != NULL) {
-               omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
-                               data_type, element_count, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               mcspi_dma->dma_tx_sync_dev, 0);
-
-               omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               tx_reg, 0, 0);
-
-               omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC,
-                               xfer->tx_dma, 0, 0);
-       }
-
-       if (rx != NULL) {
-               elements = element_count - 1;
-               if (l & OMAP2_MCSPI_CHCONF_TURBO)
-                       elements--;
-
-               omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
-                               data_type, elements, 1,
-                               OMAP_DMA_SYNC_ELEMENT,
-                               mcspi_dma->dma_rx_sync_dev, 1);
-
-               omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0,
-                               OMAP_DMA_AMODE_CONSTANT,
-                               rx_reg, 0, 0);
-
-               omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0,
-                               OMAP_DMA_AMODE_POST_INC,
-                               xfer->rx_dma, 0, 0);
-       }
-
-       if (tx != NULL) {
-               omap_start_dma(mcspi_dma->dma_tx_channel);
+               dma_async_issue_pending(mcspi_dma->dma_tx);
                omap2_mcspi_set_dma_req(spi, 0, 1);
        }
 
        if (rx != NULL) {
-               omap_start_dma(mcspi_dma->dma_rx_channel);
+               dma_async_issue_pending(mcspi_dma->dma_rx);
                omap2_mcspi_set_dma_req(spi, 1, 1);
        }
 
@@ -408,7 +459,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
                                 DMA_FROM_DEVICE);
                omap2_mcspi_set_enable(spi, 0);
 
+               elements = element_count - 1;
+
                if (l & OMAP2_MCSPI_CHCONF_TURBO) {
+                       elements--;
 
                        if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
                                   & OMAP2_MCSPI_CHSTAT_RXS)) {
@@ -725,64 +779,38 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
        return 0;
 }
 
-static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
-{
-       struct spi_device       *spi = data;
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
-
-       mcspi = spi_master_get_devdata(spi->master);
-       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
-
-       complete(&mcspi_dma->dma_rx_completion);
-
-       /* We must disable the DMA RX request */
-       omap2_mcspi_set_dma_req(spi, 1, 0);
-}
-
-static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
-{
-       struct spi_device       *spi = data;
-       struct omap2_mcspi      *mcspi;
-       struct omap2_mcspi_dma  *mcspi_dma;
-
-       mcspi = spi_master_get_devdata(spi->master);
-       mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
-
-       complete(&mcspi_dma->dma_tx_completion);
-
-       /* We must disable the DMA TX request */
-       omap2_mcspi_set_dma_req(spi, 0, 0);
-}
-
 static int omap2_mcspi_request_dma(struct spi_device *spi)
 {
        struct spi_master       *master = spi->master;
        struct omap2_mcspi      *mcspi;
        struct omap2_mcspi_dma  *mcspi_dma;
+       dma_cap_mask_t mask;
+       unsigned sig;
 
        mcspi = spi_master_get_devdata(master);
        mcspi_dma = mcspi->dma_channels + spi->chip_select;
 
-       if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
-                       omap2_mcspi_dma_rx_callback, spi,
-                       &mcspi_dma->dma_rx_channel)) {
-               dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
+       init_completion(&mcspi_dma->dma_rx_completion);
+       init_completion(&mcspi_dma->dma_tx_completion);
+
+       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);
+       if (!mcspi_dma->dma_rx) {
+               dev_err(&spi->dev, "no RX DMA engine channel for McSPI\n");
                return -EAGAIN;
        }
 
-       if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
-                       omap2_mcspi_dma_tx_callback, spi,
-                       &mcspi_dma->dma_tx_channel)) {
-               omap_free_dma(mcspi_dma->dma_rx_channel);
-               mcspi_dma->dma_rx_channel = -1;
-               dev_err(&spi->dev, "no TX DMA channel for McSPI\n");
+       sig = mcspi_dma->dma_tx_sync_dev;
+       mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
+       if (!mcspi_dma->dma_tx) {
+               dev_err(&spi->dev, "no TX DMA engine channel for McSPI\n");
+               dma_release_channel(mcspi_dma->dma_rx);
+               mcspi_dma->dma_rx = NULL;
                return -EAGAIN;
        }
 
-       init_completion(&mcspi_dma->dma_rx_completion);
-       init_completion(&mcspi_dma->dma_tx_completion);
-
        return 0;
 }
 
@@ -814,8 +842,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
                list_add_tail(&cs->node, &ctx->cs);
        }
 
-       if (mcspi_dma->dma_rx_channel == -1
-                       || mcspi_dma->dma_tx_channel == -1) {
+       if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) {
                ret = omap2_mcspi_request_dma(spi);
                if (ret < 0)
                        return ret;
@@ -850,13 +877,13 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
        if (spi->chip_select < spi->master->num_chipselect) {
                mcspi_dma = &mcspi->dma_channels[spi->chip_select];
 
-               if (mcspi_dma->dma_rx_channel != -1) {
-                       omap_free_dma(mcspi_dma->dma_rx_channel);
-                       mcspi_dma->dma_rx_channel = -1;
+               if (mcspi_dma->dma_rx) {
+                       dma_release_channel(mcspi_dma->dma_rx);
+                       mcspi_dma->dma_rx = NULL;
                }
-               if (mcspi_dma->dma_tx_channel != -1) {
-                       omap_free_dma(mcspi_dma->dma_tx_channel);
-                       mcspi_dma->dma_tx_channel = -1;
+               if (mcspi_dma->dma_tx) {
+                       dma_release_channel(mcspi_dma->dma_tx);
+                       mcspi_dma->dma_tx = NULL;
                }
        }
 }
@@ -1176,7 +1203,6 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
                        break;
                }
 
-               mcspi->dma_channels[i].dma_rx_channel = -1;
                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,
@@ -1187,7 +1213,6 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
                        break;
                }
 
-               mcspi->dma_channels[i].dma_tx_channel = -1;
                mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start;
        }