DMAEngine: sirf: add DMA pause/resume support
authorBarry Song <Baohua.Song@csr.com>
Fri, 14 Dec 2012 10:59:22 +0000 (10:59 +0000)
committerVinod Koul <vinod.koul@intel.com>
Mon, 28 Jan 2013 09:44:40 +0000 (01:44 -0800)
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>
drivers/dma/sirf-dma.c

index 3c210ba..7d78cf7 100644 (file)
@@ -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: