@@ -315,6 +315,191 @@ 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+ 
392+ 	/* Power up peripheral */ 
393+ 	wrapper -> ENABLE  =  USBHS_ENABLE_CORE_Msk ;
394+ 
395+ 	/* Set ID to Device and force D+ pull-up off for now */ 
396+ 	wrapper -> PHY .OVERRIDEVALUES  =  (1  << 31 );
397+ 	wrapper -> PHY .INPUTOVERRIDE  =  (1  << 31 ) | USBHS_PHY_INPUTOVERRIDE_VBUSVALID_Msk ;
398+ 
399+ 	/* Release PHY power-on reset */ 
400+ 	wrapper -> ENABLE  =  USBHS_ENABLE_PHY_Msk  | USBHS_ENABLE_CORE_Msk ;
401+ 
402+ 	/* Wait for PHY clock to start */ 
403+ 	k_busy_wait (45 );
404+ 
405+ 	/* Release DWC2 reset */ 
406+ 	wrapper -> TASKS_START  =  1UL ;
407+ 
408+ 	/* Wait for clock to start to avoid hang on too early register read */ 
409+ 	k_busy_wait (1 );
410+ 
411+ 	/* DWC2 opmode is now guaranteed to be Non-Driving, allow D+ pull-up to 
412+ 	 * become active once driver clears DCTL SftDiscon bit. 
413+ 	 */ 
414+ 	wrapper -> PHY .INPUTOVERRIDE  =  (1  << 31 );
415+ 
416+ 	return  0 ;
417+ }
418+ 
419+ static  inline  int  usbhs_disable_core (const  struct  device  * dev )
420+ {
421+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
422+ 
423+ 	/* Set ID to Device and forcefully disable D+ pull-up */ 
424+ 	wrapper -> PHY .OVERRIDEVALUES  =  (1  << 31 );
425+ 	wrapper -> PHY .INPUTOVERRIDE  =  (1  << 31 ) | USBHS_PHY_INPUTOVERRIDE_VBUSVALID_Msk ;
426+ 
427+ 	wrapper -> ENABLE  =  0UL ;
428+ 
429+ 	/* TODO: Release PCLK24M using clock control driver */ 
430+ 	NRF_CLOCK -> EVENTS_XO24MSTARTED  =  0 ;
431+ 	NRF_CLOCK -> TASKS_XO24MSTOP  =  1 ;
432+ 
433+ 	return  0 ;
434+ }
435+ 
436+ static  inline  int  usbhs_disable_vreg (const  struct  device  * dev )
437+ {
438+ 	NRF_VREGUSB -> INTEN  =  0 ;
439+ 	NRF_VREGUSB -> TASKS_STOP  =  1 ;
440+ 
441+ 	return  0 ;
442+ }
443+ 
444+ static  inline  int  usbhs_init_caps (const  struct  device  * dev )
445+ {
446+ 	struct  udc_data  * data  =  dev -> data ;
447+ 
448+ 	data -> caps .can_detect_vbus  =  true;
449+ 	data -> caps .hs  =  true;
450+ 
451+ 	return  0 ;
452+ }
453+ 
454+ static  inline  int  usbhs_is_phy_clk_off (const  struct  device  * dev )
455+ {
456+ 	return  !k_event_test (& usbhs_events , USBHS_VBUS_READY );
457+ }
458+ 
459+ static  inline  int  usbhs_post_hibernation_entry (const  struct  device  * dev )
460+ {
461+ 	const  struct  udc_dwc2_config  * const  config  =  dev -> config ;
462+ 	struct  usb_dwc2_reg  * const  base  =  config -> base ;
463+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
464+ 
465+ 	sys_set_bits ((mem_addr_t )& base -> pcgcctl , USB_DWC2_PCGCCTL_GATEHCLK );
466+ 
467+ 	wrapper -> TASKS_STOP  =  1 ;
468+ 
469+ 	return  0 ;
470+ }
471+ 
472+ static  inline  int  usbhs_pre_hibernation_exit (const  struct  device  * dev )
473+ {
474+ 	const  struct  udc_dwc2_config  * const  config  =  dev -> config ;
475+ 	struct  usb_dwc2_reg  * const  base  =  config -> base ;
476+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
477+ 
478+ 	sys_clear_bits ((mem_addr_t )& base -> pcgcctl , USB_DWC2_PCGCCTL_GATEHCLK );
479+ 
480+ 	wrapper -> TASKS_START  =  1 ;
481+ 
482+ 	return  0 ;
483+ }
484+ 
485+ #define  QUIRK_NRF_USBHS_DEFINE (n )						\
486+ 	struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = {			\
487+ 		.init = usbhs_enable_vreg,					\
488+ 		.pre_enable = usbhs_enable_core,				\
489+ 		.disable = usbhs_disable_core,					\
490+ 		.shutdown = usbhs_disable_vreg,					\
491+ 		.caps = usbhs_init_caps,					\
492+ 		.is_phy_clk_off = usbhs_is_phy_clk_off,				\
493+ 		.post_hibernation_entry = usbhs_post_hibernation_entry,		\
494+ 		.pre_hibernation_exit = usbhs_pre_hibernation_exit,		\
495+ 	};
496+ 
497+ DT_INST_FOREACH_STATUS_OKAY (QUIRK_NRF_USBHS_DEFINE )
498+ 
499+ #undef  DT_DRV_COMPAT
500+ 
501+ #endif  /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs_nrf54l) */ 
502+ 
318503/* Add next vendor quirks definition above this line */ 
319504
320505#endif  /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */ 
0 commit comments