diff options
Diffstat (limited to 'drivers/usb/gadget/arcotg_udc.c')
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.c | 451 |
1 files changed, 154 insertions, 297 deletions
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index 8e94549f891e..abba4d2ae8d4 100644 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -106,6 +106,19 @@ extern struct resource *otg_get_resources(void); extern void fsl_platform_set_test_mode(struct fsl_usb2_platform_data *pdata, enum usb_test_mode mode); +static inline void +dr_wake_up_enable(struct fsl_udc *udc, bool enable) +{ + struct fsl_usb2_platform_data *pdata; + pdata = udc->pdata; + + if (enable && (!device_may_wakeup(udc_controller->gadget.dev.parent))) + return; + + if (pdata->wake_up_enable) + pdata->wake_up_enable(pdata, enable); +} + #ifdef CONFIG_WORKAROUND_ARCUSB_REG_RW static void safe_writel(u32 val32, void *addr) { @@ -270,12 +283,9 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status) static void nuke(struct fsl_ep *ep, int status) { ep->stopped = 1; - /* - * At udc stop mode, the clock is already off - * So flush fifo, should be done at clock on mode. - */ - if (!ep->udc->stopped) - fsl_ep_fifo_flush(&ep->ep); + + /* Flush fifo */ + fsl_ep_fifo_flush(&ep->ep); /* Whether this eq has request linked */ while (!list_empty(&ep->queue)) { @@ -290,83 +300,31 @@ static void nuke(struct fsl_ep *ep, int status) /*------------------------------------------------------------------ Internal Hardware related function ------------------------------------------------------------------*/ -static inline void -dr_wake_up_enable(struct fsl_udc *udc, bool enable) -{ - struct fsl_usb2_platform_data *pdata; - pdata = udc->pdata; - if (pdata && pdata->wake_up_enable) - pdata->wake_up_enable(pdata, enable); -} -static bool clk_stoped = false; -static inline void dr_clk_gate(bool on) +static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) { - struct fsl_usb2_platform_data *pdata = udc_controller->pdata; + u32 temp; - if (!pdata || !pdata->usb_clock_for_pm) + if (!device_may_wakeup(udc_controller->gadget.dev.parent)) return; - if (on && clk_stoped) { - pdata->usb_clock_for_pm(true); - clk_stoped = false; - } - if (!on && !clk_stoped) { - pdata->usb_clock_for_pm(false); - clk_stoped = true; - } - if (on) - reset_phy(); -} -static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) -{ - struct fsl_usb2_platform_data *pdata = udc->pdata; - u32 portsc; + if (enable) { + temp = fsl_readl(&dr_regs->portsc1); + temp |= PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(temp, &dr_regs->portsc1); - if (pdata && pdata->phy_lowpower_suspend) { - pdata->phy_lowpower_suspend(enable); + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); } else { - if (enable){ - portsc = fsl_readl(&dr_regs->portsc1); - portsc |= PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(portsc, &dr_regs->portsc1); - } else { - portsc = fsl_readl(&dr_regs->portsc1); - portsc &= ~PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(portsc, &dr_regs->portsc1); - } - } -} - - -/* workaroud for some boards, maybe there is a large capacitor between the ground and the Vbus - * that will cause the vbus dropping very slowly when device is detached, - * may cost 2-3 seconds to below 0.8V */ -static void udc_wait_b_session_low(void) -{ - u32 temp; - u32 wait = 5000; /* max wait time is 5000 ms */ - /* if we are in host mode, don't need to care the B session */ - if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) - return; - /* if the udc is dettached , there will be a suspend irq */ - if (udc_controller->usb_state != USB_STATE_SUSPENDED) - return; - temp = fsl_readl(&dr_regs->otgsc); - temp &= ~(OTGSC_B_SESSION_VALID_IRQ_EN ); - fsl_writel(temp, &dr_regs->otgsc); + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(true); - do { - if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID)) - break; - mdelay(1); - wait -= 1; - } while(wait); - if (!wait) - printk("ERROR!!!!!: the vbus can not be lower then 0.8V for 5 seconds, Pls Check your HW design\n"); - temp = fsl_readl(&dr_regs->otgsc); - temp |= (OTGSC_B_SESSION_VALID_IRQ_EN ); - fsl_writel(temp, &dr_regs->otgsc); + /* Due to mx35/mx25's phy's bug */ + reset_phy(); + temp = fsl_readl(&dr_regs->portsc1); + temp &= ~PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(temp, &dr_regs->portsc1); + } } static int dr_controller_setup(struct fsl_udc *udc) @@ -490,20 +448,23 @@ static void dr_controller_run(struct fsl_udc *udc) fsl_writel(temp, &dr_regs->usbintr); - /* enable BSV irq */ - temp = fsl_readl(&dr_regs->otgsc); - temp |= OTGSC_B_SESSION_VALID_IRQ_EN; - fsl_writel(temp, &dr_regs->otgsc); + if (device_may_wakeup(udc_controller->gadget.dev.parent)) { + /* enable BSV irq */ + temp = fsl_readl(&dr_regs->otgsc); + temp |= OTGSC_B_SESSION_VALID_IRQ_EN; + fsl_writel(temp, &dr_regs->otgsc); + } /* If vbus not on and used low power mode */ - if (!(temp & OTGSC_B_SESSION_VALID)) { - /* Set stopped before low power mode */ - udc->stopped = 1; + if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID) + && device_may_wakeup(udc_controller->gadget.dev.parent)) { /* enable wake up */ dr_wake_up_enable(udc, true); - /* enter lower power mode */ + /* Set stopped before low power mode */ + udc->stopped = 1; + /* close PHY clock */ dr_phy_low_power_mode(udc, true); - printk(KERN_INFO "%s: udc enter low power mode \n", __func__); + printk(KERN_INFO "udc enter low power mode \n"); } else { #ifdef CONFIG_ARCH_MX37 /* @@ -515,11 +476,11 @@ static void dr_controller_run(struct fsl_udc *udc) #endif /* Clear stopped bit */ udc->stopped = 0; - - /* The usb line has already been connected to pc */ + /* Set controller to Run */ temp = fsl_readl(&dr_regs->usbcmd); temp |= USB_CMD_RUN_STOP; fsl_writel(temp, &dr_regs->usbcmd); + printk(KERN_INFO "udc run \n"); } return; @@ -2015,36 +1976,15 @@ static void suspend_irq(struct fsl_udc *udc) udc->driver->suspend(&udc->gadget); } -/* Process Wake up interrupt - * Be careful that some boards will use ID pin to control the VBUS on/off - * in these case, after the device enter the lowpower mode(clk off, - * phy lowpower mode, wakeup enable), then an udisk is attaced to the otg port, - * there will be an Vbus wakeup event and then an ID change wakeup, But the Vbus - * event is not expected, so there is an workaround that will detect the ID, if ID=0 - * we just need the ID event so we can not disable the wakeup - * - * false: host wakeup event - * true: device wakeup event -*/ -static bool wake_up_irq(struct fsl_udc *udc) -{ - /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will - * be delayed max 2 ms to show the real ID pin value - */ - mdelay(3); - - /* if the ID=0, let arc host process the wakeup */ - if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) { - dr_wake_up_enable(udc_controller, false); - dr_phy_low_power_mode(udc, false); - printk("device wake up event\n"); - return true; - }else {/* wakeup is vbus wake event, but not for device so we need to clear b session */ - int irq_src = fsl_readl(&dr_regs->otgsc) & (~OTGSC_ID_CHANGE_IRQ_STS); - fsl_writel(irq_src, &dr_regs->otgsc); - printk("The host wakeup event, should be handled by host\n"); - return false; - } +/* Process Wake up interrupt */ +static void wake_up_irq(struct fsl_udc *udc) +{ + pr_debug("%s\n", __func__); + + /* disable wake up irq */ + dr_wake_up_enable(udc_controller, false); + + udc->stopped = 0; } static void bus_resume(struct fsl_udc *udc) @@ -2113,48 +2053,43 @@ static void reset_irq(struct fsl_udc *udc) bool try_wake_up_udc(struct fsl_udc *udc) { u32 irq_src; - bool b_device; /* when udc is stopped, only handle wake up irq */ if (udc->stopped) { + if (!device_may_wakeup(&(udc->pdata->pdev->dev))) + return false; + + dr_phy_low_power_mode(udc_controller, false); + /* check to see if wake up irq */ irq_src = fsl_readl(&dr_regs->usbctrl); if (irq_src & USB_CTRL_OTG_WUIR) { - if (wake_up_irq(udc) == false){ - return false; /* host wakeup event */ - } + wake_up_irq(udc); + } else { + dr_phy_low_power_mode(udc_controller, true); } } + if (!device_may_wakeup(udc_controller->gadget.dev.parent)) + return true; + /* check if Vbus change irq */ irq_src = fsl_readl(&dr_regs->otgsc); if (irq_src & OTGSC_B_SESSION_VALID_IRQ_STS) { u32 tmp; - /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will - * be delayed max 2 ms to show the real ID pin value, as it needs to use ID to judge - * host or device - */ - mdelay(3); - b_device = (irq_src & OTGSC_STS_USB_ID)? true:false; fsl_writel(irq_src, &dr_regs->otgsc); - if (!b_device) - return false; tmp = fsl_readl(&dr_regs->usbcmd); /* check BSV bit to see if fall or rise */ if (irq_src & OTGSC_B_SESSION_VALID) { - if (udc->suspended) /*let the system pm resume the udc */ - return true; udc->stopped = 0; fsl_writel(tmp | USB_CMD_RUN_STOP, &dr_regs->usbcmd); - printk(KERN_INFO "%s: udc out low power mode\n", __func__); + printk(KERN_INFO "udc out low power mode\n"); } else { - printk(KERN_INFO "%s: udc enter low power mode \n", __func__); - if (udc->driver) - udc->driver->disconnect(&udc->gadget); + printk(KERN_INFO "udc enter low power mode \n"); fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd); - udc->stopped = 1; /* enable wake up */ dr_wake_up_enable(udc, true); + udc->stopped = 1; /* close USB PHY clock */ dr_phy_low_power_mode(udc, true); return false; @@ -2163,6 +2098,7 @@ bool try_wake_up_udc(struct fsl_udc *udc) return true; } + /* * USB device controller interrupt handler */ @@ -2173,29 +2109,15 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) irqreturn_t status = IRQ_NONE; unsigned long flags; - spin_lock_irqsave(&udc->lock, flags); - if (udc->stopped) - dr_clk_gate(true); - - if (try_wake_up_udc(udc) == false) { - goto irq_end; - } -#ifdef CONFIG_USB_OTG - /* if no gadget register in this driver, we need do noting */ - if (udc->transceiver->gadget == NULL) - goto irq_end; - - /* only handle device interrupt event */ - if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { - goto irq_end; - } -#endif + if (try_wake_up_udc(udc) == false) + return IRQ_NONE; + spin_lock_irqsave(&udc->lock, flags); irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr); /* Clear notification bits */ fsl_writel(irq_src, &dr_regs->usbsts); - VDBG("0x%x\n", irq_src); + /* VDBG("irq_src [0x%8x]", irq_src); */ /* Need to resume? */ if (udc->usb_state == USB_STATE_SUSPENDED) @@ -2240,24 +2162,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) /* Sleep Enable (Suspend) */ if (irq_src & USB_STS_SUSPEND) { - VDBG("suspend int"); suspend_irq(udc); status = IRQ_HANDLED; } if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { - printk(KERN_ERR "Error IRQ %x ", irq_src); - if (irq_src & USB_STS_SYS_ERR) { - printk(KERN_ERR "This error can't be recoveried, \ - please reboot your board\n"); - printk(KERN_ERR "If this error happens frequently, \ - please check your dma buffer\n"); - } - } - -irq_end: - if (udc->stopped){ - dr_clk_gate(false); + VDBG("Error IRQ %x ", irq_src); } spin_unlock_irqrestore(&udc->lock, flags); @@ -2272,6 +2182,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) { int retval = -ENODEV; unsigned long flags = 0; + u32 portsc; if (!udc_controller) return -ENODEV; @@ -2289,18 +2200,17 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_lock_irqsave(&udc_controller->lock, flags); driver->driver.bus = 0; - udc_controller->pdata->port_enables = 1; /* hook up the driver */ udc_controller->driver = driver; udc_controller->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc_controller->lock, flags); - dr_clk_gate(true); - /* It doesn't need to switch usb from low power mode to normal mode - * at otg mode - */ - if (!udc_controller->transceiver){ - dr_phy_low_power_mode(udc_controller, false); - } + + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(true); + + portsc = fsl_readl(&dr_regs->portsc1); + portsc &= ~PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); /* bind udc driver to gadget driver */ retval = driver->bind(&udc_controller->gadget); @@ -2313,30 +2223,30 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (udc_controller->transceiver) { /* Suspend the controller until OTG enable it */ - udc_controller->suspended = 1;/* let the otg resume it */ + udc_controller->stopped = 1; printk(KERN_INFO "Suspend udc for OTG auto detect\n"); dr_wake_up_enable(udc_controller, true); + dr_phy_low_power_mode(udc_controller, true); /* export udc suspend/resume call to OTG */ udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend; udc_controller->gadget.dev.driver->resume = (dev_res)fsl_udc_resume; /* connect to bus through transceiver */ - retval = otg_set_peripheral(udc_controller->transceiver, - &udc_controller->gadget); - if (retval < 0) { - ERR("can't bind to transceiver\n"); - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = 0; - udc_controller->driver = 0; - return retval; + if (udc_controller->transceiver) { + retval = otg_set_peripheral(udc_controller->transceiver, + &udc_controller->gadget); + if (retval < 0) { + ERR("can't bind to transceiver\n"); + driver->unbind(&udc_controller->gadget); + udc_controller->gadget.dev.driver = 0; + udc_controller->driver = 0; + return retval; + } } - //dr_clk_gate(false); } else { /* Enable DR IRQ reg and Set usbcmd reg Run bit */ dr_controller_run(udc_controller); - if (udc_controller->stopped) - dr_clk_gate(false); udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; } @@ -2344,10 +2254,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) udc_controller->gadget.name, driver->driver.name); out: - if (retval){ + if (retval) printk(KERN_DEBUG "retval %d \n", retval); - udc_controller->pdata->port_enables = 0; - } return retval; } EXPORT_SYMBOL(usb_gadget_register_driver); @@ -2357,6 +2265,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct fsl_ep *loop_ep; unsigned long flags; + u32 portsc; if (!udc_controller) return -ENODEV; @@ -2364,16 +2273,15 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; - if(udc_controller->stopped) - dr_clk_gate(true); - if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); + /* open phy clock for following operation */ + dr_phy_low_power_mode(udc_controller, false); + /* stop DR, disable intr */ dr_controller_stop(udc_controller); - udc_controller->pdata->port_enables = 0; /* in fact, no needed */ udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; @@ -2395,11 +2303,14 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) udc_controller->gadget.dev.driver = 0; udc_controller->driver = 0; - if (udc_controller->gadget.is_otg) { - dr_wake_up_enable(udc_controller, true); - } + dr_wake_up_enable(udc_controller, false); - dr_phy_low_power_mode(udc_controller, true); + portsc = fsl_readl(&dr_regs->portsc1); + portsc |= PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); + + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); printk(KERN_INFO "unregistered gadget driver '%s'\r\n", driver->driver.name); @@ -2814,7 +2725,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev) ret = -ENODEV; goto err1a; } - udc_controller->gadget.is_otg = 1; #endif if ((pdev->dev.parent) && @@ -2915,6 +2825,12 @@ static int __init fsl_udc_probe(struct platform_device *pdev) if (ret < 0) goto err3; + if (udc_controller->transceiver) { + udc_controller->gadget.is_otg = 1; + /* now didn't support lpm in OTG mode*/ + device_set_wakeup_capable(&pdev->dev, 0); + } + /* setup QH and epctrl for ep0 */ ep0_setup(udc_controller); @@ -2957,29 +2873,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev) #ifdef POSTPONE_FREE_LAST_DTD last_free_td = NULL; #endif - #ifndef CONFIG_USB_OTG /* disable all INTR */ fsl_writel(0, &dr_regs->usbintr); + dr_wake_up_enable(udc_controller, false); -#else - dr_wake_up_enable(udc_controller, true); -#endif + udc_controller->stopped = 1; -/* - * As mx25/mx35 does not implement clk_gate, should not let phy to low - * power mode due to IC bug - */ #if !(defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25) { - dr_phy_low_power_mode(udc_controller, true); + u32 portsc; + portsc = fsl_readl(&dr_regs->portsc1); + portsc |= PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); } #endif - udc_controller->stopped = 1; - - /* let the gadget register function open the clk */ - dr_clk_gate(false); - + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); +#endif create_proc_file(); return 0; @@ -3006,6 +2917,9 @@ err1a: */ static int __exit fsl_udc_remove(struct platform_device *pdev) { +#ifndef CONFIG_USB_OTG + struct resource *res; +#endif struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; DECLARE_COMPLETION(done); @@ -3014,8 +2928,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) return -ENODEV; udc_controller->done = &done; /* open USB PHY clock */ - if (udc_controller->stopped) - dr_clk_gate(true); + dr_phy_low_power_mode(udc_controller, false); /* DR has been stopped in usb_gadget_unregister_driver() */ remove_proc_file(); @@ -3038,11 +2951,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) iounmap((u8 __iomem *)dr_regs); #ifndef CONFIG_USB_OTG -{ - struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); -} #endif device_unregister(&udc_controller->gadget.dev); @@ -3056,8 +2966,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) if (pdata->platform_uninit) pdata->platform_uninit(pdata); - if (udc_controller->stopped) - dr_clk_gate(false); return 0; } @@ -3065,19 +2973,10 @@ static int udc_suspend(struct fsl_udc *udc) { u32 mode, usbcmd; - /* - * When it is the PM suspend routine and the device has no - * abilities to wakeup system, it should not set wakeup enable. - * Otherwise, the system will wakeup even the user only wants to - * charge using usb - */ - if (udc_controller->gadget.dev.parent->power.status - == DPM_SUSPENDING) { - if (!device_may_wakeup(udc_controller->gadget.dev.parent)) - dr_wake_up_enable(udc, false); - else - dr_wake_up_enable(udc, true); - } + /* open clock for register access */ + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(true); + mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK; usbcmd = fsl_readl(&dr_regs->usbcmd); @@ -3088,8 +2987,9 @@ static int udc_suspend(struct fsl_udc *udc) * PM suspend. Remember this fact, so that we will leave the * controller stopped at PM resume time. */ - if (udc->suspended) { + if (udc->stopped) { pr_debug("gadget already stopped, leaving early\n"); + udc->already_stopped = 1; goto out; } @@ -3098,30 +2998,22 @@ static int udc_suspend(struct fsl_udc *udc) goto out; } - /* For some buggy hardware designs, see comment of this function for detail */ - udc_wait_b_session_low(); - udc->stopped = 1; - - /* stop the controller */ - usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; - fsl_writel(usbcmd, &dr_regs->usbcmd); - /* if the suspend is not for switch to host in otg mode */ if ((!(udc->gadget.is_otg)) || (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { - if (device_may_wakeup(udc_controller->gadget.dev.parent)) { - dr_wake_up_enable(udc, true); - } + dr_wake_up_enable(udc, true); + dr_phy_low_power_mode(udc, true); } - dr_phy_low_power_mode(udc, true); + /* stop the controller */ + usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; + fsl_writel(usbcmd, &dr_regs->usbcmd); + printk(KERN_INFO "USB Gadget suspended\n"); out: - udc->suspended++; - if (udc->suspended > 2) - printk("ERROR: suspended times > 2\n"); - + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); return 0; } @@ -3131,24 +3023,13 @@ out: -----------------------------------------------------------------*/ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) { - int ret; -#ifdef CONFIG_USB_OTG - if (udc_controller->transceiver->gadget == NULL) - return 0; -#endif - if (udc_controller->stopped) - dr_clk_gate(true); if (((!(udc_controller->gadget.is_otg)) || (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) && (udc_controller->usb_state > USB_STATE_POWERED) && - (udc_controller->usb_state < USB_STATE_SUSPENDED)) { - return -EBUSY;/* keep the clk on */ - } - else - ret = udc_suspend(udc_controller); - dr_clk_gate(false); + (udc_controller->usb_state < USB_STATE_SUSPENDED)) + return -EBUSY; - return ret; + return udc_suspend(udc_controller); } /*----------------------------------------------------------------- @@ -3157,54 +3038,30 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) *-----------------------------------------------------------------*/ static int fsl_udc_resume(struct platform_device *pdev) { - pr_debug("%s(): stopped %d suspended %d\n", __func__, - udc_controller->stopped, udc_controller->suspended); - printk("udc resume\n"); -#ifdef CONFIG_USB_OTG - if (udc_controller->transceiver->gadget == NULL) - return 0; -#endif - if (udc_controller->stopped) - dr_clk_gate(true); + pr_debug("%s(): stopped %d already_stopped %d\n", __func__, + udc_controller->stopped, udc_controller->already_stopped); + /* * If the controller was stopped at suspend time, then * don't resume it now. */ - /* - * If it is PM resume routine, the udc is at low power mode, - * and the udc has no abilities to wakeup system, it should - * set the abilities to wakeup itself. Otherwise, the usb - * subsystem will not leave from low power mode. - */ - if (!device_may_wakeup(udc_controller->gadget.dev.parent) && - udc_controller->gadget.dev.parent->power.status - == DPM_RESUMING){ - dr_wake_up_enable(udc_controller, true); - } - - if (--udc_controller->suspended) { - printk("gadget was already stopped, leaving early\n"); - goto out; + if (udc_controller->already_stopped) { + udc_controller->already_stopped = 0; + pr_debug("gadget was already stopped, leaving early\n"); + return 0; } + /* Enable DR irq reg and set controller Run */ if (udc_controller->stopped) { - /* if in host mode, we need to do nothing */ - if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) { - goto out; - } dr_wake_up_enable(udc_controller, false); dr_phy_low_power_mode(udc_controller, false); - mdelay(10); + mdelay(1); + dr_controller_setup(udc_controller); dr_controller_run(udc_controller); } udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; -out: - /* if udc is resume by otg id change and no device - * connecting to the otg, otg will enter low power mode*/ - if (udc_controller->stopped) - dr_clk_gate(false); printk(KERN_INFO "USB Gadget resumed\n"); return 0; |