Use dma_slave_config to dynamically set dma channel for each dma transaction,
also use the dma device's device_prep_slave_sg() callback instead of the
device_prep_dma_memcpy().

Signed-off-by: Feng Tang <[email protected]>
---
 drivers/spi/dw_spi_mid.c   |  125 +++++++++++++++++++++-----------------------
 include/linux/spi/dw_spi.h |    4 +-
 2 files changed, 63 insertions(+), 66 deletions(-)

diff --git a/drivers/spi/dw_spi_mid.c b/drivers/spi/dw_spi_mid.c
index 091e80b..3a61e96 100644
--- a/drivers/spi/dw_spi_mid.c
+++ b/drivers/spi/dw_spi_mid.c
@@ -34,17 +34,12 @@ struct mid_dma {
 
 static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
 {
-       struct dw_spi *dws = (struct dw_spi *)param;
-       bool ret = false;
+       struct dw_spi *dws = param;
 
-       if (!dws->dmac)
-               goto out;
-
-       if (chan->device->dev == &dws->dmac->dev)
-               ret = true;
-
-out:
-       return ret;
+       if (dws->dmac && &dws->dmac->dev == chan->device->dev)
+               return true;
+       else
+               return false;
 }
 
 static int mid_spi_dma_init(struct dw_spi *dws)
@@ -53,52 +48,31 @@ static int mid_spi_dma_init(struct dw_spi *dws)
        struct intel_mid_dma_slave *rxs, *txs;
        dma_cap_mask_t mask;
 
-       dws->txchan = NULL;
-       dws->rxchan = NULL;
-
-       /*get pci device for DMA*/
+       /* Get pci device for DMA*/
        dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x813, NULL);
 
-       /* 1. Init rx channel */
-       rxs = &dw_dma->dmas_rx;
-
-       rxs->dirn = DMA_FROM_DEVICE;
-       rxs->hs_mode = LNW_DMA_HW_HS;
-       rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
-       rxs->src_width = LNW_DMA_WIDTH_16BIT;
-       rxs->dst_width = LNW_DMA_WIDTH_32BIT;
-       rxs->src_msize = LNW_DMA_MSIZE_16;
-       rxs->dst_msize = LNW_DMA_MSIZE_16;
-
        dma_cap_zero(mask);
-       dma_cap_set(DMA_MEMCPY, mask);
        dma_cap_set(DMA_SLAVE, mask);
 
+       /* 1. Init rx channel */
        dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
        if (!dws->rxchan)
                goto err_exit;
+
+       rxs = &dw_dma->dmas_rx;
+       rxs->hs_mode = LNW_DMA_HW_HS;
+       rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
        dws->rxchan->private = rxs;
 
        /* 2. Init tx channel */
-       txs = &dw_dma->dmas_tx;
-
-       txs->dirn = DMA_TO_DEVICE;
-       txs->hs_mode = LNW_DMA_HW_HS;
-       txs->cfg_mode = LNW_DMA_MEM_TO_PER;
-       txs->src_width = LNW_DMA_WIDTH_32BIT;
-       txs->dst_width = LNW_DMA_WIDTH_16BIT;
-       txs->src_msize = LNW_DMA_MSIZE_16;
-       txs->dst_msize = LNW_DMA_MSIZE_16;
-
-       dma_cap_set(DMA_SLAVE, mask);
-       dma_cap_set(DMA_MEMCPY, mask);
-
        dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
        if (!dws->txchan)
                goto free_rxchan;
+       txs = &dw_dma->dmas_tx;
+       txs->hs_mode = LNW_DMA_HW_HS;
+       txs->cfg_mode = LNW_DMA_MEM_TO_PER;
        dws->txchan->private = txs;
 
-       /* Set the dma done bit to 1 */
        dws->dma_inited = 1;
        return 0;
 
