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@xxxxxx> Cc: Ajay Kumar Gupta <ajay.gupta@xxxxxx> Cc: Felipe Balbi <felipe.balbi@xxxxxxxxx> Cc: David Brownell <dbrownell@xxxxxxxxxxxxxxxxxxxxx> Cc: Sergei Shtylyov <sshtylyov@xxxxxxxxxxxxx> Cc: Vikram Pandita <vikram.pandita@xxxxxx> --- This is a fix for buggy hardware (OMAP3630, OMAP4430). Please queue this up for the -rc series if possible. v2: Fix a bug in v1 pointed out by Vikram. DMA_COUNT is a 32 bit register, while csr is a 16 bit variable Also, use the wrapper API to read the register. drivers/usb/musb/musbhsdma.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) Index: linux-2.6/drivers/usb/musb/musbhsdma.c =================================================================== --- linux-2.6.orig/drivers/usb/musb/musbhsdma.c 2009-12-18 19:53:39.000000000 +0530 +++ linux-2.6/drivers/usb/musb/musbhsdma.c 2009-12-18 19:55:17.000000000 +0530 @@ -250,20 +250,39 @@ static irqreturn_t dma_controller_irq(in 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 *) -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html