From a5073b52833e4df8e16c93dc4cbb7e0c558c74a2 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 27 Mar 2009 12:52:43 -0700 Subject: musb_gadget: fix unhandled endpoint 0 IRQs The gadget EP0 code routinely ignores an interrupt at end of the data phase because of musb_g_ep0_giveback() resetting the state machine to "idle, waiting for SETUP" phase prematurely. The driver also prematurely leaves the status phase on receiving the SetupEnd interrupt. As there were still unhandled endpoint 0 interrupts happening from time to time after fixing these issues, there turned to be yet another culprit: two distinct gadget states collapsed into one. The (missing) state that comes after STATUS IN/OUT states was typically indiscernible from them since the corresponding interrupts tend to happen within too little period of time (due to only a zero-length status packet in between) and so they got coalesced; yet this state is not the same as the next one which is associated with the reception of a SETUP packet. Adding this extra state seems to have fixed the rest of the unhandled interrupts that generic_interrupt() and davinci_interrupt() hid by faking their result and only emitting a debug message -- so, stop doing that. Signed-off-by: Sergei Shtylyov Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/davinci.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/usb/musb/davinci.c') diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 10d11ab113a..898b52fcff5 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -372,12 +372,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) spin_unlock_irqrestore(&musb->lock, flags); - /* REVISIT we sometimes get unhandled IRQs - * (e.g. ep0). not clear why... - */ - if (retval != IRQ_HANDLED) - DBG(5, "unhandled? %08x\n", tmp); - return IRQ_HANDLED; + return retval; } int musb_platform_set_mode(struct musb *musb, u8 mode) -- cgit v1.2.3 From 91e9c4fec7ee777213859aa1a18bf0b885527637 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 27 Mar 2009 12:59:46 -0700 Subject: musb: split out CPPI interrupt handler As DaVinci DM646x has a dedicated CPPI DMA interrupt, replace cppi_completion() (which has always been kind of layering violation) by a complete CPPI interrupt handler. [ dbrownell@users.sourceforge.net: only cppi_dma.c needs platform device header, not cppi_dma.h ] Signed-off-by: Dmitry Krivoschekov Signed-off-by: Sergei Shtylyov Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/davinci.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/usb/musb/davinci.c') diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 898b52fcff5..6e14e06ff82 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -265,6 +265,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) irqreturn_t retval = IRQ_NONE; struct musb *musb = __hci; void __iomem *tibase = musb->ctrl_base; + struct cppi *cppi; u32 tmp; spin_lock_irqsave(&musb->lock, flags); @@ -281,16 +282,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) /* CPPI interrupts share the same IRQ line, but have their own * mask, state, "vector", and EOI registers. */ - if (is_cppi_enabled()) { - u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG); - u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG); - - if (cppi_tx || cppi_rx) { - DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx); - cppi_completion(musb, cppi_rx, cppi_tx); - retval = IRQ_HANDLED; - } - } + cppi = container_of(musb->dma_controller, struct cppi, controller); + if (is_cppi_enabled() && musb->dma_controller && !cppi->irq) + retval = cppi_interrupt(irq, __hci); /* ack and handle non-CPPI interrupts */ tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG); -- cgit v1.2.3 From 84e250ffa76dddc1bad84e04248a27f442c25986 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Tue, 31 Mar 2009 12:30:04 -0700 Subject: musb: proper hookup to transceiver drivers Let the otg_transceiver in MUSB be managed by an external driver; don't assume it's integrated. OMAP3 chips need it to be external, and there may be ways to interact with the transceiver which add functionality to the system. Platform init code is responsible for setting up the transeciver, probably using the NOP transceiver for integrated transceivers. External ones will use whatever the board init code provided, such as twl4030 or something more hands-off. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/davinci.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers/usb/musb/davinci.c') diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index 6e14e06ff82..180d7daa409 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb) DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb)); spin_lock_irqsave(&musb->lock, flags); - switch (musb->xceiv.state) { + switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_VFALL: /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL * seems to mis-handle session "start" otherwise (or in our @@ -226,7 +226,7 @@ static void otg_timer(unsigned long _musb) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); break; } - musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); break; @@ -251,7 +251,7 @@ static void otg_timer(unsigned long _musb) if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else - musb->xceiv.state = OTG_STATE_A_IDLE; + musb->xceiv->state = OTG_STATE_A_IDLE; break; default: break; @@ -325,21 +325,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) * to stop registering in devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; - musb->xceiv.state = OTG_STATE_A_WAIT_VFALL; + musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (is_host_enabled(musb) && drvvbus) { musb->is_active = 1; MUSB_HST_MODE(musb); - musb->xceiv.default_a = 1; - musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; + musb->xceiv->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; portstate(musb->port1_status |= USB_PORT_STAT_POWER); del_timer(&otg_workaround); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); - musb->xceiv.default_a = 0; - musb->xceiv.state = OTG_STATE_B_IDLE; + musb->xceiv->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } @@ -361,7 +361,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci) /* poll for ID change */ if (is_otg_enabled(musb) - && musb->xceiv.state == OTG_STATE_B_IDLE) + && musb->xceiv->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); @@ -380,6 +380,11 @@ int __init musb_platform_init(struct musb *musb) void __iomem *tibase = musb->ctrl_base; u32 revision; + usb_nop_xceiv_register(); + musb->xceiv = otg_get_transceiver(); + if (!musb->xceiv) + return -ENODEV; + musb->mregs += DAVINCI_BASE_OFFSET; clk_enable(musb->clock); @@ -387,7 +392,7 @@ int __init musb_platform_init(struct musb *musb) /* returns zero if e.g. not clocked */ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); if (revision == 0) - return -ENODEV; + goto fail; if (is_host_enabled(musb)) setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); @@ -421,6 +426,10 @@ int __init musb_platform_init(struct musb *musb) musb->isr = davinci_interrupt; return 0; + +fail: + usb_nop_xceiv_unregister(); + return -ENODEV; } int musb_platform_exit(struct musb *musb) @@ -431,7 +440,7 @@ int musb_platform_exit(struct musb *musb) davinci_source_power(musb, 0 /*off*/, 1); /* delay, to avoid problems with module reload */ - if (is_host_enabled(musb) && musb->xceiv.default_a) { + if (is_host_enabled(musb) && musb->xceiv->default_a) { int maxdelay = 30; u8 devctl, warn = 0; @@ -460,5 +469,7 @@ int musb_platform_exit(struct musb *musb) clk_disable(musb->clock); + usb_nop_xceiv_unregister(); + return 0; } -- cgit v1.2.3