X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fusb%2Fmusb%2Fmusb_core.c;h=be123a12f615d9bcbb790001cc179567e760354f;hb=d348f1694041b0310e42c6a471e97214eb301e91;hp=ce9a52d2b6056e81b523b0b59c441242d547e43c;hpb=cd691980ad3d42daa7ac184e6cef955f303caa6e;p=pandora-kernel.git diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index ce9a52d2b605..be123a12f615 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -654,6 +654,15 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->is_active = 0; break; } + + switch (musb->xceiv->state) { + case OTG_STATE_B_IDLE: + case OTG_STATE_B_PERIPHERAL: + cancel_delayed_work(&musb->vbus_workaround_work); + schedule_delayed_work(&musb->vbus_workaround_work, HZ / 2); + default: + break; + } } if (int_usb & MUSB_INTR_CONNECT) { @@ -996,6 +1005,9 @@ static void musb_shutdown(struct platform_device *pdev) musb_platform_exit(musb); pm_runtime_put(musb->controller); + + cancel_delayed_work(&musb->vbus_workaround_work); + /* FIXME power down */ } @@ -1773,6 +1785,41 @@ static void musb_irq_work(struct work_struct *data) } } +#include + +static void musb_vbus_workaround_work(struct work_struct *work) +{ + struct musb *musb = container_of(work, struct musb, vbus_workaround_work.work); + u8 devctl; + int ret; + + if (musb_ulpi_access.write == NULL) + return; + + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + /* + * I don't really know why but VBUS sometimes gets stuck and + * causes session to never end. It would look like some pullup + * is enabled when it shouldn't be on certain PHY states. + * Turning on pulldowns magically drains VBUS to zero and allows + * session to end, so let's do that here. + * + * XXX: probably better check VBUS on TWL? + * beagle sometimes has session bit set but no VBUS on twl? + */ + if ((musb->xceiv->state == OTG_STATE_B_PERIPHERAL || + musb->xceiv->state == OTG_STATE_B_IDLE) && + (devctl & MUSB_DEVCTL_VBUS) != (3 << MUSB_DEVCTL_VBUS_SHIFT) && + (devctl & MUSB_DEVCTL_VBUS) != (0 << MUSB_DEVCTL_VBUS_SHIFT)) { + dev_dbg(musb->controller, "VBUS workaround..\n"); + ret = musb_ulpi_access.write(musb->xceiv, ULPI_SET(ULPI_OTG_CTRL), + ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN); + //if (ret) + // dev_err(musb->controller, "VBUS workaround error\n"); + } +} + /* -------------------------------------------------------------------------- * Init support */ @@ -1942,6 +1989,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* Init IRQ workqueue before request_irq */ INIT_WORK(&musb->irq_work, musb_irq_work); + INIT_DELAYED_WORK(&musb->vbus_workaround_work, musb_vbus_workaround_work); + /* attach to the IRQ */ if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) { dev_err(dev, "request_irq %d failed!\n", nIrq);