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
