aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authormake shi <b15407@freescale.com>2011-11-04 17:24:05 +0800
committerEric Miao <eric.miao@canonical.com>2011-11-10 07:39:05 +0800
commited7b5053122dd296bd82bb2c8b27cea35e47d76c (patch)
tree776213a01e90d3b95d61fb2b9b38141339f56972 /drivers
parent9134219dda3772ff2a924eb3f78692e5b371b95f (diff)
ENGR00161383 [MX6Q] USB OTG: enable OTG driver
Enable OTG driver on mx6q board Signed-off-by: make shi <b15407@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/gadget/arcotg_udc.c87
-rw-r--r--drivers/usb/gadget/arcotg_udc.h1
-rw-r--r--drivers/usb/host/ehci-arc.c5
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);