summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorIra Snyder <iws@ovro.caltech.edu>2011-03-03 07:55:01 +0000
committerDan Williams <dan.j.williams@intel.com>2011-03-11 17:52:37 -0800
commita00ae34ac8bc8a5897d9b6b9b685c39b955b14b9 (patch)
tree72be720ffc981acbf15f6c8ef7381a5e38416e2e /drivers/dma
parentdc8d4091575ba81e886ebcdfd1e559c981f82f86 (diff)
downloadlinux-3.10-a00ae34ac8bc8a5897d9b6b9b685c39b955b14b9.tar.gz
linux-3.10-a00ae34ac8bc8a5897d9b6b9b685c39b955b14b9.tar.bz2
linux-3.10-a00ae34ac8bc8a5897d9b6b9b685c39b955b14b9.zip
fsldma: make halt behave nicely on all supported controllers
The original dma_halt() function set the CA (channel abort) bit on both the 83xx and 85xx controllers. This is incorrect on the 83xx, where this bit means TEM (transfer error mask) instead. The 83xx doesn't support channel abort, so we only do this operation on 85xx. Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/fsldma.c19
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index d300de456c9..8670a501212 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -221,13 +221,26 @@ static void dma_halt(struct fsldma_chan *chan)
u32 mode;
int i;
+ /* read the mode register */
mode = DMA_IN(chan, &chan->regs->mr, 32);
- mode |= FSL_DMA_MR_CA;
- DMA_OUT(chan, &chan->regs->mr, mode, 32);
- mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA);
+ /*
+ * The 85xx controller supports channel abort, which will stop
+ * the current transfer. On 83xx, this bit is the transfer error
+ * mask bit, which should not be changed.
+ */
+ if ((chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX) {
+ mode |= FSL_DMA_MR_CA;
+ DMA_OUT(chan, &chan->regs->mr, mode, 32);
+
+ mode &= ~FSL_DMA_MR_CA;
+ }
+
+ /* stop the DMA controller */
+ mode &= ~(FSL_DMA_MR_CS | FSL_DMA_MR_EMS_EN);
DMA_OUT(chan, &chan->regs->mr, mode, 32);
+ /* wait for the DMA controller to become idle */
for (i = 0; i < 100; i++) {
if (dma_is_idle(chan))
return;