From ed7b5053122dd296bd82bb2c8b27cea35e47d76c Mon Sep 17 00:00:00 2001 From: make shi Date: Fri, 4 Nov 2011 17:24:05 +0800 Subject: ENGR00161383 [MX6Q] USB OTG: enable OTG driver Enable OTG driver on mx6q board Signed-off-by: make shi --- drivers/usb/gadget/arcotg_udc.c | 87 +++++++++++++++++++++++++++-------------- drivers/usb/gadget/arcotg_udc.h | 1 - drivers/usb/host/ehci-arc.c | 5 +-- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index ccd8591134a..8d35728dbb4 100644 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -2021,9 +2021,6 @@ static void suspend_irq(struct fsl_udc *udc) otgsc |= OTGSC_CTRL_VBUS_DISCHARGE; fsl_writel(otgsc, &dr_regs->otgsc); - /* discharge in work queue */ - __cancel_delayed_work(&udc->gadget_delay_work); - schedule_delayed_work(&udc->gadget_delay_work, msecs_to_jiffies(20)); /* report suspend to the driver, serial.c does not support this */ if (udc->driver->suspend) @@ -2098,6 +2095,7 @@ static void fsl_gadget_event(struct work_struct *work) { struct fsl_udc *udc = udc_controller; unsigned long flags; + u32 tmp; if (udc->driver) udc->driver->disconnect(&udc->gadget); @@ -2109,6 +2107,13 @@ static void fsl_gadget_event(struct work_struct *work) udc->stopped = 1; /* enable wake up */ dr_wake_up_enable(udc, true); + /* here we need to enable the B_SESSION_IRQ + * to enable the following device attach + */ + tmp = fsl_readl(&dr_regs->otgsc); + if (!(tmp & (OTGSC_B_SESSION_VALID_IRQ_EN))) + fsl_writel(tmp | (OTGSC_B_SESSION_VALID_IRQ_EN), + &dr_regs->otgsc); /* close USB PHY clock */ dr_phy_low_power_mode(udc, true); /* close dr controller clock */ @@ -2116,20 +2121,6 @@ static void fsl_gadget_event(struct work_struct *work) printk(KERN_DEBUG "%s: udc enter low power mode\n", __func__); } -static void fsl_gadget_delay_event(struct work_struct *work) -{ - u32 otgsc = 0; - - dr_clk_gate(true); - otgsc = fsl_readl(&dr_regs->otgsc); - /* clear vbus discharge */ - if (otgsc & OTGSC_CTRL_VBUS_DISCHARGE) { - otgsc &= ~(OTGSC_INTSTS_MASK | OTGSC_CTRL_VBUS_DISCHARGE); - fsl_writel(otgsc, &dr_regs->otgsc); - } - dr_clk_gate(false); -} - /* if wakup udc, return true; else return false*/ bool try_wake_up_udc(struct fsl_udc *udc) { @@ -2162,7 +2153,21 @@ bool try_wake_up_udc(struct fsl_udc *udc) printk(KERN_DEBUG "%s: udc out low power mode\n", __func__); } else { fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd); - schedule_work(&udc->gadget_work); + /* here we need disable B_SESSION_IRQ, after + * schedule_work finished, it need to be enabled again. + * Doing like this can avoid conflicting between rapid + * plug in/out. + */ + tmp = fsl_readl(&dr_regs->otgsc); + if (tmp & (OTGSC_B_SESSION_VALID_IRQ_EN)) + fsl_writel(tmp & + (~OTGSC_B_SESSION_VALID_IRQ_EN), + &dr_regs->otgsc); + /*here we need delay 30 ms for avoid exception usb vbus falling interrupt + Once we clear the RS bit, D+ D- need about 20 ms to SE0 modet ,during this period + we can not enable device wake up + */ + schedule_delayed_work(&udc->gadget_delay_work, msecs_to_jiffies(30)); return false; } } @@ -2201,7 +2206,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr); /* Clear notification bits */ fsl_writel(irq_src, &dr_regs->usbsts); - pr_debug("%s: 0x%x\n", __func__, irq_src); + + /* only handle enabled interrupt */ + if (irq_src == 0x0) + goto irq_end; + + VDBG("0x%x\n", irq_src); /* Need to resume? */ if (udc->usb_state == USB_STATE_SUSPENDED) @@ -2247,7 +2257,8 @@ 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); + if (!(udc->usb_state == USB_STATE_SUSPENDED)) + suspend_irq(udc); status = IRQ_HANDLED; } @@ -2309,9 +2320,11 @@ int usb_gadget_probe_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 */ - printk(KERN_DEBUG "Suspend udc for OTG auto detect\n"); + if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) + udc_controller->suspended = 1; + else + udc_controller->suspended = 0; + printk(KERN_INFO "Suspend udc for OTG auto detect\n"); dr_wake_up_enable(udc_controller, true); dr_clk_gate(false); /* export udc suspend/resume call to OTG */ @@ -2943,9 +2956,7 @@ static int __devinit fsl_udc_probe(struct platform_device *pdev) } } - INIT_WORK(&udc_controller->gadget_work, fsl_gadget_event); - INIT_DELAYED_WORK(&udc_controller->gadget_delay_work, - fsl_gadget_delay_event); + INIT_DELAYED_WORK(&udc_controller->gadget_delay_work, fsl_gadget_event); #ifdef POSTPONE_FREE_LAST_DTD last_free_td = NULL; #endif @@ -3168,10 +3179,9 @@ static int fsl_udc_resume(struct platform_device *pdev) struct fsl_usb2_wakeup_platform_data *wake_up_pdata = pdata->wakeup_pdata; printk(KERN_DEBUG "USB Gadget resume begins\n"); - if (pdata->pmflags == 0) { - printk(KERN_DEBUG "%s, Wait for wakeup thread finishes\n", __func__); - wait_event_interruptible(wake_up_pdata->wq, !wake_up_pdata->usb_wakeup_is_pending); - } + printk(KERN_DEBUG "%s, Wait for wakeup thread finishes\n", __func__); + wait_event_interruptible(wake_up_pdata->wq, !wake_up_pdata->usb_wakeup_is_pending); + #ifdef CONFIG_USB_OTG if (udc_controller->transceiver->gadget == NULL) { @@ -3184,9 +3194,25 @@ static int fsl_udc_resume(struct platform_device *pdev) udc_controller->stopped, udc_controller->suspended); /* Do noop if the udc is already at resume state */ if (udc_controller->suspended == 0) { + u32 temp; + if (udc_controller->stopped) + dr_clk_gate(true); + usb_debounce_id_vbus(); + if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) { + temp = fsl_readl(&dr_regs->otgsc); + /* if b_session_irq_en is cleared by otg */ + if (!(temp & OTGSC_B_SESSION_VALID_IRQ_EN)) { + temp |= OTGSC_B_SESSION_VALID_IRQ_EN; + fsl_writel(temp, &dr_regs->otgsc); + } + } + if (udc_controller->stopped) + dr_clk_gate(false); mutex_unlock(&udc_resume_mutex); return 0; } + /* prevent the quirk interrupts from resuming */ + disable_irq_nosync(udc_controller->irq); /* * If the controller was stopped at suspend time, then @@ -3239,6 +3265,7 @@ end: dr_clk_gate(false); } --udc_controller->suspended; + enable_irq(udc_controller->irq); mutex_unlock(&udc_resume_mutex); printk(KERN_DEBUG "USB Gadget resume ends\n"); return 0; diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h index 6f141c66ba8..eb92e470a7f 100644 --- a/drivers/usb/gadget/arcotg_udc.h +++ b/drivers/usb/gadget/arcotg_udc.h @@ -624,7 +624,6 @@ struct fsl_udc { struct completion *done; /* to make sure release() is done */ u32 iram_buffer[IRAM_PPH_NTD]; void *iram_buffer_v[IRAM_PPH_NTD]; - struct work_struct gadget_work; struct delayed_work gadget_delay_work; }; diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c index 9ab9531e0ab..5ccfdf8e7b2 100644 --- a/drivers/usb/host/ehci-arc.c +++ b/drivers/usb/host/ehci-arc.c @@ -469,7 +469,6 @@ static int ehci_fsl_bus_resume(struct usb_hcd *hcd) if (pdata->platform_resume) pdata->platform_resume(pdata); - ehci->command = pdata->pm_command; ret = ehci_bus_resume(hcd); if (ret) return ret; @@ -691,8 +690,8 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, port_status = ehci_readl(ehci, &ehci->regs->port_status[0]); /* save EHCI registers */ -/* pdata->pm_command = ehci_readl(ehci, &ehci->regs->command); */ -/* pdata->pm_command &= ~CMD_RUN; */ + pdata->pm_command = ehci_readl(ehci, &ehci->regs->command); + pdata->pm_command &= ~CMD_RUN; pdata->pm_status = ehci_readl(ehci, &ehci->regs->status); pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable); pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index); -- cgit v1.2.3