summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/arcotg_udc.c77
-rw-r--r--drivers/usb/host/ehci-arc.c103
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 */