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=98c37d869a2f406d994252d76b56f60f07f6aed1;hb=a592f46075d79ff7348e624e7d871dca730e70f2;hpb=0a749094a5e2bdcbef355b0c2eb3658fa6d7903c diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 98c37d869a2f..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", @@ -592,9 +597,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, break; } - dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n", + dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller, + "VBUS_ERROR in %s (%02x, %02x, %s), retry #%d, port1 %08x\n", otg_state_string(musb->xceiv->state), - devctl, + devctl, power, ({ char *s; switch (devctl & MUSB_DEVCTL_VBUS) { case 0 << MUSB_DEVCTL_VBUS_SHIFT: @@ -714,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 @@ -943,8 +949,8 @@ void musb_start(struct musb *musb) */ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) musb->is_active = 1; - else - devctl |= MUSB_DEVCTL_SESSION; + //else + // devctl |= MUSB_DEVCTL_SESSION; } else if (is_host_enabled(musb)) { /* assume ID pin is hard-wired to ground */ @@ -1517,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); @@ -1557,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); @@ -1574,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++; } @@ -1814,6 +1835,8 @@ static void musb_vbus_workaround_work(struct work_struct *work) if (musb_ulpi_access.write == NULL) return; + pm_runtime_get_sync(musb->controller); + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); /* @@ -1836,6 +1859,8 @@ static void musb_vbus_workaround_work(struct work_struct *work) //if (ret) // dev_err(musb->controller, "VBUS workaround error\n"); } + + pm_runtime_put(musb->controller); } /* -------------------------------------------------------------------------- @@ -1907,7 +1932,7 @@ static void musb_free(struct musb *musb) dma_controller_destroy(c); } - kfree(musb); + usb_put_hcd(musb_to_hcd(musb)); } /* @@ -2066,9 +2091,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) ? 'B' : 'A')); } else /* peripheral is enabled */ { - MUSB_DEV_MODE(musb); - musb->xceiv->default_a = 0; - musb->xceiv->state = OTG_STATE_B_IDLE; + if (musb->xceiv->default_a) { + MUSB_HST_MODE(musb); + musb->xceiv->state = OTG_STATE_A_IDLE; + } else { + MUSB_DEV_MODE(musb); + musb->xceiv->state = OTG_STATE_B_IDLE; + } status = musb_gadget_setup(musb); @@ -2361,7 +2390,7 @@ static int musb_suspend(struct device *dev) spin_lock_irqsave(&musb->lock, flags); - if (is_peripheral_active(musb)) { + { /* FIXME force disconnect unless we know USB will wake * the system up quickly enough to respond ... */ @@ -2379,10 +2408,6 @@ static int musb_suspend(struct device *dev) pm_usage_count); ret = -EBUSY; } - } else if (is_host_active(musb)) { - /* we know all the children are suspended; sometimes - * they will even be wakeup-enabled. - */ } spin_unlock_irqrestore(&musb->lock, flags); @@ -2458,10 +2483,7 @@ static int __init musb_init(void) if (usb_disabled()) return 0; - pr_info("%s: version " MUSB_VERSION ", " - "?dma?" - ", " - "otg (peripheral+host)", + pr_info("%s: version " MUSB_VERSION ", ?dma?, otg (peripheral+host)\n", musb_driver_name); return platform_driver_probe(&musb_driver, musb_probe); }