aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2010-12-09 10:37:36 +0000
committerAlan Cox <alan@linux.intel.com>2010-12-09 10:37:36 +0000
commitcb9ecc7487de9469cf229506d6e3482dcaa36820 (patch)
tree3f284171ec6ce06e0b7b2825aa21c096c82e60e3
parent30c35436894b81172616e72f1a1a6ca5229ee2d9 (diff)
downloadmrst-s0i3-test-cb9ecc7487de9469cf229506d6e3482dcaa36820.tar.gz
mrst-s0i3-test-cb9ecc7487de9469cf229506d6e3482dcaa36820.tar.xz
mrst-s0i3-test-cb9ecc7487de9469cf229506d6e3482dcaa36820.zip
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 <feng.tang@intel.com>
-rw-r--r--drivers/spi/dw_spi_mid.c126
-rw-r--r--include/linux/spi/dw_spi.h4
2 files changed, 62 insertions, 68 deletions
diff --git a/drivers/spi/dw_spi_mid.c b/drivers/spi/dw_spi_mid.c
index b53ab22f3cc..f7103e58511 100644
--- a/drivers/spi/dw_spi_mid.c
+++ b/drivers/spi/dw_spi_mid.c
@@ -35,73 +35,44 @@ 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)
{
struct mid_dma *dw_dma = dws->dma_priv;
struct intel_mid_dma_slave *rxs, *txs;
- struct dma_slave_config *ds;
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;
- ds = &rxs->dma_slave;
- ds->direction = DMA_FROM_DEVICE;
- rxs->hs_mode = LNW_DMA_HW_HS;
- rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
- ds->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- ds->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- ds->src_maxburst = 16;
- ds->dst_maxburst = 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;
- ds = &txs->dma_slave;
-
- ds->direction = DMA_TO_DEVICE;
- txs->hs_mode = LNW_DMA_HW_HS;
- txs->cfg_mode = LNW_DMA_MEM_TO_PER;
- ds->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- ds->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
- ds->src_maxburst = 16;
- ds->dst_maxburst = 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;
@@ -136,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 */
@@ -153,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 890266a6365..e3aa5a1ff3f 100644
--- a/include/linux/spi/dw_spi.h
+++ b/include/linux/spi/dw_spi.h
@@ -144,10 +144,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;