diff options
author | Peter Chen <peter.chen@freescale.com> | 2011-11-18 14:01:06 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2012-01-09 21:07:22 +0800 |
commit | 4ecfcfd2a9abc3bcca35056a2e077352c70c6daa (patch) | |
tree | 8bcb7803dc4ea1e313aa1c639eabeb4831e27ad7 /drivers/usb/otg | |
parent | a7dacc3fc8231ba21d2b5f1b95b7a40c1ba3c0f6 (diff) |
ENGR00162583-2 usb driver: avoid class driver access register after usb is off
- An well-behavior class driver should disable their endpoints
after being notified disconnect with host, we use all endpoints
are stopped (ep->stopped) to indicates the class
driver will not visit device driver any more.
the ep-stopped will be initialized as 1 for non-control endpoint
it will be 0 after fsl_ep_enable, and be 1 after fsl_ep_disable.
Where is a non-sleep wait routine at disconnect event for waiting all
endpoints are stopped
- Some controller's (like i.mx6q) DP will change from J
to SE0 slowly after the cable disconnects with host, in that case there
will be a wakeup interrupt after driver enables the wakeup interrupt.
For i.mx6q, there is a discharge routine for DP after the disconnection.
- Should not wait vbus to low during first otg switch, as the wait will
be timeout when the usb cable is connecting to host.
Signed-off-by: Peter Chen <peter.chen@freescale.com>
Diffstat (limited to 'drivers/usb/otg')
-rwxr-xr-x | drivers/usb/otg/fsl_otg.c | 18 | ||||
-rwxr-xr-x | drivers/usb/otg/fsl_otg.h | 2 |
2 files changed, 15 insertions, 5 deletions
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c index a30815cba3f1..be8e0160a197 100755 --- a/drivers/usb/otg/fsl_otg.c +++ b/drivers/usb/otg/fsl_otg.c @@ -168,11 +168,11 @@ static void fsl_otg_wait_stable_vbus(bool on) fsl_otg_clk_gate(true); /* Wait for vbus change to B_SESSION_VALID complete */ timeout = jiffies + FSL_VBUS_CHANGE_TIMEOUT; - while ((le32_to_cpu(usb_dr_regs->otgsc)&OTGSC_INTSTS_B_SESSION_VALID) == !on) { + while ((le32_to_cpu(usb_dr_regs->otgsc)&OTGSC_STS_B_SESSION_VALID) != (on << 11)) { if (time_after(jiffies, timeout)) { printk(KERN_ERR"wait otg vbus change timeout! \n"); fsl_otg_clk_gate(false); - break; + return; } msleep(10); } @@ -619,8 +619,11 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host) * so suspend the host after a short delay. */ otg_dev->host_working = 1; - if (otg_dev->fsm.id) + + if (otg_dev->fsm.id) { + otg_dev->host_first_call = true; schedule_otg_work(&otg_dev->otg_event, 100); + } else { /* if the device is already at the port */ otg_drv_vbus(&otg_dev->fsm, 1); @@ -733,8 +736,12 @@ static void fsl_otg_event(struct work_struct *work) if (fsm->id) { /* switch to gadget */ fsl_otg_start_host(fsm, 0); otg_drv_vbus(fsm, 0); - fsl_otg_wait_stable_vbus(false); - fsl_otg_wait_dischrg_vbus(); + if (og->host_first_call == false) { + fsl_otg_wait_dischrg_vbus(); + fsl_otg_wait_stable_vbus(false); + } else { + og->host_first_call = false; + } b_session_irq_enable(false); fsl_otg_start_gadget(fsm, 1); } else { /* switch to host */ @@ -943,6 +950,7 @@ static int fsl_otg_conf(struct platform_device *pdev) fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp; fsl_otg_tc->otg.start_srp = fsl_otg_start_srp; fsl_otg_tc->otg.dev = &pdev->dev; + fsl_otg_tc->host_first_call = false; fsl_otg_dev = fsl_otg_tc; diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/otg/fsl_otg.h index a8536815d0bf..d3d382bd8e32 100755 --- a/drivers/usb/otg/fsl_otg.h +++ b/drivers/usb/otg/fsl_otg.h @@ -385,6 +385,8 @@ struct fsl_otg { /*used for usb host */ struct work_struct work_wq; u8 host_working; + /*Used for host init call,we need to avoid discharge Vbus when usb cable connect to PC*/ + bool host_first_call; int irq; }; |