@@ -133,7 +107,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int 
cs_change)
 {
        struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
        struct dma_chan *txchan, *rxchan;
-       enum dma_ctrl_flags flag;
+       struct dma_slave_config txconf, rxconf;
        u16 dma_ctrl = 0;
 
        /* 1. setup DMA related registers */
@@ -150,35 +124,56 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int 
cs_change)
        }
 
        dws->dma_chan_done = 0;
-
-       /* 2. start the TX dma transfer */
        txchan = dws->txchan;
        rxchan = dws->rxchan;
 
-       flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
-       if (dws->tx_dma) {
-               txdesc = txchan->device->device_prep_dma_memcpy(txchan,
-                               dws->dma_addr, dws->tx_dma,
-                               dws->len, flag);
-               txdesc->callback = dw_spi_dma_done;
-               txdesc->callback_param = dws;
-       }
-
-       /* 3. start the RX dma transfer */
-       if (dws->rx_dma) {
-               rxdesc = rxchan->device->device_prep_dma_memcpy(rxchan,
-                               dws->rx_dma, dws->dma_addr,
-                               dws->len, flag);
-               rxdesc->callback = dw_spi_dma_done;
-               rxdesc->callback_param = dws;
-       }
+       /* 2. Prepare the TX dma transfer */
+       txconf.direction = DMA_TO_DEVICE;
+       txconf.dst_addr = dws->dma_addr;
+       txconf.dst_maxburst = LNW_DMA_MSIZE_16;
+       txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+       txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
+                                      (unsigned long) &txconf);
+
+       memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
+       dws->tx_sgl.dma_address = dws->tx_dma;
+       dws->tx_sgl.length = dws->len;
+
+       txdesc = txchan->device->device_prep_slave_sg(txchan,
+                                     &dws->tx_sgl,
+                                     1,
+                                     DMA_TO_DEVICE,
+                                     DMA_PREP_INTERRUPT | 
DMA_COMPL_SKIP_DEST_UNMAP);
+       txdesc->callback = dw_spi_dma_done;
+       txdesc->callback_param = dws;
+
+       /* 3. Prepare the RX dma transfer */
+       rxconf.direction = DMA_FROM_DEVICE;
+       rxconf.src_addr = dws->dma_addr;
+       rxconf.src_maxburst = LNW_DMA_MSIZE_16;
+       rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+       rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
+                                      (unsigned long) &rxconf);
+
+       memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
+       dws->rx_sgl.dma_address = dws->rx_dma;
+       dws->rx_sgl.length = dws->len;
+
+       rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+                                     &dws->rx_sgl,
+                                     1,
+                                     DMA_FROM_DEVICE,
+                                     DMA_PREP_INTERRUPT | 
DMA_COMPL_SKIP_DEST_UNMAP);
+       rxdesc->callback = dw_spi_dma_done;
+       rxdesc->callback_param = dws;
 
        /* rx must be started before tx due to spi instinct */
-       if (rxdesc)
-               rxdesc->tx_submit(rxdesc);
-       if (txdesc)
-               txdesc->tx_submit(txdesc);
-
+       rxdesc->tx_submit(rxdesc);
+       txdesc->tx_submit(txdesc);
        return 0;
 }
 
diff --git a/include/linux/spi/dw_spi.h b/include/linux/spi/dw_spi.h
index d9ce113..c00da7f 100644
--- a/include/linux/spi/dw_spi.h
+++ b/include/linux/spi/dw_spi.h
@@ -145,10 +145,12 @@ struct dw_spi {
        /* Dma info */
        int                     dma_inited;
        struct dma_chan         *txchan;
+       struct scatterlist      tx_sgl;
        struct dma_chan         *rxchan;
+       struct scatterlist      rx_sgl;
        int                     dma_chan_done;
        struct device           *dma_dev;
-       dma_addr_t              dma_addr;
+       dma_addr_t              dma_addr;  /* phy address of the Data register 
*/
        struct dw_spi_dma_ops   *dma_ops;
        void                    *dma_priv; /* platform relate info */
        struct pci_dev          *dmac;
-- 
1.7.0.4

_______________________________________________
Meego-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to