@@ -315,6 +315,177 @@ 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+ 	/* FIXME: Request PCLK24M from clock control driver */ 
388+ 	NRF_CLOCK -> TASKS_XO24MSTART  =  1 ;
389+ 	while  (NRF_CLOCK -> EVENTS_XO24MSTARTED  ==  0 );
390+ 
391+ 	wrapper -> ENABLE  =  USBHS_ENABLE_PHY_Msk  | USBHS_ENABLE_CORE_Msk ;
392+ 
393+ 	/* USBHS will work in Device mode, set ID high */ 
394+ 	wrapper -> PHY .OVERRIDEVALUES  =  (1  << 31 );
395+ 	wrapper -> PHY .INPUTOVERRIDE  =  (1  << 31 );
396+ 
397+ 	/* Wait for PHY clock to start */ 
398+ 	k_busy_wait (45 );
399+ 
400+ 	/* Release DWC2 reset */ 
401+ 	wrapper -> TASKS_START  =  1UL ;
402+ 
403+ 	/* Wait for clock to start to avoid hang on too early register read */ 
404+ 	k_busy_wait (1 );
405+ 
406+ 	return  0 ;
407+ }
408+ 
409+ static  inline  int  usbhs_disable_core (const  struct  device  * dev )
410+ {
411+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
412+ 
413+ 	wrapper -> ENABLE  =  0UL ;
414+ 
415+ 	/* FIXME: Release PCLK24M from clock control driver */ 
416+ 	NRF_CLOCK -> EVENTS_XO24MSTARTED  =  0 ;
417+ 	NRF_CLOCK -> TASKS_XO24MSTOP  =  1 ;
418+ 
419+ 	return  0 ;
420+ }
421+ 
422+ static  inline  int  usbhs_disable_vreg (const  struct  device  * dev )
423+ {
424+ 	NRF_VREGUSB -> INTEN  =  0 ;
425+ 	NRF_VREGUSB -> TASKS_STOP  =  1 ;
426+ 
427+ 	return  0 ;
428+ }
429+ 
430+ static  inline  int  usbhs_init_caps (const  struct  device  * dev )
431+ {
432+ 	struct  udc_data  * data  =  dev -> data ;
433+ 
434+ 	data -> caps .can_detect_vbus  =  true;
435+ 	data -> caps .hs  =  true;
436+ 
437+ 	return  0 ;
438+ }
439+ 
440+ static  inline  int  usbhs_is_phy_clk_off (const  struct  device  * dev )
441+ {
442+ 	return  !k_event_test (& usbhs_events , USBHS_VBUS_READY );
443+ }
444+ 
445+ static  inline  int  usbhs_post_hibernation_entry (const  struct  device  * dev )
446+ {
447+ 	const  struct  udc_dwc2_config  * const  config  =  dev -> config ;
448+ 	struct  usb_dwc2_reg  * const  base  =  config -> base ;
449+ 	NRF_USBHS_Type  * wrapper  =  USBHS_DT_WRAPPER_REG_ADDR (0 );
450+ 
451+ 	sys_set_bits ((mem_addr_t )& base -> pcgcctl , USB_DWC2_PCGCCTL_GATEHCLK );
452+ 
453+ 	wrapper -> TASKS_STOP  =  1 ;
454+ 
455+ 	return  0 ;
456+ }
457+ 
458+ static  inline  int  usbhs_pre_hibernation_exit (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_clear_bits ((mem_addr_t )& base -> pcgcctl , USB_DWC2_PCGCCTL_GATEHCLK );
465+ 
466+ 	wrapper -> TASKS_START  =  1 ;
467+ 
468+ 	return  0 ;
469+ }
470+ 
471+ #define  QUIRK_NRF_USBHS_DEFINE (n )						\
472+ 	struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = {			\
473+ 		.init = usbhs_enable_vreg,					\
474+ 		.pre_enable = usbhs_enable_core,				\
475+ 		.disable = usbhs_disable_core,					\
476+ 		.shutdown = usbhs_disable_vreg,					\
477+ 		.caps = usbhs_init_caps,					\
478+ 		.is_phy_clk_off = usbhs_is_phy_clk_off,				\
479+ 		.post_hibernation_entry = usbhs_post_hibernation_entry,		\
480+ 		.pre_hibernation_exit = usbhs_pre_hibernation_exit,		\
481+ 	};
482+ 
483+ DT_INST_FOREACH_STATUS_OKAY (QUIRK_NRF_USBHS_DEFINE )
484+ 
485+ #undef  DT_DRV_COMPAT
486+ 
487+ #endif  /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs_nrf54l) */ 
488+ 
318489/* Add next vendor quirks definition above this line */ 
319490
320491#endif  /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */ 
0 commit comments