diff options
author | Barry Song <Baohua.Song@csr.com> | 2012-12-14 10:59:22 +0000 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2013-01-28 01:44:40 -0800 |
commit | 2518d1d1fc0ba7ef781bac97132bcfd6d7466c4b (patch) | |
tree | 7c38d76cbf4f92fc81dea18073f66f53027ce946 | |
parent | 6c5e6a3990ce64192b56ffafa5ffa5af129751d5 (diff) | |
download | lwn-2518d1d1fc0ba7ef781bac97132bcfd6d7466c4b.tar.gz lwn-2518d1d1fc0ba7ef781bac97132bcfd6d7466c4b.zip |
DMAEngine: sirf: add DMA pause/resume support
pause/resume are important for users like ALSA sound drivers,
this patches make the sirf prima2/marco support DMA commands
DMA_PAUSE and DMA_RESUME.
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Cc: Russell King <linux@arm.linux.org.uk>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r-- | drivers/dma/sirf-dma.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index 3c210ba9f938..7d78cf7bb7f1 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -313,6 +313,48 @@ static int sirfsoc_dma_terminate_all(struct sirfsoc_dma_chan *schan) return 0; } +static int sirfsoc_dma_pause_chan(struct sirfsoc_dma_chan *schan) +{ + struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan); + int cid = schan->chan.chan_id; + unsigned long flags; + + spin_lock_irqsave(&schan->lock, flags); + + if (!sdma->is_marco) + writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL) + & ~((1 << cid) | 1 << (cid + 16)), + sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL); + else + writel_relaxed((1 << cid) | 1 << (cid + 16), + sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL_CLR); + + spin_unlock_irqrestore(&schan->lock, flags); + + return 0; +} + +static int sirfsoc_dma_resume_chan(struct sirfsoc_dma_chan *schan) +{ + struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan); + int cid = schan->chan.chan_id; + unsigned long flags; + + spin_lock_irqsave(&schan->lock, flags); + + if (!sdma->is_marco) + writel_relaxed(readl_relaxed(sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL) + | ((1 << cid) | 1 << (cid + 16)), + sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL); + else + writel_relaxed((1 << cid) | 1 << (cid + 16), + sdma->base + SIRFSOC_DMA_CH_LOOP_CTRL); + + spin_unlock_irqrestore(&schan->lock, flags); + + return 0; +} + static int sirfsoc_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg) { @@ -320,6 +362,10 @@ static int sirfsoc_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan); switch (cmd) { + case DMA_PAUSE: + return sirfsoc_dma_pause_chan(schan); + case DMA_RESUME: + return sirfsoc_dma_resume_chan(schan); case DMA_TERMINATE_ALL: return sirfsoc_dma_terminate_all(schan); case DMA_SLAVE_CONFIG: |