summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAnand Gadiyar <gadiyar@ti.com>2009-12-28 12:40:36 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2010-03-02 23:53:42 +0100
commitf933a0c0fe0ea5f49a35bcd45e3e4850e0606cba (patch)
tree9a8052f7fd2119bd76f7cd94c6db5ae7324c21cd /drivers
parentusb: musb: hsdma: add wrapper for reading DMA count (diff)
downloadlinux-f933a0c0fe0ea5f49a35bcd45e3e4850e0606cba.tar.xz
linux-f933a0c0fe0ea5f49a35bcd45e3e4850e0606cba.zip
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')
-rw-r--r--drivers/usb/musb/musbhsdma.c25
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 *)