@@ -315,6 +315,190 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE)
315315
316316#endif  /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs) */ 
317317
318+ #if  DT_HAS_COMPAT_STATUS_OKAY (nordic_nrf_usbhs_nrf54l )
319+ 
320+ #define  DT_DRV_COMPAT  snps_dwc2
321+ 
322+ #define  USBHS_DT_WRAPPER_REG_ADDR (n ) UINT_TO_POINTER(DT_INST_REG_ADDR_BY_NAME(n, wrapper))
323+ 
324+ #include  <nrf.h> 
325+ 
326+ #define  NRF_DEFAULT_IRQ_PRIORITY  1
327+ 
328+ /* 
329+  * On USBHS, we cannot access the DWC2 register until VBUS is detected and 
330+  * valid. If the user tries to force usbd_enable() and the corresponding 
331+  * udc_enable() without a "VBUS ready" notification, the event wait will block 
332+  * until a valid VBUS signal is detected or until the 
333+  * CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT timeout expires. 
334+  */ 
335+ static  K_EVENT_DEFINE (usbhs_events );
336+ #define  USBHS_VBUS_READY 	BIT(0)
337+ 
338+ static  void  vregusb_isr (const  void  * arg )
339+ {
340+ 	const  struct  device  * dev  =  arg ;
341+ 
342+ 	if  (NRF_VREGUSB -> EVENTS_VBUSDETECTED ) {
343+ 		NRF_VREGUSB -> EVENTS_VBUSDETECTED  =  0 ;
344+ 		k_event_post (& usbhs_events , USBHS_VBUS_READY );
345+ 		udc_submit_event (dev , UDC_EVT_VBUS_READY , 0 );
346+ 	}
347+ 
348+ 	if  (NRF_VREGUSB -> EVENTS_VBUSREMOVED ) {
349+ 		NRF_VREGUSB -> EVENTS_VBUSREMOVED  =  0 ;
350+ 		k_event_set_masked (& usbhs_events , 0 , USBHS_VBUS_READY );
351+ 		udc_submit_event (dev , UDC_EVT_VBUS_REMOVED , 0 );
352+ 	}
353+ }
354+ 
355+ static  inline  int  usbhs_enable_vreg (const  struct  device  * dev )
356+ {
357+ 	IRQ_CONNECT (VREGUSB_IRQn , NRF_DEFAULT_IRQ_PRIORITY ,
358+ 		    vregusb_isr , DEVICE_DT_INST_GET (0 ), 0 );
359+ 
360+ 	NRF_VREGUSB -> INTEN  =  VREGUSB_INTEN_VBUSDETECTED_Msk  |
361+ 			     VREGUSB_INTEN_VBUSREMOVED_Msk ;
362+ 	NRF_VREGUSB -> TASKS_START  =  1 ;
363+ 
364+ 	/* TODO: Determine conditions when VBUSDETECTED is not generated */ 
365+ 	if  (sys_read32 ((mem_addr_t )NRF_VREGUSB  +  0x400 ) &  BIT (2 )) {
366+ 		k_event_post (& usbhs_events , USBHS_VBUS_READY );
367+ 		udc_submit_event (dev , UDC_EVT_VBUS_READY , 0 );
368+ 	}
369+ 
370+ 	irq_enable (VREGUSB_IRQn );
371+ 
372+ 	return  0 ;
373+ }
374+ 
375+ static  inline  int  usbhs_enable_core (const  struct  device  * dev )
376+ {
377+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
378+ 	k_timeout_t  timeout  =  K_FOREVER ;
379+ 
380+ 	if  (!k_event_wait (& usbhs_events , USBHS_VBUS_READY , false, K_NO_WAIT )) {
381+ 		LOG_WRN ("VBUS is not ready, block udc_enable()" );
382+ 		if  (!k_event_wait (& usbhs_events , USBHS_VBUS_READY , false, timeout )) {
383+ 			return  - ETIMEDOUT ;
384+ 		}
385+ 	}
386+ 
387+ 	/* TODO: Request PCLK24M using clock control driver */ 
388+ 	NRF_CLOCK -> TASKS_XO24MSTART  =  1 ;
389+ 	while  (NRF_CLOCK -> EVENTS_XO24MSTARTED  ==  0 );
390+ 
391+ 	/* Power up peripheral */ 
392+ 	wrapper -> ENABLE  =  USBHS_ENABLE_CORE_Msk ;
393+ 
394+ 	/* Set ID to Device and force D+ pull-up off for now */ 
395+ 	wrapper -> PHY .OVERRIDEVALUES  =  (1  << 31 );
396+ 	wrapper -> PHY .INPUTOVERRIDE  =  (1  << 31 ) | USBHS_PHY_INPUTOVERRIDE_VBUSVALID_Msk ;
397+ 
398+ 	/* Release PHY power-on reset */ 
399+ 	wrapper -> ENABLE  =  USBHS_ENABLE_PHY_Msk  | USBHS_ENABLE_CORE_Msk ;
400+ 
401+ 	/* Wait for PHY clock to start */ 
402+ 	k_busy_wait (45 );
403+ 
404+ 	/* Release DWC2 reset */ 
405+ 	wrapper -> TASKS_START  =  1UL ;
406+ 
407+ 	/* Wait for clock to start to avoid hang on too early register read */ 
408+ 	k_busy_wait (1 );
409+ 
410+ 	/* DWC2 opmode is now guaranteed to be Non-Driving, allow D+ pull-up to 
411+ 	 * become active once driver clears DCTL SftDiscon bit. 
412+ 	 */ 
413+ 	wrapper -> PHY .INPUTOVERRIDE  =  (1  << 31 );
414+ 
415+ 	return  0 ;
416+ }
417+ 
418+ static  inline  int  usbhs_disable_core (const  struct  device  * dev )
419+ {
420+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
421+ 
422+ 	/* Set ID to Device and forcefully disable D+ pull-up */ 
423+ 	wrapper -> PHY .OVERRIDEVALUES  =  (1  << 31 );
424+ 	wrapper -> PHY .INPUTOVERRIDE  =  (1  << 31 ) | USBHS_PHY_INPUTOVERRIDE_VBUSVALID_Msk ;
425+ 
426+ 	wrapper -> ENABLE  =  0UL ;
427+ 
428+ 	/* TODO: Release PCLK24M using clock control driver */ 
429+ 	NRF_CLOCK -> EVENTS_XO24MSTARTED  =  0 ;
430+ 	NRF_CLOCK -> TASKS_XO24MSTOP  =  1 ;
431+ 
432+ 	return  0 ;
433+ }
434+ 
435+ static  inline  int  usbhs_disable_vreg (const  struct  device  * dev )
436+ {
437+ 	NRF_VREGUSB -> INTEN  =  0 ;
438+ 	NRF_VREGUSB -> TASKS_STOP  =  1 ;
439+ 
440+ 	return  0 ;
441+ }
442+ 
443+ static  inline  int  usbhs_init_caps (const  struct  device  * dev )
444+ {
445+ 	struct  udc_data  * data  =  dev -> data ;
446+ 
447+ 	data -> caps .can_detect_vbus  =  true;
448+ 	data -> caps .hs  =  true;
449+ 
450+ 	return  0 ;
451+ }
452+ 
453+ static  inline  int  usbhs_is_phy_clk_off (const  struct  device  * dev )
454+ {
455+ 	return  !k_event_test (& usbhs_events , USBHS_VBUS_READY );
456+ }
457+ 
458+ static  inline  int  usbhs_post_hibernation_entry (const  struct  device  * dev )
459+ {
460+ 	const  struct  udc_dwc2_config  * const  config  =  dev -> config ;
461+ 	struct  usb_dwc2_reg  * const  base  =  config -> base ;
462+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
463+ 
464+ 	sys_set_bits ((mem_addr_t )& base -> pcgcctl , USB_DWC2_PCGCCTL_GATEHCLK );
465+ 
466+ 	wrapper -> TASKS_STOP  =  1 ;
467+ 
468+ 	return  0 ;
469+ }
470+ 
471+ static  inline  int  usbhs_pre_hibernation_exit (const  struct  device  * dev )
472+ {
473+ 	const  struct  udc_dwc2_config  * const  config  =  dev -> config ;
474+ 	struct  usb_dwc2_reg  * const  base  =  config -> base ;
475+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
476+ 
477+ 	sys_clear_bits ((mem_addr_t )& base -> pcgcctl , USB_DWC2_PCGCCTL_GATEHCLK );
478+ 
479+ 	wrapper -> TASKS_START  =  1 ;
480+ 
481+ 	return  0 ;
482+ }
483+ 
484+ #define  QUIRK_NRF_USBHS_DEFINE (n )						\
485+ 	struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = {			\
486+ 		.init = usbhs_enable_vreg,					\
487+ 		.pre_enable = usbhs_enable_core,				\
488+ 		.disable = usbhs_disable_core,					\
489+ 		.shutdown = usbhs_disable_vreg,					\
490+ 		.caps = usbhs_init_caps,					\
491+ 		.is_phy_clk_off = usbhs_is_phy_clk_off,				\
492+ 		.post_hibernation_entry = usbhs_post_hibernation_entry,		\
493+ 		.pre_hibernation_exit = usbhs_pre_hibernation_exit,		\
494+ 	};
495+ 
496+ DT_INST_FOREACH_STATUS_OKAY (QUIRK_NRF_USBHS_DEFINE )
497+ 
498+ #undef  DT_DRV_COMPAT
499+ 
500+ #endif  /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs_nrf54l) */ 
501+ 
318502/* Add next vendor quirks definition above this line */ 
319503
320504#endif  /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */ 
0 commit comments