diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.c | 77 | ||||
-rw-r--r-- | drivers/usb/host/ehci-arc.c | 103 |
2 files changed, 107 insertions, 73 deletions
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index acc1b9508da9..7772c39a1044 100644 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -109,7 +109,7 @@ dr_wake_up_enable(struct fsl_udc *udc, bool enable) struct fsl_usb2_platform_data *pdata; pdata = udc->pdata; - if (device_can_wakeup(udc_controller->gadget.dev.parent)) { + if (device_may_wakeup(udc_controller->gadget.dev.parent)) { if (pdata->wake_up_enable) pdata->wake_up_enable(pdata, enable); } @@ -272,19 +272,21 @@ static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) { u32 temp; - if (!device_can_wakeup(udc_controller->gadget.dev.parent)) + if (!device_may_wakeup(udc_controller->gadget.dev.parent)) return; - temp = fsl_readl(&dr_regs->portsc1); - if ((enable) && !(temp & PORTSCX_PHY_LOW_POWER_SPD)) { + + if (enable) { + temp = fsl_readl(&dr_regs->portsc1); temp |= PORTSCX_PHY_LOW_POWER_SPD; fsl_writel(temp, &dr_regs->portsc1); if (udc_controller->pdata->usb_clock_for_pm) udc_controller->pdata->usb_clock_for_pm(false); - } else if ((!enable) && (temp & PORTSCX_PHY_LOW_POWER_SPD)) { + } else { if (udc_controller->pdata->usb_clock_for_pm) udc_controller->pdata->usb_clock_for_pm(true); + temp = fsl_readl(&dr_regs->portsc1); temp &= ~PORTSCX_PHY_LOW_POWER_SPD; fsl_writel(temp, &dr_regs->portsc1); } @@ -411,11 +413,7 @@ static void dr_controller_run(struct fsl_udc *udc) fsl_writel(temp, &dr_regs->usbintr); - /* If PHY clock is disabled, enable it */ - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(1); - - if (device_can_wakeup(udc_controller->gadget.dev.parent)) { + 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; @@ -424,7 +422,7 @@ static void dr_controller_run(struct fsl_udc *udc) /* If vbus not on and used low power mode */ if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID) - && device_can_wakeup(udc_controller->gadget.dev.parent)) { + && device_may_wakeup(udc_controller->gadget.dev.parent)) { /* enable wake up */ dr_wake_up_enable(udc, true); /* Set stopped before low power mode */ @@ -1939,8 +1937,7 @@ static void wake_up_irq(struct fsl_udc *udc) /* disable wake up irq */ dr_wake_up_enable(udc_controller, false); - if (udc_controller->pdata->usb_clock_for_pm) - udc_controller->pdata->usb_clock_for_pm(true); + udc->stopped = 0; } @@ -2030,16 +2027,21 @@ bool try_wake_up_udc(struct fsl_udc *udc) /* when udc is stopped, only handle wake up irq */ if (udc->stopped) { - if (!device_can_wakeup(&(udc->pdata->pdev->dev))) + 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) { wake_up_irq(udc); + } else { + dr_phy_low_power_mode(udc_controller, true); } } - if (!device_can_wakeup(udc_controller->gadget.dev.parent)) + if (!device_may_wakeup(udc_controller->gadget.dev.parent)) return true; /* check if Vbus change irq */ @@ -2151,6 +2153,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; @@ -2173,7 +2176,13 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) udc_controller->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc_controller->lock, flags); - dr_phy_low_power_mode(udc_controller, false); + 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(true); + /* bind udc driver to gadget driver */ retval = driver->bind(&udc_controller->gadget); if (retval) { @@ -2227,6 +2236,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; @@ -2237,11 +2247,12 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); - /* stop DR, disable intr */ - dr_controller_stop(udc_controller); /* open phy clock for following operation */ dr_phy_low_power_mode(udc_controller, false); + /* stop DR, disable intr */ + dr_controller_stop(udc_controller); + /* in fact, no needed */ udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; @@ -2264,7 +2275,13 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) udc_controller->driver = 0; 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); @@ -2662,7 +2679,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; int ret = -ENODEV; unsigned int i; - u32 dccparams; + u32 dccparams, portsc; if (strcmp(pdev->name, driver_name)) { VDBG("Wrong device\n"); @@ -2840,7 +2857,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev) dr_wake_up_enable(udc_controller, false); udc_controller->stopped = 1; - 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); create_proc_file(); return 0; @@ -2920,6 +2943,10 @@ static int udc_suspend(struct fsl_udc *udc) { u32 mode, usbcmd; + /* 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); @@ -2933,12 +2960,12 @@ static int udc_suspend(struct fsl_udc *udc) if (udc->stopped) { pr_debug("gadget already stopped, leaving early\n"); udc->already_stopped = 1; - return 0; + goto out; } if (mode != USB_MODE_CTRL_MODE_DEVICE) { pr_debug("gadget not in device mode, leaving early\n"); - return 0; + goto out; } udc->stopped = 1; @@ -2954,7 +2981,9 @@ static int udc_suspend(struct fsl_udc *udc) fsl_writel(usbcmd, &dr_regs->usbcmd); printk(KERN_INFO "USB Gadget suspended\n"); - +out: + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); return 0; } diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c index 57aa1a4fd64d..f05e97a57d58 100644 --- a/drivers/usb/host/ehci-arc.c +++ b/drivers/usb/host/ehci-arc.c @@ -269,6 +269,23 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, { struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + u32 tmp; + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + /* Need open clock for register access */ + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(true); + + tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); + if (tmp & PORT_PHCD) { + tmp &= ~PORT_PHCD; + ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); + msleep(100); + + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(false); + } + } /* DDD shouldn't we turn off the power here? */ fsl_platform_set_vbus_power(pdata, 0); @@ -446,6 +463,12 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, u32 tmp, port_status; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + if (device_may_wakeup(&(pdev->dev))) { + /* Need open clock for register access */ + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(true); + } + #ifdef DEBUG u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE); mode &= USBMODE_CM_MASK; @@ -464,7 +487,7 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, if (pdata->suspended) { pr_debug("%s: already suspended, leaving early\n", __func__); pdata->already_suspended = 1; - return 0; + goto err1; } pr_debug("%s: suspending...\n", __func__); @@ -472,17 +495,11 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, printk(KERN_INFO "USB Host suspended\n"); port_status = ehci_readl(ehci, &ehci->regs->port_status[0]); - hcd->state = HC_STATE_SUSPENDED; pdev->dev.power.power_state = PMSG_SUSPEND; /* ignore non-host interrupts */ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* stop the controller */ - tmp = ehci_readl(ehci, &ehci->regs->command); - tmp &= ~CMD_RUN; - ehci_writel(ehci, tmp, &ehci->regs->command); - /* save EHCI registers */ pdata->pm_command = ehci_readl(ehci, &ehci->regs->command); pdata->pm_command &= ~CMD_RUN; @@ -499,6 +516,9 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, /* clear the W1C bits */ pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS); + /* clear PHCD bit */ + pdata->pm_portsc &= ~PORT_PHCD; + pdata->suspended = 1; if (!device_may_wakeup(&(pdev->dev))) { @@ -506,45 +526,18 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); tmp &= ~PORT_POWER; ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - return 0; - } - - /* device_may_wakeup */ - if (!((ehci->transceiver) && - (readl(hcd->regs + 0x1A4) & (1 << 8)))) { - /* enable remote wake up irq */ - if (pdata->wake_up_enable) - pdata->wake_up_enable(pdata, true); - - /* We CAN NOT enable wake up by connetion and disconnection - * concurrently */ - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - /* if there is no usb device connectted */ - if (port_status & PORT_CONNECT) { - /* enable wake up by usb device disconnection */ - tmp |= PORT_WKDISC_E; - tmp &= ~(PORT_WKOC_E | PORT_WKCONN_E); - } else { - /* enable wake up by usb device insertion */ - tmp |= PORT_WKCONN_E; - tmp &= ~(PORT_WKOC_E | PORT_WKDISC_E); + goto err1; } - ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - - /* Set the port into suspend */ - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - tmp |= PORT_SUSPEND; - ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - /* Disable PHY clock */ tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - tmp |= (1 << 23); - ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - } if (pdata->platform_suspend) pdata->platform_suspend(pdata); - +err1: + if (device_may_wakeup(&(pdev->dev))) { + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(false); + } return 0; } @@ -573,15 +566,16 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) return 0; } + /* If hcd is resumed by non-usb wakeup events, + * then usb clocks are still not open when come here */ if (device_may_wakeup(&(pdev->dev))) { - tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); - if (tmp & (1 << 23)) { - tmp &= ~(1 << 23); - ehci_writel(ehci, tmp, &ehci->regs->port_status[0]); - msleep(10); - } + /* Need open clock for register access */ + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(true); } + tmp = ehci_readl(ehci, &ehci->regs->port_status[0]); + pdata->suspended = 0; pr_debug("%s resuming...\n", __func__); @@ -593,6 +587,7 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) pdata->platform_resume(pdata); /* restore EHCI registers */ + ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]); ehci_writel(ehci, pdata->pm_command, &ehci->regs->command); ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable); ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index); @@ -601,10 +596,14 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next); ehci_writel(ehci, pdata->pm_configured_flag, &ehci->regs->configured_flag); - ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - hcd->state = HC_STATE_RUNNING; + /* set bit should be done by wakeup irq routine if may wakeup */ + if (!device_may_wakeup(&(pdev->dev))) + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + else + while (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) + msleep(1); + pdev->dev.power.power_state = PMSG_ON; tmp = ehci_readl(ehci, &ehci->regs->command); @@ -614,6 +613,12 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev) usb_hcd_resume_root_hub(hcd); printk(KERN_INFO "USB Host resumed\n"); + + if (device_may_wakeup(&(pdev->dev))) { + if (pdata->usb_clock_for_pm) + pdata->usb_clock_for_pm(false); + } + return 0; } #endif /* CONFIG_USB_OTG */ |