diff options
author | Felipe Balbi <balbi@ti.com> | 2014-02-25 21:47:54 +0100 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-03-05 16:44:50 +0100 |
commit | e1dadd3b0f277e59847d6b7de86ff67306bee4b1 (patch) | |
tree | 32b8c2b41f6b57b8ff4aa5acc1b60525cf15dfb0 /drivers/usb/dwc3/gadget.c | |
parent | usb: dwc3: workaround: clock gating issues (diff) | |
download | linux-e1dadd3b0f277e59847d6b7de86ff67306bee4b1.tar.xz linux-e1dadd3b0f277e59847d6b7de86ff67306bee4b1.zip |
usb: dwc3: workaround: bogus hibernation events
Revision 2.20a of the core has a known issue
which would generate bogus hibernation events
_and_ random failures on USB CV TD.9.23 test
case.
The suggested workaround is to ignore hibernation
events which don't match currently connected
speed.
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 31 |
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 9e878d9bc909..7f4e6dd63c00 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2378,6 +2378,30 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); } +static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, + unsigned int evtinfo) +{ + unsigned int is_ss = evtinfo & BIT(4); + + /** + * WORKAROUND: DWC3 revison 2.20a with hibernation support + * have a known issue which can cause USB CV TD.9.23 to fail + * randomly. + * + * Because of this issue, core could generate bogus hibernation + * events which SW needs to ignore. + * + * Refers to: + * + * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0 + * Device Fallback from SuperSpeed + */ + if (is_ss ^ (dwc->speed == USB_SPEED_SUPER)) + return; + + /* enter hibernation here */ +} + static void dwc3_gadget_interrupt(struct dwc3 *dwc, const struct dwc3_event_devt *event) { @@ -2394,6 +2418,13 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, case DWC3_DEVICE_EVENT_WAKEUP: dwc3_gadget_wakeup_interrupt(dwc); break; + case DWC3_DEVICE_EVENT_HIBER_REQ: + if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, + "unexpected hibernation event\n")) + break; + + dwc3_gadget_hibernation_interrupt(dwc, event->event_info); + break; case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE: dwc3_gadget_linksts_change_interrupt(dwc, event->event_info); break; |