@@ -31,6 +31,8 @@ enum dwc2_drv_event_type {
3131 DWC2_DRV_EVT_SETUP ,
3232 /* Transaction on endpoint is finished */
3333 DWC2_DRV_EVT_EP_FINISHED ,
34+ /* Core should enter hibernation */
35+ DWC2_DRV_EVT_ENTER_HIBERNATION ,
3436 /* Core should exit hibernation due to bus reset */
3537 DWC2_DRV_EVT_HIBERNATION_EXIT_BUS_RESET ,
3638 /* Core should exit hibernation due to host resume */
@@ -1075,6 +1077,18 @@ static void dwc2_exit_hibernation(const struct device *dev)
10751077 LOG_DBG ("Hibernation exit complete" );
10761078}
10771079
1080+ static void cancel_hibernation_request (struct udc_dwc2_data * const priv )
1081+ {
1082+ k_event_clear (& priv -> drv_evt , BIT (DWC2_DRV_EVT_ENTER_HIBERNATION ));
1083+ }
1084+
1085+ static void request_hibernation (struct udc_dwc2_data * const priv )
1086+ {
1087+ if (priv -> suspend_type == DWC2_SUSPEND_HIBERNATION ) {
1088+ k_event_post (& priv -> drv_evt , BIT (DWC2_DRV_EVT_ENTER_HIBERNATION ));
1089+ }
1090+ }
1091+
10781092static void dwc2_unset_unused_fifo (const struct device * dev )
10791093{
10801094 struct udc_dwc2_data * const priv = udc_get_private (dev );
@@ -2624,6 +2638,8 @@ static void udc_dwc2_isr_handler(const struct device *dev)
26242638 sys_write32 (USB_DWC2_GINTSTS_USBRST , gintsts_reg );
26252639 dwc2_on_bus_reset (dev );
26262640 LOG_DBG ("USB Reset interrupt" );
2641+
2642+ cancel_hibernation_request (priv );
26272643 }
26282644
26292645 if (int_status & USB_DWC2_GINTSTS_ENUMDONE ) {
@@ -2638,6 +2654,8 @@ static void udc_dwc2_isr_handler(const struct device *dev)
26382654 sys_write32 (USB_DWC2_GINTSTS_WKUPINT , gintsts_reg );
26392655 udc_set_suspended (dev , false);
26402656 udc_submit_event (dev , UDC_EVT_RESUME , 0 );
2657+
2658+ cancel_hibernation_request (priv );
26412659 }
26422660
26432661 if (int_status & USB_DWC2_GINTSTS_IEPINT ) {
@@ -2664,30 +2682,53 @@ static void udc_dwc2_isr_handler(const struct device *dev)
26642682 }
26652683
26662684 if (int_status & USB_DWC2_GINTSTS_USBSUSP ) {
2685+ /* Clear USB Suspend interrupt. */
2686+ sys_write32 (USB_DWC2_GINTSTS_USBSUSP , gintsts_reg );
2687+
26672688 if (!priv -> enumdone ) {
2668- /* Clear stale suspend interrupt */
2669- sys_write32 (USB_DWC2_GINTSTS_USBSUSP , gintsts_reg );
2689+ /* Ignore stale suspend interrupt */
26702690 continue ;
26712691 }
26722692
26732693 /* Notify the stack */
26742694 udc_set_suspended (dev , true);
26752695 udc_submit_event (dev , UDC_EVT_SUSPEND , 0 );
26762696
2677- if (priv -> suspend_type == DWC2_SUSPEND_HIBERNATION ) {
2678- dwc2_enter_hibernation (dev );
2679- /* Next interrupt will be from PMU */
2680- break ;
2681- }
2682-
2683- /* Clear USB Suspend interrupt. */
2684- sys_write32 (USB_DWC2_GINTSTS_USBSUSP , gintsts_reg );
2697+ request_hibernation (priv );
26852698 }
26862699 }
26872700
26882701 (void )dwc2_quirk_irq_clear (dev );
26892702}
26902703
2704+ static void dwc2_handle_hibernation_exit (const struct device * dev ,
2705+ bool bus_reset )
2706+ {
2707+ struct udc_dwc2_data * const priv = udc_get_private (dev );
2708+
2709+ dwc2_exit_hibernation (dev );
2710+
2711+ /* Let stack know we are no longer suspended */
2712+ udc_set_suspended (dev , false);
2713+ udc_submit_event (dev , UDC_EVT_RESUME , 0 );
2714+
2715+ if (bus_reset ) {
2716+ /* Clear all pending transfers */
2717+ k_event_clear (& priv -> xfer_new , UINT32_MAX );
2718+ k_event_clear (& priv -> xfer_finished , UINT32_MAX );
2719+ dwc2_on_bus_reset (dev );
2720+ } else {
2721+ /* Resume any pending transfer handling */
2722+ if (k_event_test (& priv -> xfer_new , UINT32_MAX )) {
2723+ k_event_post (& priv -> drv_evt , BIT (DWC2_DRV_EVT_XFER ));
2724+ }
2725+
2726+ if (k_event_test (& priv -> xfer_finished , UINT32_MAX )) {
2727+ k_event_post (& priv -> drv_evt , BIT (DWC2_DRV_EVT_EP_FINISHED ));
2728+ }
2729+ }
2730+ }
2731+
26912732static uint8_t pull_next_ep_from_bitmap (uint32_t * bitmap )
26922733{
26932734 unsigned int bit ;
@@ -2727,9 +2768,14 @@ static ALWAYS_INLINE void dwc2_thread_handler(void *const arg)
27272768 if (evt & BIT (DWC2_DRV_EVT_XFER )) {
27282769 k_event_clear (& priv -> drv_evt , BIT (DWC2_DRV_EVT_XFER ));
27292770
2730- LOG_DBG ("New transfer(s) in the queue" );
2731- eps = k_event_test (& priv -> xfer_new , UINT32_MAX );
2732- k_event_clear (& priv -> xfer_new , eps );
2771+ if (!priv -> hibernated ) {
2772+ LOG_DBG ("New transfer(s) in the queue" );
2773+ eps = k_event_test (& priv -> xfer_new , UINT32_MAX );
2774+ k_event_clear (& priv -> xfer_new , eps );
2775+ } else {
2776+ /* Events will be handled after hibernation exit */
2777+ eps = 0 ;
2778+ }
27332779
27342780 while (eps ) {
27352781 ep = pull_next_ep_from_bitmap (& eps );
@@ -2746,8 +2792,13 @@ static ALWAYS_INLINE void dwc2_thread_handler(void *const arg)
27462792 if (evt & BIT (DWC2_DRV_EVT_EP_FINISHED )) {
27472793 k_event_clear (& priv -> drv_evt , BIT (DWC2_DRV_EVT_EP_FINISHED ));
27482794
2749- eps = k_event_test (& priv -> xfer_finished , UINT32_MAX );
2750- k_event_clear (& priv -> xfer_finished , eps );
2795+ if (!priv -> hibernated ) {
2796+ eps = k_event_test (& priv -> xfer_finished , UINT32_MAX );
2797+ k_event_clear (& priv -> xfer_finished , eps );
2798+ } else {
2799+ /* Events will be handled after hibernation exit */
2800+ eps = 0 ;
2801+ }
27512802
27522803 while (eps ) {
27532804 ep = pull_next_ep_from_bitmap (& eps );
@@ -2776,22 +2827,30 @@ static ALWAYS_INLINE void dwc2_thread_handler(void *const arg)
27762827 dwc2_handle_evt_setup (dev );
27772828 }
27782829
2830+ if (evt & BIT (DWC2_DRV_EVT_ENTER_HIBERNATION )) {
2831+ config -> irq_disable_func (dev );
2832+
2833+ prev = k_event_clear (& priv -> drv_evt , BIT (DWC2_DRV_EVT_ENTER_HIBERNATION ));
2834+
2835+ /* Only enter hibernation if IRQ did not cancel the request */
2836+ if (prev & BIT (DWC2_DRV_EVT_ENTER_HIBERNATION )) {
2837+ dwc2_enter_hibernation (dev );
2838+ }
2839+
2840+ config -> irq_enable_func (dev );
2841+ }
2842+
27792843 if (evt & hibernation_exit_events ) {
2844+ bool bus_reset ;
2845+
27802846 LOG_DBG ("Hibernation exit event" );
27812847 config -> irq_disable_func (dev );
27822848
27832849 prev = k_event_clear (& priv -> drv_evt , hibernation_exit_events );
2850+ bus_reset = prev & BIT (DWC2_DRV_EVT_HIBERNATION_EXIT_BUS_RESET );
27842851
27852852 if (priv -> hibernated ) {
2786- dwc2_exit_hibernation (dev );
2787-
2788- /* Let stack know we are no longer suspended */
2789- udc_set_suspended (dev , false);
2790- udc_submit_event (dev , UDC_EVT_RESUME , 0 );
2791-
2792- if (prev & BIT (DWC2_DRV_EVT_HIBERNATION_EXIT_BUS_RESET )) {
2793- dwc2_on_bus_reset (dev );
2794- }
2853+ dwc2_handle_hibernation_exit (dev , bus_reset );
27952854 }
27962855
27972856 config -> irq_enable_func (dev );
0 commit comments