X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=drivers%2Fusb%2Fmusb%2Fmusb_core.c;h=fe1d5c5de2bc4d9af862e89763efeb9390f45ed1;hp=7245b89b020a3ee0c505aa16a0fb803d2b0f1c01;hb=a592f46075d79ff7348e624e7d871dca730e70f2;hpb=0e7bb344c55d7ed3ae76cab208984f76e82aa643 diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 7245b89b020a..fe1d5c5de2bc 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -131,7 +131,7 @@ static inline struct musb *dev_to_musb(struct device *dev) /*-------------------------------------------------------------------------*/ #ifndef CONFIG_BLACKFIN -static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) +static int musb_ulpi_read(struct otg_transceiver *otg, u32 reg) { void __iomem *addr = otg->io_priv; int i = 0; @@ -150,7 +150,7 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset) * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM. */ - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg); musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR); @@ -175,8 +175,7 @@ out: return ret; } -static int musb_ulpi_write(struct otg_transceiver *otg, - u32 offset, u32 data) +static int musb_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg) { void __iomem *addr = otg->io_priv; int i = 0; @@ -191,8 +190,8 @@ static int musb_ulpi_write(struct otg_transceiver *otg, power &= ~MUSB_POWER_SUSPENDM; musb_writeb(addr, MUSB_POWER, power); - musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); - musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data); + musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg); + musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)val); musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ); while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) @@ -456,8 +455,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if (power & MUSB_POWER_SUSPENDM) { /* spurious */ - musb->int_usb &= ~MUSB_INTR_SUSPEND; - dev_dbg(musb->controller, "Spurious SUSPENDM\n"); + int_usb &= ~MUSB_INTR_SUSPEND; + dev_err(musb->controller, "Spurious SUSPENDM\n"); break; } @@ -500,14 +499,20 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, if ((devctl & MUSB_DEVCTL_VBUS) != (3 << MUSB_DEVCTL_VBUS_SHIFT) ) { - musb->int_usb |= MUSB_INTR_DISCONNECT; - musb->int_usb &= ~MUSB_INTR_SUSPEND; + if (!(int_usb & MUSB_INTR_DISCONNECT)) + dev_err(musb->controller, + "disconnect while suspended?\n"); + int_usb |= MUSB_INTR_DISCONNECT; + int_usb &= ~MUSB_INTR_SUSPEND; break; } musb_g_resume(musb); break; case OTG_STATE_B_IDLE: - musb->int_usb &= ~MUSB_INTR_SUSPEND; + if (int_usb & MUSB_INTR_SUSPEND) + dev_err(musb->controller, + "bogus suspend+resume?\n"); + int_usb &= ~MUSB_INTR_SUSPEND; break; default: WARNING("bogus %s RESUME (%s)\n", @@ -715,7 +720,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, switch (musb->xceiv->state) { case OTG_STATE_B_PERIPHERAL: if (int_usb & MUSB_INTR_SUSPEND) { - dev_dbg(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n"); + dev_err(musb->controller, "HNP: SUSPEND+CONNECT, now b_host\n"); int_usb &= ~MUSB_INTR_SUSPEND; goto b_host; } else @@ -1518,15 +1523,22 @@ static irqreturn_t generic_interrupt(int irq, void *__hci) unsigned long flags; irqreturn_t retval = IRQ_NONE; struct musb *musb = __hci; + int i; spin_lock_irqsave(&musb->lock, flags); - musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); - musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); - musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + for (i = 0; i < 8; i++) { + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + /* SOF is not enabled, but status is still often set */ + musb->int_usb &= ~MUSB_INTR_SOF; + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); - if (musb->int_usb || musb->int_tx || musb->int_rx) - retval = musb_interrupt(musb); + if (musb->int_usb || musb->int_tx || musb->int_rx) + retval = musb_interrupt(musb); + else + break; + } spin_unlock_irqrestore(&musb->lock, flags); @@ -1558,16 +1570,30 @@ irqreturn_t musb_interrupt(struct musb *musb) (devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral", musb->int_usb, musb->int_tx, musb->int_rx); - /* the core can interrupt us for multiple reasons; docs have - * a generic interrupt flowchart to follow + /** + * According to Mentor Graphics' documentation, flowchart on page 98, + * IRQ should be handled as follows: + * + * . Resume IRQ + * . Session Request IRQ + * . VBUS Error IRQ + * . Suspend IRQ + * . Connect IRQ + * . Disconnect IRQ + * . Reset/Babble IRQ + * . SOF IRQ (we're not using this one) + * . Endpoint 0 IRQ + * . TX Endpoints + * . RX Endpoints + * + * We will be following that flowchart in order to avoid any problems + * that might arise with internal Finite State Machine. */ + if (musb->int_usb) retval |= musb_stage0_irq(musb, musb->int_usb, devctl, power); - /* "stage 1" is handling endpoint irqs */ - - /* handle endpoint 0 first */ if (musb->int_tx & 1) { if (devctl & MUSB_DEVCTL_HM) retval |= musb_h_ep0_irq(musb); @@ -1575,43 +1601,37 @@ irqreturn_t musb_interrupt(struct musb *musb) retval |= musb_g_ep0_irq(musb); } - /* RX on endpoints 1-15 */ - reg = musb->int_rx >> 1; + reg = musb->int_tx >> 1; ep_num = 1; while (reg) { if (reg & 1) { - /* musb_ep_select(musb->mregs, ep_num); */ - /* REVISIT just retval = ep->rx_irq(...) */ retval = IRQ_HANDLED; if (devctl & MUSB_DEVCTL_HM) { if (is_host_capable()) - musb_host_rx(musb, ep_num); + musb_host_tx(musb, ep_num); } else { if (is_peripheral_capable()) - musb_g_rx(musb, ep_num); + musb_g_tx(musb, ep_num); } } - reg >>= 1; ep_num++; } - /* TX on endpoints 1-15 */ - reg = musb->int_tx >> 1; + reg = musb->int_rx >> 1; ep_num = 1; while (reg) { if (reg & 1) { - /* musb_ep_select(musb->mregs, ep_num); */ - /* REVISIT just retval |= ep->tx_irq(...) */ retval = IRQ_HANDLED; if (devctl & MUSB_DEVCTL_HM) { if (is_host_capable()) - musb_host_tx(musb, ep_num); + musb_host_rx(musb, ep_num); } else { if (is_peripheral_capable()) - musb_g_tx(musb, ep_num); + musb_g_rx(musb, ep_num); } } + reg >>= 1; ep_num++; }