diff options
-rw-r--r-- | chip/stm32/usb.c | 29 |
1 files changed, 28 insertions, 1 deletions
diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c index 4aec16f8d3..57e629a3d1 100644 --- a/chip/stm32/usb.c +++ b/chip/stm32/usb.c @@ -460,13 +460,34 @@ void board_usb_wake(void) /* Side-band USB wake, do nothing by default. */ } +/* Called 10ms after usb_wake started. */ +static void usb_wake_deferred(void) +{ + if (esof_count == 3) { + /* + * If we reach here, it means that we are not counting ESOF/SOF + * properly (either of these interrupts should occur every 1ms). + * This should never happen if we implemented the resume logic + * correctly. + * + * We reset the controller in that case, which recovers the + * interface. + */ + CPRINTF("USB stuck\n"); + STM32_RCC_APB1RSTR |= STM32_RCC_PB1_USB; + STM32_RCC_APB1RSTR &= ~STM32_RCC_PB1_USB; + usb_init(); + } +} +DECLARE_DEFERRED(usb_wake_deferred); + void usb_wake(void) { if (!remote_wakeup_enabled || !(STM32_USB_CNTR & STM32_USB_CNTR_FSUSP)) { /* * USB wake not enabled, or already woken up, or already waking - * up,nothing to do. + * up, nothing to do. */ return; } @@ -478,6 +499,12 @@ void usb_wake(void) CPRINTF("WAKE\n"); /* + * Sometimes the USB controller gets stuck, and does not count SOF/ESOF + * frames anymore, detect that. + */ + hook_call_deferred(&usb_wake_deferred_data, 10 * MSEC); + + /* * Set RESUME bit for 1 to 15 ms, then clear it. We ask the interrupt * routine to count 3 ESOF interrupts, which should take between * 2 and 3 ms. |