summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/arcotg_udc.c
diff options
context:
space:
mode:
authorHu hui <b29976@freescale.com>2010-10-12 14:09:47 +0800
committerHu Hui <b29976@freescale.com>2010-10-13 10:33:54 +0800
commitb083bdc50fa42eaf639f8a121b7359dfcc98adce (patch)
treed1f6c4fe0e54eaeeb3c2092dc60d4d4d9ba8ac68 /drivers/usb/gadget/arcotg_udc.c
parent2a769d0843947b44b107807af75e682404efa4dd (diff)
ENGR00132477-3 IMX USB:fix some wakeup releated issues
Driver Part 1. add pm_mutex lock/unlock in the device/host switch function. 2. use private workqueue instead of the system default workqueue 3. fix the issue: gadget class driver must be loaded when wakeup function is enabled 4. in udc_resume, use mdelay(3) instead of mdelay(1) after put phy out of low power mode, because of the debounce for some status bit of the otgsc register 5. in fsl_ep_queue, we must make sure that the ep->desc is not NULL, as the ep_index will use the ep->desc Signed-off-by: Hu Hui <b29976@freescale.com>
Diffstat (limited to 'drivers/usb/gadget/arcotg_udc.c')
-rw-r--r--drivers/usb/gadget/arcotg_udc.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c
index a31c956f66dc..90edc5597f0e 100644
--- a/drivers/usb/gadget/arcotg_udc.c
+++ b/drivers/usb/gadget/arcotg_udc.c
@@ -1072,16 +1072,16 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
unsigned long flags;
int is_iso = 0;
+ if (!_ep || (!ep->desc && ep_index(ep))) {
+ VDBG("%s, bad ep\n", __func__);
+ return -EINVAL;
+ }
/* catch various bogus parameters */
if (!_req || !req->req.buf || (ep_index(ep)
&& !list_empty(&req->queue))) {
VDBG("%s, bad params\n", __func__);
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep_index(ep))) {
- VDBG("%s, bad ep\n", __func__);
- return -EINVAL;
- }
if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
if (req->req.length > ep->ep.maxpacket)
return -EMSGSIZE;
@@ -2036,7 +2036,13 @@ static void suspend_irq(struct fsl_udc *udc)
/* 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);
+#ifdef CONFIG_USB_OTG
+ /* if no gadget register in this driver, we need clear the wakeup event */
+ if (udc->transceiver->gadget == NULL)
+ dr_wake_up_enable(udc_controller, true);
+ else
+#endif
+ dr_phy_low_power_mode(udc, false);
pr_debug("at %s: device wake up event\n", __func__);
return true;
} else {/* wakeup is vbus wake event, but not for device so we need to clear b session */
@@ -2164,7 +2170,7 @@ bool try_wake_up_udc(struct fsl_udc *udc)
static irqreturn_t fsl_udc_irq(int irq, void *_udc)
{
struct fsl_udc *udc = _udc;
- u32 irq_src;
+ u32 irq_src, clr_remain_irq = 0;
irqreturn_t status = IRQ_NONE;
unsigned long flags;
@@ -2173,19 +2179,21 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
dr_clk_gate(true);
if (try_wake_up_udc(udc) == false) {
+ clr_remain_irq = 1;
goto irq_end;
}
#ifdef CONFIG_USB_OTG
/* if no gadget register in this driver, we need do noting */
if (udc->transceiver->gadget == NULL)
+ clr_remain_irq = 1;
goto irq_end;
/* only handle device interrupt event */
if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) {
+ clr_remain_irq = 1;
goto irq_end;
}
#endif
-
irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr);
/* Clear notification bits */
fsl_writel(irq_src, &dr_regs->usbsts);
@@ -2245,6 +2253,13 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
}
irq_end:
+ /* clear the unprocessed events(mainly PCD bit).
+ * this isr is the last on the shared irq
+ * chain, so we can clear the remained events */
+ if (clr_remain_irq) {
+ irq_src = fsl_readl(&dr_regs->usbsts);
+ fsl_writel(irq_src, &dr_regs->usbsts);
+ }
if (udc->stopped) {
dr_clk_gate(false);
}
@@ -3195,8 +3210,7 @@ static int fsl_udc_resume(struct platform_device *pdev)
}
dr_wake_up_enable(udc_controller, false);
dr_phy_low_power_mode(udc_controller, false);
- mdelay(1);
-
+ mdelay(3);/* IC have the debounce for ID\vbus status in otgsc */
dr_controller_setup(udc_controller);
dr_controller_run(udc_controller);
}