diff options
author | Anand Gadiyar <gadiyar@ti.com> | 2009-12-28 14:40:36 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-03 01:53:42 +0300 |
commit | f933a0c0fe0ea5f49a35bcd45e3e4850e0606cba (patch) | |
tree | 9a8052f7fd2119bd76f7cd94c6db5ae7324c21cd /drivers/usb/musb/musbhsdma.c | |
parent | 452f0394376d2cc882e4c4a593fc290c042799a9 (diff) | |
download | linux-f933a0c0fe0ea5f49a35bcd45e3e4850e0606cba.tar.xz |
usb: musb: workaround MUSB DMA_INTR sometimes reads zero
MUSB DMA_INTR register may sometimes read zero when infact there
was a pending interrupt. Workaround this by reading the DMA_COUNT
values for all enabled channels when this condition occurs.
Flag these channels as the ones needing to be serviced.
Additionally, the absence of a debug print meant we would never
catch a spurious DMA interrupt in MUSB. So this patch adds a
debug print in the IRQ handler.
Signed-off-by: Anand Gadiyar <gadiyar@ti.com>
Cc: Ajay Kumar Gupta <ajay.gupta@ti.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Vikram Pandita <vikram.pandita@ti.com>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/musb/musbhsdma.c')
-rw-r--r-- | drivers/usb/musb/musbhsdma.c | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c index a237550f91bf..2fa7d5c00f31 100644 --- a/drivers/usb/musb/musbhsdma.c +++ b/drivers/usb/musb/musbhsdma.c @@ -250,20 +250,39 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data) u8 bchannel; u8 int_hsdma; - u32 addr; + u32 addr, count; u16 csr; spin_lock_irqsave(&musb->lock, flags); int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR); - if (!int_hsdma) - goto done; #ifdef CONFIG_BLACKFIN /* Clear DMA interrupt flags */ musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma); #endif + if (!int_hsdma) { + DBG(2, "spurious DMA irq\n"); + + for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { + musb_channel = (struct musb_dma_channel *) + &(controller->channel[bchannel]); + channel = &musb_channel->channel; + if (channel->status == MUSB_DMA_STATUS_BUSY) { + count = musb_read_hsdma_count(mbase, bchannel); + + if (count == 0) + int_hsdma |= (1 << bchannel); + } + } + + DBG(2, "int_hsdma = 0x%x\n", int_hsdma); + + if (!int_hsdma) + goto done; + } + for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { if (int_hsdma & (1 << bchannel)) { musb_channel = (struct musb_dma_channel *) |