summaryrefslogtreecommitdiff
path: root/nuttx/arch
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2014-11-04 10:14:04 -0600
committerGregory Nutt <gnutt@nuttx.org>2014-11-04 10:14:04 -0600
commitb0669e950f3b76cb418f4b6645916ecedb606a13 (patch)
treee39a6c6937da0f2fded4f3283fd56cff06c0b8f9 /nuttx/arch
parent010c1b49310bec659c9a922e608776f0a53ff4b3 (diff)
downloadnuttx-b0669e950f3b76cb418f4b6645916ecedb606a13.tar.gz
nuttx-b0669e950f3b76cb418f4b6645916ecedb606a13.tar.bz2
nuttx-b0669e950f3b76cb418f4b6645916ecedb606a13.zip
EFM32: Port USB device and host drivers from STM32. Still does not compile
Diffstat (limited to 'nuttx/arch')
-rw-r--r--nuttx/arch/arm/src/efm32/Kconfig43
-rw-r--r--nuttx/arch/arm/src/efm32/Make.defs2
-rw-r--r--nuttx/arch/arm/src/efm32/chip/efm32_usb.h1002
-rw-r--r--nuttx/arch/arm/src/efm32/efm32_usb.h126
-rw-r--r--nuttx/arch/arm/src/efm32/efm32_usbdev.c5701
-rw-r--r--nuttx/arch/arm/src/efm32/efm32_usbhost.c4452
6 files changed, 10820 insertions, 506 deletions
diff --git a/nuttx/arch/arm/src/efm32/Kconfig b/nuttx/arch/arm/src/efm32/Kconfig
index 2d4d22316..448cb9f20 100644
--- a/nuttx/arch/arm/src/efm32/Kconfig
+++ b/nuttx/arch/arm/src/efm32/Kconfig
@@ -73,7 +73,7 @@ config EFM32_EFM32GG
select EFM32_HAVE_UART0
select EFM32_HAVE_UART1
select EFM32_HAVE_LEUART1
- select EFM32_HAVE_USBFSOTG
+ select EFM32_HAVE_OTGFS
menu "EFM32 Peripheral Support"
@@ -96,7 +96,7 @@ config EFM32_HAVE_LEUART1
bool
default n
-config EFM32_HAVE_USBFSOTG
+config EFM32_HAVE_OTGFS
bool
default n
@@ -169,10 +169,10 @@ config EFM32_LEUART1
select ARCH_HAVE_OTHER_UART
select EFM32_LEUART
-config EFM32_USBFSOTG
+config EFM32_OTGFS
bool "USB Full-Speed OTG"
default n
- depends on EFM32_HAVE_USBFSOTG && EXPERIMENTAL
+ depends on EFM32_HAVE_OTGFS && EXPERIMENTAL
endmenu # EFM32 Peripheral Support
@@ -392,4 +392,39 @@ endif # EFM32_SPI_DMA
endmenu # SPI Configuration
endif # EFM32_USART_ISSPI
+menu "USB FS Host Configuration"
+ depends on USBHOST && EFM32_OTGFS
+
+config EFM32_OTGFS_RXFIFO_SIZE
+ int "Rx Packet Size"
+ default 128
+ ---help---
+ Size of the RX FIFO in 32-bit words. Default 128 (512 bytes)
+
+config EFM32_OTGFS_NPTXFIFO_SIZE
+ int "Non-periodic Tx FIFO Size"
+ default 96
+ ---help---
+ Size of the non-periodic Tx FIFO in 32-bit words. Default 96 (384 bytes)
+
+config EFM32_OTGFS_PTXFIFO_SIZE
+ int "Periodic Tx FIFO size"
+ default 128
+ ---help---
+ Size of the periodic Tx FIFO in 32-bit words. Default 96 (384 bytes)
+
+config EFM32_OTGFS_DESCSIZE
+ int "Descriptor Size"
+ default 128
+ ---help---
+ Maximum size to allocate for descriptor memory descriptor. Default: 128
+
+config EFM32_OTGFS_SOFINTR
+ bool "Enable SOF interrupts"
+ default n
+ ---help---
+ Enable SOF interrupts. Why would you ever want to do that?
+
+endmenu
+
endif # ARCH_CHIP_EFM32
diff --git a/nuttx/arch/arm/src/efm32/Make.defs b/nuttx/arch/arm/src/efm32/Make.defs
index 1aec13974..3c19b698f 100644
--- a/nuttx/arch/arm/src/efm32/Make.defs
+++ b/nuttx/arch/arm/src/efm32/Make.defs
@@ -127,7 +127,7 @@ ifeq ($(CONFIG_EFM32_DMA),y)
CHIP_CSRCS += efm32_dma.c
endif
-ifeq ($(CONFIG_EFM32_USBFSOTG),y)
+ifeq ($(CONFIG_EFM32_OTGFS),y)
ifeq ($(CONFIG_USBDEV),y)
CHIP_CSRCS += efm32_usbdev.c
endif
diff --git a/nuttx/arch/arm/src/efm32/chip/efm32_usb.h b/nuttx/arch/arm/src/efm32/chip/efm32_usb.h
index f6df7516e..8bac0a15c 100644
--- a/nuttx/arch/arm/src/efm32/chip/efm32_usb.h
+++ b/nuttx/arch/arm/src/efm32/chip/efm32_usb.h
@@ -158,53 +158,53 @@
#define EFM32_USB_DIEP5_OFFSET 0x3c9a0 /* Device IN Endpoint 5 */
#define EFM32_USB_DIEP6_OFFSET 0x3c9c0 /* Device IN Endpoint 6 */
-#define EFM32_USB_DIEPn_CTL_OFFSET 0x00000 /* Device IN Endpoint n Control Register */
-#define EFM32_USB_DIEPn_INT_OFFSET 0x00008 /* Device IN Endpoint n Interrupt Register */
-#define EFM32_USB_DIEPn_TSIZ_OFFSET 0x00010 /* Device IN Endpoint n Transfer Size Register */
-#define EFM32_USB_DIEPn_DMAADDR_OFFSET 0x00014 /* Device IN Endpoint n DMA Address Register */
-#define EFM32_USB_DIEPn_TXFSTS_OFFSET 0x00018 /* Device IN Endpoint n Transmit FIFO Status Register */
-
-#define EFM32_USB_DIEP0_CTL_OFFSET 0x3c900 /* Device IN Endpoint 0 Control Register */
-#define EFM32_USB_DIEP0_INT_OFFSET 0x3c908 /* Device IN Endpoint 0 Interrupt Register */
-#define EFM32_USB_DIEP0_TSIZ_OFFSET 0x3c910 /* Device IN Endpoint 0 Transfer Size Register */
-#define EFM32_USB_DIEP0_DMAADDR_OFFSET 0x3c914 /* Device IN Endpoint 0 DMA Address Register */
-#define EFM32_USB_DIEP0_TXFSTS_OFFSET 0x3c918 /* Device IN Endpoint 0 Transmit FIFO Status Register */
-
-#define EFM32_USB_DIEP1_CTL_OFFSET 0x3c920 /* Device IN Endpoint 1 Control Register */
-#define EFM32_USB_DIEP1_INT_OFFSET 0x3c928 /* Device IN Endpoint 1 Interrupt Register */
-#define EFM32_USB_DIEP1_TSIZ_OFFSET 0x3c930 /* Device IN Endpoint 1 Transfer Size Register */
-#define EFM32_USB_DIEP1_DMAADDR_OFFSET 0x3c934 /* Device IN Endpoint 1 DMA Address Register */
-#define EFM32_USB_DIEP1_TXFSTS_OFFSET 0x3c938 /* Device IN Endpoint 1 Transmit FIFO Status Register */
-
-#define EFM32_USB_DIEP2_CTL_OFFSET 0x3c940 /* Device IN Endpoint 2 Control Register */
-#define EFM32_USB_DIEP2_INT_OFFSET 0x3c948 /* Device IN Endpoint 2 Interrupt Register */
-#define EFM32_USB_DIEP2_TSIZ_OFFSET 0x3c950 /* Device IN Endpoint 2 Transfer Size Register */
-#define EFM32_USB_DIEP2_DMAADDR_OFFSET 0x3c954 /* Device IN Endpoint 2 DMA Address Register */
-#define EFM32_USB_DIEP2_TXFSTS_OFFSET 0x3c958 /* Device IN Endpoint 2 Transmit FIFO Status Register */
-
-#define EFM32_USB_DIEP3_CTL_OFFSET 0x3c960 /* Device IN Endpoint 3 Control Register */
-#define EFM32_USB_DIEP3_INT_OFFSET 0x3c968 /* Device IN Endpoint 3 Interrupt Register */
-#define EFM32_USB_DIEP3_TSIZ_OFFSET 0x3c970 /* Device IN Endpoint 3 Transfer Size Register */
-#define EFM32_USB_DIEP3_DMAADDR_OFFSET 0x3c974 /* Device IN Endpoint 3 DMA Address Register */
-#define EFM32_USB_DIEP3_TXFSTS_OFFSET 0x3c978 /* Device IN Endpoint 3 Transmit FIFO Status Register */
-
-#define EFM32_USB_DIEP4_CTL_OFFSET 0x3c980 /* Device IN Endpoint 4 Control Register */
-#define EFM32_USB_DIEP4_INT_OFFSET 0x3c988 /* Device IN Endpoint 4 Interrupt Register */
-#define EFM32_USB_DIEP4_TSIZ_OFFSET 0x3c990 /* Device IN Endpoint 4 Transfer Size Register */
-#define EFM32_USB_DIEP4_DMAADDR_OFFSET 0x3c994 /* Device IN Endpoint 4 DMA Address Register */
-#define EFM32_USB_DIEP4_TXFSTS_OFFSET 0x3c998 /* Device IN Endpoint 4 Transmit FIFO Status Register */
-
-#define EFM32_USB_DIEP5_CTL_OFFSET 0x3c9a0 /* Device IN Endpoint 5 Control Register */
-#define EFM32_USB_DIEP5_INT_OFFSET 0x3c9a8 /* Device IN Endpoint 5 Interrupt Register */
-#define EFM32_USB_DIEP5_TSIZ_OFFSET 0x3c9b0 /* Device IN Endpoint 5 Transfer Size Register */
-#define EFM32_USB_DIEP5_DMAADDR_OFFSET 0x3c9b4 /* Device IN Endpoint 5 DMA Address Register */
-#define EFM32_USB_DIEP5_TXFSTS_OFFSET 0x3c9b8 /* Device IN Endpoint 5 Transmit FIFO Status Register */
-
-#define EFM32_USB_DIEP6_CTL_OFFSET 0x3c9c0 /* Device IN Endpoint 6 Control Register */
-#define EFM32_USB_DIEP6_INT_OFFSET 0x3c9c8 /* Device IN Endpoint 6 Interrupt Register */
-#define EFM32_USB_DIEP6_TSIZ_OFFSET 0x3c9d0 /* Device IN Endpoint 6 Transfer Size Register */
-#define EFM32_USB_DIEP6_DMAADDR_OFFSET 0x3c9d4 /* Device IN Endpoint 6 DMA Address Register */
-#define EFM32_USB_DIEP6_TXFSTS_OFFSET 0x3c9d8 /* Device IN Endpoint 6 Transmit FIFO Status Register */
+#define EFM32_USB_DIEPnCTL_OFFSET 0x00000 /* Device IN Endpoint n Control Register */
+#define EFM32_USB_DIEPnINT_OFFSET 0x00008 /* Device IN Endpoint n Interrupt Register */
+#define EFM32_USB_DIEPnTSIZ_OFFSET 0x00010 /* Device IN Endpoint n Transfer Size Register */
+#define EFM32_USB_DIEPnDMAADDR_OFFSET 0x00014 /* Device IN Endpoint n DMA Address Register */
+#define EFM32_USB_DIEPnTXFSTS_OFFSET 0x00018 /* Device IN Endpoint n Transmit FIFO Status Register */
+
+#define EFM32_USB_DIEP0CTL_OFFSET 0x3c900 /* Device IN Endpoint 0 Control Register */
+#define EFM32_USB_DIEP0INT_OFFSET 0x3c908 /* Device IN Endpoint 0 Interrupt Register */
+#define EFM32_USB_DIEP0TSIZ_OFFSET 0x3c910 /* Device IN Endpoint 0 Transfer Size Register */
+#define EFM32_USB_DIEP0DMAADDR_OFFSET 0x3c914 /* Device IN Endpoint 0 DMA Address Register */
+#define EFM32_USB_DIEP0TXFSTS_OFFSET 0x3c918 /* Device IN Endpoint 0 Transmit FIFO Status Register */
+
+#define EFM32_USB_DIEP1CTL_OFFSET 0x3c920 /* Device IN Endpoint 1 Control Register */
+#define EFM32_USB_DIEP1INT_OFFSET 0x3c928 /* Device IN Endpoint 1 Interrupt Register */
+#define EFM32_USB_DIEP1TSIZ_OFFSET 0x3c930 /* Device IN Endpoint 1 Transfer Size Register */
+#define EFM32_USB_DIEP1DMAADDR_OFFSET 0x3c934 /* Device IN Endpoint 1 DMA Address Register */
+#define EFM32_USB_DIEP1TXFSTS_OFFSET 0x3c938 /* Device IN Endpoint 1 Transmit FIFO Status Register */
+
+#define EFM32_USB_DIEP2CTL_OFFSET 0x3c940 /* Device IN Endpoint 2 Control Register */
+#define EFM32_USB_DIEP2INT_OFFSET 0x3c948 /* Device IN Endpoint 2 Interrupt Register */
+#define EFM32_USB_DIEP2TSIZ_OFFSET 0x3c950 /* Device IN Endpoint 2 Transfer Size Register */
+#define EFM32_USB_DIEP2DMAADDR_OFFSET 0x3c954 /* Device IN Endpoint 2 DMA Address Register */
+#define EFM32_USB_DIEP2TXFSTS_OFFSET 0x3c958 /* Device IN Endpoint 2 Transmit FIFO Status Register */
+
+#define EFM32_USB_DIEP3CTL_OFFSET 0x3c960 /* Device IN Endpoint 3 Control Register */
+#define EFM32_USB_DIEP3INT_OFFSET 0x3c968 /* Device IN Endpoint 3 Interrupt Register */
+#define EFM32_USB_DIEP3TSIZ_OFFSET 0x3c970 /* Device IN Endpoint 3 Transfer Size Register */
+#define EFM32_USB_DIEP3DMAADDR_OFFSET 0x3c974 /* Device IN Endpoint 3 DMA Address Register */
+#define EFM32_USB_DIEP3TXFSTS_OFFSET 0x3c978 /* Device IN Endpoint 3 Transmit FIFO Status Register */
+
+#define EFM32_USB_DIEP4CTL_OFFSET 0x3c980 /* Device IN Endpoint 4 Control Register */
+#define EFM32_USB_DIEP4INT_OFFSET 0x3c988 /* Device IN Endpoint 4 Interrupt Register */
+#define EFM32_USB_DIEP4TSIZ_OFFSET 0x3c990 /* Device IN Endpoint 4 Transfer Size Register */
+#define EFM32_USB_DIEP4DMAADDR_OFFSET 0x3c994 /* Device IN Endpoint 4 DMA Address Register */
+#define EFM32_USB_DIEP4TXFSTS_OFFSET 0x3c998 /* Device IN Endpoint 4 Transmit FIFO Status Register */
+
+#define EFM32_USB_DIEP5CTL_OFFSET 0x3c9a0 /* Device IN Endpoint 5 Control Register */
+#define EFM32_USB_DIEP5INT_OFFSET 0x3c9a8 /* Device IN Endpoint 5 Interrupt Register */
+#define EFM32_USB_DIEP5TSIZ_OFFSET 0x3c9b0 /* Device IN Endpoint 5 Transfer Size Register */
+#define EFM32_USB_DIEP5DMAADDR_OFFSET 0x3c9b4 /* Device IN Endpoint 5 DMA Address Register */
+#define EFM32_USB_DIEP5TXFSTS_OFFSET 0x3c9b8 /* Device IN Endpoint 5 Transmit FIFO Status Register */
+
+#define EFM32_USB_DIEP6CTL_OFFSET 0x3c9c0 /* Device IN Endpoint 6 Control Register */
+#define EFM32_USB_DIEP6INT_OFFSET 0x3c9c8 /* Device IN Endpoint 6 Interrupt Register */
+#define EFM32_USB_DIEP6TSIZ_OFFSET 0x3c9d0 /* Device IN Endpoint 6 Transfer Size Register */
+#define EFM32_USB_DIEP6DMAADDR_OFFSET 0x3c9d4 /* Device IN Endpoint 6 DMA Address Register */
+#define EFM32_USB_DIEP6TXFSTS_OFFSET 0x3c9d8 /* Device IN Endpoint 6 Transmit FIFO Status Register */
#define EFM32_USB_DOEP_OFFSET(n) (0x3c900 + ((n) << 5))
#define EFM32_USB_DOEP0_OFFSET 0x3c900 /* Device OUT Endpoint 0 */
@@ -215,45 +215,45 @@
#define EFM32_USB_DOEP5_OFFSET 0x3c9a0 /* Device OUT Endpoint 5 */
#define EFM32_USB_DOEP6_OFFSET 0x3c9c0 /* Device OUT Endpoint 6 */
-#define EFM32_USB_DOEPn_CTL_OFFSET 0x00000 /* Device OUT Endpoint n Control Register */
-#define EFM32_USB_DOEPn_INT_OFFSET 0x00008 /* Device OUT Endpoint n Interrupt Register */
-#define EFM32_USB_DOEPn_TSIZ_OFFSET 0x00010 /* Device OUT Endpoint n Transfer Size Register */
-#define EFM32_USB_DOEPn_DMAADDR_OFFSET 0x00014 /* Device OUT Endpoint n DMA Address Register */
+#define EFM32_USB_DOEPnCTL_OFFSET 0x00000 /* Device OUT Endpoint n Control Register */
+#define EFM32_USB_DOEPnINT_OFFSET 0x00008 /* Device OUT Endpoint n Interrupt Register */
+#define EFM32_USB_DOEPnTSIZ_OFFSET 0x00010 /* Device OUT Endpoint n Transfer Size Register */
+#define EFM32_USB_DOEPnDMAADDR_OFFSET 0x00014 /* Device OUT Endpoint n DMA Address Register */
-#define EFM32_USB_DOEP0_CTL_OFFSET 0x3cb00 /* Device OUT Endpoint 0 Control Register */
-#define EFM32_USB_DOEP0_INT_OFFSET 0x3cb08 /* Device OUT Endpoint 0 Interrupt Register */
-#define EFM32_USB_DOEP0_TSIZ_OFFSET 0x3cb10 /* Device OUT Endpoint 0 Transfer Size Register */
-#define EFM32_USB_DOEP0_DMAADDR_OFFSET 0x3cb14 /* Device OUT Endpoint 0 DMA Address Register */
+#define EFM32_USB_DOEP0CTL_OFFSET 0x3cb00 /* Device OUT Endpoint 0 Control Register */
+#define EFM32_USB_DOEP0INT_OFFSET 0x3cb08 /* Device OUT Endpoint 0 Interrupt Register */
+#define EFM32_USB_DOEP0TSIZ_OFFSET 0x3cb10 /* Device OUT Endpoint 0 Transfer Size Register */
+#define EFM32_USB_DOEP0DMAADDR_OFFSET 0x3cb14 /* Device OUT Endpoint 0 DMA Address Register */
-#define EFM32_USB_DOEP1_CTL_OFFSET 0x3cb20 /* Device OUT Endpoint x Control Register */
-#define EFM32_USB_DOEP1_INT_OFFSET 0x3cb28 /* Device OUT Endpoint x Interrupt Register */
-#define EFM32_USB_DOEP1_TSIZ_OFFSET 0x3cb30 /* Device OUT Endpoint x Transfer Size Register */
-#define EFM32_USB_DOEP1_DMAADDR_OFFSET 0x3cb34 /* Device OUT Endpoint x DMA Address Register */
+#define EFM32_USB_DOEP1CTL_OFFSET 0x3cb20 /* Device OUT Endpoint x Control Register */
+#define EFM32_USB_DOEP1INT_OFFSET 0x3cb28 /* Device OUT Endpoint x Interrupt Register */
+#define EFM32_USB_DOEP1TSIZ_OFFSET 0x3cb30 /* Device OUT Endpoint x Transfer Size Register */
+#define EFM32_USB_DOEP1DMAADDR_OFFSET 0x3cb34 /* Device OUT Endpoint x DMA Address Register */
#define EFM32_USB_DOEP2_CTL_OFFSET 0x3cb40 /* Device OUT Endpoint x Control Register */
#define EFM32_USB_DOEP2_INT_OFFSET 0x3cb48 /* Device OUT Endpoint x Interrupt Register */
#define EFM32_USB_DOEP2_TSIZ_OFFSET 0x3cb50 /* Device OUT Endpoint x Transfer Size Register */
#define EFM32_USB_DOEP2_DMAADDR_OFFSET 0x3cb54 /* Device OUT Endpoint x DMA Address Register */
-#define EFM32_USB_DOEP3_CTL_OFFSET 0x3cb60 /* Device OUT Endpoint x Control Register */
-#define EFM32_USB_DOEP3_INT_OFFSET 0x3cb68 /* Device OUT Endpoint x Interrupt Register */
-#define EFM32_USB_DOEP3_TSIZ_OFFSET 0x3cb70 /* Device OUT Endpoint x Transfer Size Register */
-#define EFM32_USB_DOEP3_DMAADDR_OFFSET 0x3cb74 /* Device OUT Endpoint x DMA Address Register */
+#define EFM32_USB_DOEP3CTL_OFFSET 0x3cb60 /* Device OUT Endpoint x Control Register */
+#define EFM32_USB_DOEP3INT_OFFSET 0x3cb68 /* Device OUT Endpoint x Interrupt Register */
+#define EFM32_USB_DOEP3TSIZ_OFFSET 0x3cb70 /* Device OUT Endpoint x Transfer Size Register */
+#define EFM32_USB_DOEP3DMAADDR_OFFSET 0x3cb74 /* Device OUT Endpoint x DMA Address Register */
-#define EFM32_USB_DOEP4_CTL_OFFSET 0x3cb80 /* Device OUT Endpoint x Control Register */
-#define EFM32_USB_DOEP4_INT_OFFSET 0x3cb88 /* Device OUT Endpoint x Interrupt Register */
-#define EFM32_USB_DOEP4_TSIZ_OFFSET 0x3cb90 /* Device OUT Endpoint x Transfer Size Register */
-#define EFM32_USB_DOEP4_DMAADDR_OFFSET 0x3cb94 /* Device OUT Endpoint x DMA Address Register */
+#define EFM32_USB_DOEP4CTL_OFFSET 0x3cb80 /* Device OUT Endpoint x Control Register */
+#define EFM32_USB_DOEP4INT_OFFSET 0x3cb88 /* Device OUT Endpoint x Interrupt Register */
+#define EFM32_USB_DOEP4TSIZ_OFFSET 0x3cb90 /* Device OUT Endpoint x Transfer Size Register */
+#define EFM32_USB_DOEP4DMAADDR_OFFSET 0x3cb94 /* Device OUT Endpoint x DMA Address Register */
-#define EFM32_USB_DOEP5_CTL_OFFSET 0x3cba0 /* Device OUT Endpoint x Control Register */
-#define EFM32_USB_DOEP5_INT_OFFSET 0x3cba8 /* Device OUT Endpoint x Interrupt Register */
-#define EFM32_USB_DOEP5_TSIZ_OFFSET 0x3cbb0 /* Device OUT Endpoint x Transfer Size Register */
-#define EFM32_USB_DOEP5_DMAADDR_OFFSET 0x3cbb4 /* Device OUT Endpoint x DMA Address Register */
+#define EFM32_USB_DOEP5CTL_OFFSET 0x3cba0 /* Device OUT Endpoint x Control Register */
+#define EFM32_USB_DOEP5INT_OFFSET 0x3cba8 /* Device OUT Endpoint x Interrupt Register */
+#define EFM32_USB_DOEP5TSIZ_OFFSET 0x3cbb0 /* Device OUT Endpoint x Transfer Size Register */
+#define EFM32_USB_DOEP5DMAADDR_OFFSET 0x3cbb4 /* Device OUT Endpoint x DMA Address Register */
-#define EFM32_USB_DOEP6_CTL_OFFSET 0x3cbc0 /* Device OUT Endpoint x Control Register */
-#define EFM32_USB_DOEP6_INT_OFFSET 0x3cbc8 /* Device OUT Endpoint x Interrupt Register */
-#define EFM32_USB_DOEP6_TSIZ_OFFSET 0x3cbd0 /* Device OUT Endpoint x Transfer Size Register */
-#define EFM32_USB_DOEP6_DMAADDR_OFFSET 0x3cbd4 /* Device OUT Endpoint x DMA Address Register */
+#define EFM32_USB_DOEP6CTL_OFFSET 0x3cbc0 /* Device OUT Endpoint x Control Register */
+#define EFM32_USB_DOEP6INT_OFFSET 0x3cbc8 /* Device OUT Endpoint x Interrupt Register */
+#define EFM32_USB_DOEP6TSIZ_OFFSET 0x3cbd0 /* Device OUT Endpoint x Transfer Size Register */
+#define EFM32_USB_DOEP6DMAADDR_OFFSET 0x3cbd4 /* Device OUT Endpoint x DMA Address Register */
#define EFM32_USB_PCGCCTL_OFFSET 0x3ce00 /* Power and Clock Gating Control Register */
@@ -361,53 +361,53 @@
#define EFM32_USB_DIEP5_BASE (EFM32_USB_BASE+EFM32_USB_DIEP5_OFFSET)
#define EFM32_USB_DIEP6_BASE (EFM32_USB_BASE+EFM32_USB_DIEP6_OFFSET)
-#define EFM32_USB_DIEP_CTL(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPn_CTL_OFFSET)
-#define EFM32_USB_DIEP_INT(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPn_INT_OFFSET)
-#define EFM32_USB_DIEP_TSIZ(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPn_TSIZ_OFFSET)
-#define EFM32_USB_DIEP_DMAADDR(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPn_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP_TXFSTS(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPn_TXFSTS_OFFSET)
-
-#define EFM32_USB_DIEP0_CTL (EFM32_USB_BASE+EFM32_USB_DIEP0_CTL_OFFSET)
-#define EFM32_USB_DIEP0_INT (EFM32_USB_BASE+EFM32_USB_DIEP0_INT_OFFSET)
-#define EFM32_USB_DIEP0_TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP0_TSIZ_OFFSET)
-#define EFM32_USB_DIEP0_DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP0_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP0_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP0_TXFSTS_OFFSET)
-
-#define EFM32_USB_DIEP1_CTL (EFM32_USB_BASE+EFM32_USB_DIEP1_CTL_OFFSET)
-#define EFM32_USB_DIEP1_INT (EFM32_USB_BASE+EFM32_USB_DIEP1_INT_OFFSET)
-#define EFM32_USB_DIEP1_TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP1_TSIZ_OFFSET)
-#define EFM32_USB_DIEP1_DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP1_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP1_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP1_TXFSTS_OFFSET)
-
-#define EFM32_USB_DIEP2_CTL (EFM32_USB_BASE+EFM32_USB_DIEP2_CTL_OFFSET)
-#define EFM32_USB_DIEP2_INT (EFM32_USB_BASE+EFM32_USB_DIEP2_INT_OFFSET)
-#define EFM32_USB_DIEP2_TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP2_TSIZ_OFFSET)
-#define EFM32_USB_DIEP2_DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP2_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP2_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP2_TXFSTS_OFFSET)
-
-#define EFM32_USB_DIEP3_CTL (EFM32_USB_BASE+EFM32_USB_DIEP3_CTL_OFFSET)
-#define EFM32_USB_DIEP3_INT (EFM32_USB_BASE+EFM32_USB_DIEP3_INT_OFFSET)
-#define EFM32_USB_DIEP3_TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP3_TSIZ_OFFSET)
-#define EFM32_USB_DIEP3_DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP3_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP3_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP3_TXFSTS_OFFSET)
-
-#define EFM32_USB_DIEP4_CTL (EFM32_USB_BASE+EFM32_USB_DIEP4_CTL_OFFSET)
-#define EFM32_USB_DIEP4_INT (EFM32_USB_BASE+EFM32_USB_DIEP4_INT_OFFSET)
-#define EFM32_USB_DIEP4_TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP4_TSIZ_OFFSET)
-#define EFM32_USB_DIEP4_DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP4_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP4_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP4_TXFSTS_OFFSET)
-
-#define EFM32_USB_DIEP5_CTL (EFM32_USB_BASE+EFM32_USB_DIEP5_CTL_OFFSET)
-#define EFM32_USB_DIEP5_INT (EFM32_USB_BASE+EFM32_USB_DIEP5_INT_OFFSET)
-#define EFM32_USB_DIEP5_TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP5_TSIZ_OFFSET)
-#define EFM32_USB_DIEP5_DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP5_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP5_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP5_TXFSTS_OFFSET)
-
-#define EFM32_USB_DIEP6_CTL (EFM32_USB_BASE+EFM32_USB_DIEP6_CTL_OFFSET)
-#define EFM32_USB_DIEP6_INT (EFM32_USB_BASE+EFM32_USB_DIEP6_INT_OFFSET)
-#define EFM32_USB_DIEP6_TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP6_TSIZ_OFFSET)
-#define EFM32_USB_DIEP6_DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP6_DMAADDR_OFFSET)
-#define EFM32_USB_DIEP6_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP6_TXFSTS_OFFSET)
+#define EFM32_USB_DIEPCTL(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPnCTL_OFFSET)
+#define EFM32_USB_DIEPINT(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPnINT_OFFSET)
+#define EFM32_USB_DIEPTSIZ(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPnTSIZ_OFFSET)
+#define EFM32_USB_DIEPDMAADDR(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPnDMAADDR_OFFSET)
+#define EFM32_USB_DIEPTXFSTS(n) (EFM32_USB_DIEP_BASE(n)+EFM32_USB_DIEPnTXFSTS_OFFSET)
+
+#define EFM32_USB_DIEP0CTL (EFM32_USB_BASE+EFM32_USB_DIEP0CTL_OFFSET)
+#define EFM32_USB_DIEP0INT (EFM32_USB_BASE+EFM32_USB_DIEP0INT_OFFSET)
+#define EFM32_USB_DIEP0TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP0TSIZ_OFFSET)
+#define EFM32_USB_DIEP0DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP0DMAADDR_OFFSET)
+#define EFM32_USB_DIEP0TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP0TXFSTS_OFFSET)
+
+#define EFM32_USB_DIEP1CTL (EFM32_USB_BASE+EFM32_USB_DIEP1CTL_OFFSET)
+#define EFM32_USB_DIEP1INT (EFM32_USB_BASE+EFM32_USB_DIEP1INT_OFFSET)
+#define EFM32_USB_DIEP1TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP1TSIZ_OFFSET)
+#define EFM32_USB_DIEP1DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP1DMAADDR_OFFSET)
+#define EFM32_USB_DIEP1TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP1TXFSTS_OFFSET)
+
+#define EFM32_USB_DIEP2CTL (EFM32_USB_BASE+EFM32_USB_DIEP2CTL_OFFSET)
+#define EFM32_USB_DIEP2INT (EFM32_USB_BASE+EFM32_USB_DIEP2INT_OFFSET)
+#define EFM32_USB_DIEP2TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP2TSIZ_OFFSET)
+#define EFM32_USB_DIEP2DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP2DMAADDR_OFFSET)
+#define EFM32_USB_DIEP2TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP2TXFSTS_OFFSET)
+
+#define EFM32_USB_DIEP3CTL (EFM32_USB_BASE+EFM32_USB_DIEP3CTL_OFFSET)
+#define EFM32_USB_DIEP3INT (EFM32_USB_BASE+EFM32_USB_DIEP3INT_OFFSET)
+#define EFM32_USB_DIEP3TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP3TSIZ_OFFSET)
+#define EFM32_USB_DIEP3DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP3DMAADDR_OFFSET)
+#define EFM32_USB_DIEP3_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP3TXFSTS_OFFSET)
+
+#define EFM32_USB_DIEP4CTL (EFM32_USB_BASE+EFM32_USB_DIEP4CTL_OFFSET)
+#define EFM32_USB_DIEP4INT (EFM32_USB_BASE+EFM32_USB_DIEP4INT_OFFSET)
+#define EFM32_USB_DIEP4TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP4TSIZ_OFFSET)
+#define EFM32_USB_DIEP4DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP4DMAADDR_OFFSET)
+#define EFM32_USB_DIEP4TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP4TXFSTS_OFFSET)
+
+#define EFM32_USB_DIEP5CTL (EFM32_USB_BASE+EFM32_USB_DIEP5CTL_OFFSET)
+#define EFM32_USB_DIEP5INT (EFM32_USB_BASE+EFM32_USB_DIEP5INT_OFFSET)
+#define EFM32_USB_DIEP5TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP5TSIZ_OFFSET)
+#define EFM32_USB_DIEP5DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP5DMAADDR_OFFSET)
+#define EFM32_USB_DIEP5_TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP5TXFSTS_OFFSET)
+
+#define EFM32_USB_DIEP6CTL (EFM32_USB_BASE+EFM32_USB_DIEP6_CTL_OFFSET)
+#define EFM32_USB_DIEP6INT (EFM32_USB_BASE+EFM32_USB_DIEP6_INT_OFFSET)
+#define EFM32_USB_DIEP6TSIZ (EFM32_USB_BASE+EFM32_USB_DIEP6_TSIZ_OFFSET)
+#define EFM32_USB_DIEP6DMAADDR (EFM32_USB_BASE+EFM32_USB_DIEP6_DMAADDR_OFFSET)
+#define EFM32_USB_DIEP6TXFSTS (EFM32_USB_BASE+EFM32_USB_DIEP6_TXFSTS_OFFSET)
#define EFM32_USB_DOEP_BASE(n) (EFM32_USB_BASE+EFM32_USB_DOEP_OFFSET(n))
#define EFM32_USB_DOEP0_BASE (EFM32_USB_BASE+EFM32_USB_DOEP0_OFFSET)
@@ -418,45 +418,45 @@
#define EFM32_USB_DOEP5_BASE (EFM32_USB_BASE+EFM32_USB_DOEP5_OFFSET)
#define EFM32_USB_DOEP6_BASE (EFM32_USB_BASE+EFM32_USB_DOEP6_OFFSET)
-#define EFM32_USB_DOEP_CTL(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPn_CTL_OFFSET)
-#define EFM32_USB_DOEP_INT(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPn_INT_OFFSET)
-#define EFM32_USB_DOEP_TSIZ(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPn_TSIZ_OFFSET)
-#define EFM32_USB_DOEP_DMAADDR(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPn_DMAADDR_OFFSET)
-
-#define EFM32_USB_DOEP0_CTL (EFM32_USB_BASE+EFM32_USB_DOEP0_CTL_OFFSET)
-#define EFM32_USB_DOEP0_INT (EFM32_USB_BASE+EFM32_USB_DOEP0_INT_OFFSET)
-#define EFM32_USB_DOEP0_TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP0_TSIZ_OFFSET)
-#define EFM32_USB_DOEP0_DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP0_DMAADDR_OFFSET)
-
-#define EFM32_USB_DOEP1_CTL (EFM32_USB_BASE+EFM32_USB_DOEP1_CTL_OFFSET)
-#define EFM32_USB_DOEP1_INT (EFM32_USB_BASE+EFM32_USB_DOEP1_INT_OFFSET)
-#define EFM32_USB_DOEP1_TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP1_TSIZ_OFFSET)
-#define EFM32_USB_DOEP1_DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP1_DMAADDR_OFFSET)
-
-#define EFM32_USB_DOEP2_CTL (EFM32_USB_BASE+EFM32_USB_DOEP2_CTL_OFFSET)
-#define EFM32_USB_DOEP2_INT (EFM32_USB_BASE+EFM32_USB_DOEP2_INT_OFFSET)
-#define EFM32_USB_DOEP2_TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP2_TSIZ_OFFSET)
-#define EFM32_USB_DOEP2_DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP2_DMAADDR_OFFSET)
-
-#define EFM32_USB_DOEP3_CTL (EFM32_USB_BASE+EFM32_USB_DOEP3_CTL_OFFSET)
-#define EFM32_USB_DOEP3_INT (EFM32_USB_BASE+EFM32_USB_DOEP3_INT_OFFSET)
-#define EFM32_USB_DOEP3_TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP3_TSIZ_OFFSET)
-#define EFM32_USB_DOEP3_DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP3_DMAADDR_OFFSET)
-
-#define EFM32_USB_DOEP4_CTL (EFM32_USB_BASE+EFM32_USB_DOEP4_CTL_OFFSET)
-#define EFM32_USB_DOEP4_INT (EFM32_USB_BASE+EFM32_USB_DOEP4_INT_OFFSET)
-#define EFM32_USB_DOEP4_TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP4_TSIZ_OFFSET)
-#define EFM32_USB_DOEP4_DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP4_DMAADDR_OFFSET)
-
-#define EFM32_USB_DOEP5_CTL (EFM32_USB_BASE+EFM32_USB_DOEP5_CTL_OFFSET)
-#define EFM32_USB_DOEP5_INT (EFM32_USB_BASE+EFM32_USB_DOEP5_INT_OFFSET)
-#define EFM32_USB_DOEP5_TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP5_TSIZ_OFFSET)
-#define EFM32_USB_DOEP5_DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP5_DMAADDR_OFFSET)
-
-#define EFM32_USB_DOEP6_CTL (EFM32_USB_BASE+EFM32_USB_DOEP6_CTL_OFFSET)
-#define EFM32_USB_DOEP6_INT (EFM32_USB_BASE+EFM32_USB_DOEP6_INT_OFFSET)
-#define EFM32_USB_DOEP6_TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP6_TSIZ_OFFSET)
-#define EFM32_USB_DOEP6_DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP6_DMAADDR_OFFSET)
+#define EFM32_USB_DOEPCTL(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPnCTL_OFFSET)
+#define EFM32_USB_DOEPINT(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPnINT_OFFSET)
+#define EFM32_USB_DOEPTSIZ(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPnTSIZ_OFFSET)
+#define EFM32_USB_DOEPDMAADDR(n) (EFM32_USB_DOEP_BASE(n)+EFM32_USB_DOEPnDMAADDR_OFFSET)
+
+#define EFM32_USB_DOEP0CTL (EFM32_USB_BASE+EFM32_USB_DOEP0CTL_OFFSET)
+#define EFM32_USB_DOEP0INT (EFM32_USB_BASE+EFM32_USB_DOEP0INT_OFFSET)
+#define EFM32_USB_DOEP0TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP0TSIZ_OFFSET)
+#define EFM32_USB_DOEP0DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP0DMAADDR_OFFSET)
+
+#define EFM32_USB_DOEP1CTL (EFM32_USB_BASE+EFM32_USB_DOEP1CTL_OFFSET)
+#define EFM32_USB_DOEP1INT (EFM32_USB_BASE+EFM32_USB_DOEP1INT_OFFSET)
+#define EFM32_USB_DOEP1TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP1TSIZ_OFFSET)
+#define EFM32_USB_DOEP1DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP1DMAADDR_OFFSET)
+
+#define EFM32_USB_DOEP2CTL (EFM32_USB_BASE+EFM32_USB_DOEP2CTL_OFFSET)
+#define EFM32_USB_DOEP2INT (EFM32_USB_BASE+EFM32_USB_DOEP2INT_OFFSET)
+#define EFM32_USB_DOEP2TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP2TSIZ_OFFSET)
+#define EFM32_USB_DOEP2DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP2DMAADDR_OFFSET)
+
+#define EFM32_USB_DOEP3CTL (EFM32_USB_BASE+EFM32_USB_DOEP3CTL_OFFSET)
+#define EFM32_USB_DOEP3INT (EFM32_USB_BASE+EFM32_USB_DOEP3INT_OFFSET)
+#define EFM32_USB_DOEP3TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP3TSIZ_OFFSET)
+#define EFM32_USB_DOEP3DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP3DMAADDR_OFFSET)
+
+#define EFM32_USB_DOEP4CTL (EFM32_USB_BASE+EFM32_USB_DOEP4CTL_OFFSET)
+#define EFM32_USB_DOEP4INT (EFM32_USB_BASE+EFM32_USB_DOEP4INT_OFFSET)
+#define EFM32_USB_DOEP4TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP4TSIZ_OFFSET)
+#define EFM32_USB_DOEP4DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP4DMAADDR_OFFSET)
+
+#define EFM32_USB_DOEP5CTL (EFM32_USB_BASE+EFM32_USB_DOEP5CTL_OFFSET)
+#define EFM32_USB_DOEP5INT (EFM32_USB_BASE+EFM32_USB_DOEP5INT_OFFSET)
+#define EFM32_USB_DOEP5TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP5TSIZ_OFFSET)
+#define EFM32_USB_DOEP5DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP5DMAADDR_OFFSET)
+
+#define EFM32_USB_DOEP6CTL (EFM32_USB_BASE+EFM32_USB_DOEP6CTL_OFFSET)
+#define EFM32_USB_DOEP6INT (EFM32_USB_BASE+EFM32_USB_DOEP6INT_OFFSET)
+#define EFM32_USB_DOEP6TSIZ (EFM32_USB_BASE+EFM32_USB_DOEP6TSIZ_OFFSET)
+#define EFM32_USB_DOEP6DMAADDR (EFM32_USB_BASE+EFM32_USB_DOEP6DMAADDR_OFFSET)
#define EFM32_USB_PCGCCTL (EFM32_USB_BASE+EFM32_USB_PCGCCTL_OFFSET)
@@ -2441,179 +2441,179 @@
#define _USB_DIEP0TXFSTS_SPCAVAIL_DEFAULT 0x00000200UL /* Mode DEFAULT for USB_DIEP0TXFSTS */
#define USB_DIEP0TXFSTS_SPCAVAIL_DEFAULT (_USB_DIEP0TXFSTS_SPCAVAIL_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEP0TXFSTS */
-/* Bit fields for USB DIEP_CTL */
-
-#define _USB_DIEP_CTL_RESETVALUE 0x00000000UL /* Default value for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_MASK 0xFFEF87FFUL /* Mask for USB_DIEP_CTL */
-
-#define _USB_DIEP_CTL_MPS_SHIFT 0 /* Shift value for USB_MPS */
-#define _USB_DIEP_CTL_MPS_MASK 0x7FFUL /* Bit mask for USB_MPS */
-#define _USB_DIEP_CTL_MPS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_MPS_DEFAULT (_USB_DIEP_CTL_MPS_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_USBACTEP (0x1UL << 15) /* USB Active Endpoint */
-#define _USB_DIEP_CTL_USBACTEP_SHIFT 15 /* Shift value for USB_USBACTEP */
-#define _USB_DIEP_CTL_USBACTEP_MASK 0x8000UL /* Bit mask for USB_USBACTEP */
-#define _USB_DIEP_CTL_USBACTEP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_USBACTEP_DEFAULT (_USB_DIEP_CTL_USBACTEP_DEFAULT << 15) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_DPIDEOF (0x1UL << 16) /* Endpoint Data PID / Even or Odd Frame */
-#define _USB_DIEP_CTL_DPIDEOF_SHIFT 16 /* Shift value for USB_DPIDEOF */
-#define _USB_DIEP_CTL_DPIDEOF_MASK 0x10000UL /* Bit mask for USB_DPIDEOF */
-#define _USB_DIEP_CTL_DPIDEOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_DPIDEOF_DATA0EVEN 0x00000000UL /* Mode DATA0EVEN for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_DPIDEOF_DATA1ODD 0x00000001UL /* Mode DATA1ODD for USB_DIEP_CTL */
-#define USB_DIEP_CTL_DPIDEOF_DEFAULT (_USB_DIEP_CTL_DPIDEOF_DEFAULT << 16) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_DPIDEOF_DATA0EVEN (_USB_DIEP_CTL_DPIDEOF_DATA0EVEN << 16) /* Shifted mode DATA0EVEN for USB_DIEP_CTL */
-#define USB_DIEP_CTL_DPIDEOF_DATA1ODD (_USB_DIEP_CTL_DPIDEOF_DATA1ODD << 16) /* Shifted mode DATA1ODD for USB_DIEP_CTL */
-#define USB_DIEP_CTL_NAKSTS (0x1UL << 17) /* NAK Status */
-#define _USB_DIEP_CTL_NAKSTS_SHIFT 17 /* Shift value for USB_NAKSTS */
-#define _USB_DIEP_CTL_NAKSTS_MASK 0x20000UL /* Bit mask for USB_NAKSTS */
-#define _USB_DIEP_CTL_NAKSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_NAKSTS_DEFAULT (_USB_DIEP_CTL_NAKSTS_DEFAULT << 17) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_EPTYPE_SHIFT 18 /* Shift value for USB_EPTYPE */
-#define _USB_DIEP_CTL_EPTYPE_MASK 0xC0000UL /* Bit mask for USB_EPTYPE */
-#define _USB_DIEP_CTL_EPTYPE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_EPTYPE_CONTROL 0x00000000UL /* Mode CONTROL for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_EPTYPE_ISO 0x00000001UL /* Mode ISO for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_EPTYPE_BULK 0x00000002UL /* Mode BULK for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_EPTYPE_INT 0x00000003UL /* Mode INT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPTYPE_DEFAULT (_USB_DIEP_CTL_EPTYPE_DEFAULT << 18) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPTYPE_CONTROL (_USB_DIEP_CTL_EPTYPE_CONTROL << 18) /* Shifted mode CONTROL for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPTYPE_ISO (_USB_DIEP_CTL_EPTYPE_ISO << 18) /* Shifted mode ISO for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPTYPE_BULK (_USB_DIEP_CTL_EPTYPE_BULK << 18) /* Shifted mode BULK for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPTYPE_INT (_USB_DIEP_CTL_EPTYPE_INT << 18) /* Shifted mode INT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_STALL (0x1UL << 21) /* Handshake */
-#define _USB_DIEP_CTL_STALL_SHIFT 21 /* Shift value for USB_STALL */
-#define _USB_DIEP_CTL_STALL_MASK 0x200000UL /* Bit mask for USB_STALL */
-#define _USB_DIEP_CTL_STALL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_STALL_DEFAULT (_USB_DIEP_CTL_STALL_DEFAULT << 21) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define _USB_DIEP_CTL_TXFNUM_SHIFT 22 /* Shift value for USB_TXFNUM */
-#define _USB_DIEP_CTL_TXFNUM_MASK 0x3c00000UL /* Bit mask for USB_TXFNUM */
-#define _USB_DIEP_CTL_TXFNUM_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_TXFNUM_DEFAULT (_USB_DIEP_CTL_TXFNUM_DEFAULT << 22) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_CNAK (0x1UL << 26) /* Clear NAK */
-#define _USB_DIEP_CTL_CNAK_SHIFT 26 /* Shift value for USB_CNAK */
-#define _USB_DIEP_CTL_CNAK_MASK 0x4000000UL /* Bit mask for USB_CNAK */
-#define _USB_DIEP_CTL_CNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_CNAK_DEFAULT (_USB_DIEP_CTL_CNAK_DEFAULT << 26) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_SNAK (0x1UL << 27) /* Set NAK */
-#define _USB_DIEP_CTL_SNAK_SHIFT 27 /* Shift value for USB_SNAK */
-#define _USB_DIEP_CTL_SNAK_MASK 0x8000000UL /* Bit mask for USB_SNAK */
-#define _USB_DIEP_CTL_SNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_SNAK_DEFAULT (_USB_DIEP_CTL_SNAK_DEFAULT << 27) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_SETD0PIDEF (0x1UL << 28) /* Set DATA0 PID / Even Frame */
-#define _USB_DIEP_CTL_SETD0PIDEF_SHIFT 28 /* Shift value for USB_SETD0PIDEF */
-#define _USB_DIEP_CTL_SETD0PIDEF_MASK 0x10000000UL /* Bit mask for USB_SETD0PIDEF */
-#define _USB_DIEP_CTL_SETD0PIDEF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_SETD0PIDEF_DEFAULT (_USB_DIEP_CTL_SETD0PIDEF_DEFAULT << 28) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_SETD1PIDOF (0x1UL << 29) /* Set DATA1 PID / Odd Frame */
-#define _USB_DIEP_CTL_SETD1PIDOF_SHIFT 29 /* Shift value for USB_SETD1PIDOF */
-#define _USB_DIEP_CTL_SETD1PIDOF_MASK 0x20000000UL /* Bit mask for USB_SETD1PIDOF */
-#define _USB_DIEP_CTL_SETD1PIDOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_SETD1PIDOF_DEFAULT (_USB_DIEP_CTL_SETD1PIDOF_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPDIS (0x1UL << 30) /* Endpoint Disable */
-#define _USB_DIEP_CTL_EPDIS_SHIFT 30 /* Shift value for USB_EPDIS */
-#define _USB_DIEP_CTL_EPDIS_MASK 0x40000000UL /* Bit mask for USB_EPDIS */
-#define _USB_DIEP_CTL_EPDIS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPDIS_DEFAULT (_USB_DIEP_CTL_EPDIS_DEFAULT << 30) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPENA (0x1UL << 31) /* Endpoint Enable */
-#define _USB_DIEP_CTL_EPENA_SHIFT 31 /* Shift value for USB_EPENA */
-#define _USB_DIEP_CTL_EPENA_MASK 0x80000000UL /* Bit mask for USB_EPENA */
-#define _USB_DIEP_CTL_EPENA_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_CTL */
-#define USB_DIEP_CTL_EPENA_DEFAULT (_USB_DIEP_CTL_EPENA_DEFAULT << 31) /* Shifted mode DEFAULT for USB_DIEP_CTL */
-
-/* Bit fields for USB DIEP_INT */
-
-#define _USB_DIEP_INT_RESETVALUE 0x00000080UL /* Default value for USB_DIEP_INT */
-#define _USB_DIEP_INT_MASK 0x000038DFUL /* Mask for USB_DIEP_INT */
-
-#define USB_DIEP_INT_XFERCOMPL (0x1UL << 0) /* Transfer Completed Interrupt */
-#define _USB_DIEP_INT_XFERCOMPL_SHIFT 0 /* Shift value for USB_XFERCOMPL */
-#define _USB_DIEP_INT_XFERCOMPL_MASK 0x1UL /* Bit mask for USB_XFERCOMPL */
-#define _USB_DIEP_INT_XFERCOMPL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_XFERCOMPL_DEFAULT (_USB_DIEP_INT_XFERCOMPL_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_EPDISBLD (0x1UL << 1) /* Endpoint Disabled Interrupt */
-#define _USB_DIEP_INT_EPDISBLD_SHIFT 1 /* Shift value for USB_EPDISBLD */
-#define _USB_DIEP_INT_EPDISBLD_MASK 0x2UL /* Bit mask for USB_EPDISBLD */
-#define _USB_DIEP_INT_EPDISBLD_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_EPDISBLD_DEFAULT (_USB_DIEP_INT_EPDISBLD_DEFAULT << 1) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_AHBERR (0x1UL << 2) /* AHB Error */
-#define _USB_DIEP_INT_AHBERR_SHIFT 2 /* Shift value for USB_AHBERR */
-#define _USB_DIEP_INT_AHBERR_MASK 0x4UL /* Bit mask for USB_AHBERR */
-#define _USB_DIEP_INT_AHBERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_AHBERR_DEFAULT (_USB_DIEP_INT_AHBERR_DEFAULT << 2) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_TIMEOUT (0x1UL << 3) /* Timeout Condition */
-#define _USB_DIEP_INT_TIMEOUT_SHIFT 3 /* Shift value for USB_TIMEOUT */
-#define _USB_DIEP_INT_TIMEOUT_MASK 0x8UL /* Bit mask for USB_TIMEOUT */
-#define _USB_DIEP_INT_TIMEOUT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_TIMEOUT_DEFAULT (_USB_DIEP_INT_TIMEOUT_DEFAULT << 3) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_INTKNTXFEMP (0x1UL << 4) /* IN Token Received When TxFIFO is Empty */
-#define _USB_DIEP_INT_INTKNTXFEMP_SHIFT 4 /* Shift value for USB_INTKNTXFEMP */
-#define _USB_DIEP_INT_INTKNTXFEMP_MASK 0x10UL /* Bit mask for USB_INTKNTXFEMP */
-#define _USB_DIEP_INT_INTKNTXFEMP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_INTKNTXFEMP_DEFAULT (_USB_DIEP_INT_INTKNTXFEMP_DEFAULT << 4) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_INEPNAKEFF (0x1UL << 6) /* IN Endpoint NAK Effective */
-#define _USB_DIEP_INT_INEPNAKEFF_SHIFT 6 /* Shift value for USB_INEPNAKEFF */
-#define _USB_DIEP_INT_INEPNAKEFF_MASK 0x40UL /* Bit mask for USB_INEPNAKEFF */
-#define _USB_DIEP_INT_INEPNAKEFF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_INEPNAKEFF_DEFAULT (_USB_DIEP_INT_INEPNAKEFF_DEFAULT << 6) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_TXFEMP (0x1UL << 7) /* Transmit FIFO Empty */
-#define _USB_DIEP_INT_TXFEMP_SHIFT 7 /* Shift value for USB_TXFEMP */
-#define _USB_DIEP_INT_TXFEMP_MASK 0x80UL /* Bit mask for USB_TXFEMP */
-#define _USB_DIEP_INT_TXFEMP_DEFAULT 0x00000001UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_TXFEMP_DEFAULT (_USB_DIEP_INT_TXFEMP_DEFAULT << 7) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_PKTDRPSTS (0x1UL << 11) /* Packet Drop Status */
-#define _USB_DIEP_INT_PKTDRPSTS_SHIFT 11 /* Shift value for USB_PKTDRPSTS */
-#define _USB_DIEP_INT_PKTDRPSTS_MASK 0x800UL /* Bit mask for USB_PKTDRPSTS */
-#define _USB_DIEP_INT_PKTDRPSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_PKTDRPSTS_DEFAULT (_USB_DIEP_INT_PKTDRPSTS_DEFAULT << 11) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_BBLEERR (0x1UL << 12) /* NAK Interrupt */
-#define _USB_DIEP_INT_BBLEERR_SHIFT 12 /* Shift value for USB_BBLEERR */
-#define _USB_DIEP_INT_BBLEERR_MASK 0x1000UL /* Bit mask for USB_BBLEERR */
-#define _USB_DIEP_INT_BBLEERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_BBLEERR_DEFAULT (_USB_DIEP_INT_BBLEERR_DEFAULT << 12) /* Shifted mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_NAKINTRPT (0x1UL << 13) /* NAK Interrupt */
-#define _USB_DIEP_INT_NAKINTRPT_SHIFT 13 /* Shift value for USB_NAKINTRPT */
-#define _USB_DIEP_INT_NAKINTRPT_MASK 0x2000UL /* Bit mask for USB_NAKINTRPT */
-#define _USB_DIEP_INT_NAKINTRPT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_INT */
-#define USB_DIEP_INT_NAKINTRPT_DEFAULT (_USB_DIEP_INT_NAKINTRPT_DEFAULT << 13) /* Shifted mode DEFAULT for USB_DIEP_INT */
-
-/* Bit fields for USB DIEP_TSIZ */
-
-#define _USB_DIEP_TSIZ_RESETVALUE 0x00000000UL /* Default value for USB_DIEP_TSIZ */
-#define _USB_DIEP_TSIZ_MASK 0x7FFFFFFFUL /* Mask for USB_DIEP_TSIZ */
-
-#define _USB_DIEP_TSIZ_XFERSIZE_SHIFT 0 /* Shift value for USB_XFERSIZE */
-#define _USB_DIEP_TSIZ_XFERSIZE_MASK 0x7FFFFUL /* Bit mask for USB_XFERSIZE */
-#define _USB_DIEP_TSIZ_XFERSIZE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_TSIZ */
-#define USB_DIEP_TSIZ_XFERSIZE_DEFAULT (_USB_DIEP_TSIZ_XFERSIZE_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEP_TSIZ */
-#define _USB_DIEP_TSIZ_PKTCNT_SHIFT 19 /* Shift value for USB_PKTCNT */
-#define _USB_DIEP_TSIZ_PKTCNT_MASK 0x1FF80000UL /* Bit mask for USB_PKTCNT */
-#define _USB_DIEP_TSIZ_PKTCNT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_TSIZ */
-#define USB_DIEP_TSIZ_PKTCNT_DEFAULT (_USB_DIEP_TSIZ_PKTCNT_DEFAULT << 19) /* Shifted mode DEFAULT for USB_DIEP_TSIZ */
-#define _USB_DIEP_TSIZ_MC_SHIFT 29 /* Shift value for USB_MC */
-#define _USB_DIEP_TSIZ_MC_MASK 0x60000000UL /* Bit mask for USB_MC */
-#define _USB_DIEP_TSIZ_MC_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_TSIZ */
-#define USB_DIEP_TSIZ_MC_DEFAULT (_USB_DIEP_TSIZ_MC_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DIEP_TSIZ */
-
-/* Bit fields for USB DIEP_DMAADDR */
-
-#define _USB_DIEP_DMAADDR_RESETVALUE 0x00000000UL /* Default value for USB_DIEP_DMAADDR */
-#define _USB_DIEP_DMAADDR_MASK 0xFFFFFFFFUL /* Mask for USB_DIEP_DMAADDR */
-
-#define _USB_DIEP_DMAADDR_DMAADDR_SHIFT 0 /* Shift value for USB_DMAADDR */
-#define _USB_DIEP_DMAADDR_DMAADDR_MASK 0xFFFFFFFFUL /* Bit mask for USB_DMAADDR */
-#define _USB_DIEP_DMAADDR_DMAADDR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEP_DMAADDR */
-#define USB_DIEP_DMAADDR_DMAADDR_DEFAULT (_USB_DIEP_DMAADDR_DMAADDR_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEP_DMAADDR */
-
-/* Bit fields for USB DIEP_TXFSTS */
-
-#define _USB_DIEP_TXFSTS_RESETVALUE 0x00000200UL /* Default value for USB_DIEP_TXFSTS */
-#define _USB_DIEP_TXFSTS_MASK 0x0000FFFFUL /* Mask for USB_DIEP_TXFSTS */
-
-#define _USB_DIEP_TXFSTS_SPCAVAIL_SHIFT 0 /* Shift value for USB_SPCAVAIL */
-#define _USB_DIEP_TXFSTS_SPCAVAIL_MASK 0xFFFFUL /* Bit mask for USB_SPCAVAIL */
-#define _USB_DIEP_TXFSTS_SPCAVAIL_DEFAULT 0x00000200UL /* Mode DEFAULT for USB_DIEP_TXFSTS */
-#define USB_DIEP_TXFSTS_SPCAVAIL_DEFAULT (_USB_DIEP_TXFSTS_SPCAVAIL_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEP_TXFSTS */
+/* Bit fields for USB DIEPCTL */
+
+#define _USB_DIEPCTL_RESETVALUE 0x00000000UL /* Default value for USB_DIEPCTL */
+#define _USB_DIEPCTL_MASK 0xFFEF87FFUL /* Mask for USB_DIEPCTL */
+
+#define _USB_DIEPCTL_MPS_SHIFT 0 /* Shift value for USB_MPS */
+#define _USB_DIEPCTL_MPS_MASK 0x7FFUL /* Bit mask for USB_MPS */
+#define _USB_DIEPCTL_MPS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_MPS_DEFAULT (_USB_DIEPCTL_MPS_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_USBACTEP (0x1UL << 15) /* USB Active Endpoint */
+#define _USB_DIEPCTL_USBACTEP_SHIFT 15 /* Shift value for USB_USBACTEP */
+#define _USB_DIEPCTL_USBACTEP_MASK 0x8000UL /* Bit mask for USB_USBACTEP */
+#define _USB_DIEPCTL_USBACTEP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_USBACTEP_DEFAULT (_USB_DIEPCTL_USBACTEP_DEFAULT << 15) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_DPIDEOF (0x1UL << 16) /* Endpoint Data PID / Even or Odd Frame */
+#define _USB_DIEPCTL_DPIDEOF_SHIFT 16 /* Shift value for USB_DPIDEOF */
+#define _USB_DIEPCTL_DPIDEOF_MASK 0x10000UL /* Bit mask for USB_DPIDEOF */
+#define _USB_DIEPCTL_DPIDEOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define _USB_DIEPCTL_DPIDEOF_DATA0EVEN 0x00000000UL /* Mode DATA0EVEN for USB_DIEPCTL */
+#define _USB_DIEPCTL_DPIDEOF_DATA1ODD 0x00000001UL /* Mode DATA1ODD for USB_DIEPCTL */
+#define USB_DIEPCTL_DPIDEOF_DEFAULT (_USB_DIEPCTL_DPIDEOF_DEFAULT << 16) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_DPIDEOF_DATA0EVEN (_USB_DIEPCTL_DPIDEOF_DATA0EVEN << 16) /* Shifted mode DATA0EVEN for USB_DIEPCTL */
+#define USB_DIEPCTL_DPIDEOF_DATA1ODD (_USB_DIEPCTL_DPIDEOF_DATA1ODD << 16) /* Shifted mode DATA1ODD for USB_DIEPCTL */
+#define USB_DIEPCTL_NAKSTS (0x1UL << 17) /* NAK Status */
+#define _USB_DIEPCTL_NAKSTS_SHIFT 17 /* Shift value for USB_NAKSTS */
+#define _USB_DIEPCTL_NAKSTS_MASK 0x20000UL /* Bit mask for USB_NAKSTS */
+#define _USB_DIEPCTL_NAKSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_NAKSTS_DEFAULT (_USB_DIEPCTL_NAKSTS_DEFAULT << 17) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define _USB_DIEPCTL_EPTYPE_SHIFT 18 /* Shift value for USB_EPTYPE */
+#define _USB_DIEPCTL_EPTYPE_MASK 0xC0000UL /* Bit mask for USB_EPTYPE */
+#define _USB_DIEPCTL_EPTYPE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define _USB_DIEPCTL_EPTYPE_CONTROL 0x00000000UL /* Mode CONTROL for USB_DIEPCTL */
+#define _USB_DIEPCTL_EPTYPE_ISO 0x00000001UL /* Mode ISO for USB_DIEPCTL */
+#define _USB_DIEPCTL_EPTYPE_BULK 0x00000002UL /* Mode BULK for USB_DIEPCTL */
+#define _USB_DIEPCTL_EPTYPE_INT 0x00000003UL /* Mode INT for USB_DIEPCTL */
+#define USB_DIEPCTL_EPTYPE_DEFAULT (_USB_DIEPCTL_EPTYPE_DEFAULT << 18) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_EPTYPE_CONTROL (_USB_DIEPCTL_EPTYPE_CONTROL << 18) /* Shifted mode CONTROL for USB_DIEPCTL */
+#define USB_DIEPCTL_EPTYPE_ISO (_USB_DIEPCTL_EPTYPE_ISO << 18) /* Shifted mode ISO for USB_DIEPCTL */
+#define USB_DIEPCTL_EPTYPE_BULK (_USB_DIEPCTL_EPTYPE_BULK << 18) /* Shifted mode BULK for USB_DIEPCTL */
+#define USB_DIEPCTL_EPTYPE_INT (_USB_DIEPCTL_EPTYPE_INT << 18) /* Shifted mode INT for USB_DIEPCTL */
+#define USB_DIEPCTL_STALL (0x1UL << 21) /* Handshake */
+#define _USB_DIEPCTL_STALL_SHIFT 21 /* Shift value for USB_STALL */
+#define _USB_DIEPCTL_STALL_MASK 0x200000UL /* Bit mask for USB_STALL */
+#define _USB_DIEPCTL_STALL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_STALL_DEFAULT (_USB_DIEPCTL_STALL_DEFAULT << 21) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define _USB_DIEPCTL_TXFNUM_SHIFT 22 /* Shift value for USB_TXFNUM */
+#define _USB_DIEPCTL_TXFNUM_MASK 0x3c00000UL /* Bit mask for USB_TXFNUM */
+#define _USB_DIEPCTL_TXFNUM_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_TXFNUM_DEFAULT (_USB_DIEPCTL_TXFNUM_DEFAULT << 22) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_CNAK (0x1UL << 26) /* Clear NAK */
+#define _USB_DIEPCTL_CNAK_SHIFT 26 /* Shift value for USB_CNAK */
+#define _USB_DIEPCTL_CNAK_MASK 0x4000000UL /* Bit mask for USB_CNAK */
+#define _USB_DIEPCTL_CNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_CNAK_DEFAULT (_USB_DIEPCTL_CNAK_DEFAULT << 26) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_SNAK (0x1UL << 27) /* Set NAK */
+#define _USB_DIEPCTL_SNAK_SHIFT 27 /* Shift value for USB_SNAK */
+#define _USB_DIEPCTL_SNAK_MASK 0x8000000UL /* Bit mask for USB_SNAK */
+#define _USB_DIEPCTL_SNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_SNAK_DEFAULT (_USB_DIEPCTL_SNAK_DEFAULT << 27) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_SETD0PIDEF (0x1UL << 28) /* Set DATA0 PID / Even Frame */
+#define _USB_DIEPCTL_SETD0PIDEF_SHIFT 28 /* Shift value for USB_SETD0PIDEF */
+#define _USB_DIEPCTL_SETD0PIDEF_MASK 0x10000000UL /* Bit mask for USB_SETD0PIDEF */
+#define _USB_DIEPCTL_SETD0PIDEF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_SETD0PIDEF_DEFAULT (_USB_DIEPCTL_SETD0PIDEF_DEFAULT << 28) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_SETD1PIDOF (0x1UL << 29) /* Set DATA1 PID / Odd Frame */
+#define _USB_DIEPCTL_SETD1PIDOF_SHIFT 29 /* Shift value for USB_SETD1PIDOF */
+#define _USB_DIEPCTL_SETD1PIDOF_MASK 0x20000000UL /* Bit mask for USB_SETD1PIDOF */
+#define _USB_DIEPCTL_SETD1PIDOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_SETD1PIDOF_DEFAULT (_USB_DIEPCTL_SETD1PIDOF_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_EPDIS (0x1UL << 30) /* Endpoint Disable */
+#define _USB_DIEPCTL_EPDIS_SHIFT 30 /* Shift value for USB_EPDIS */
+#define _USB_DIEPCTL_EPDIS_MASK 0x40000000UL /* Bit mask for USB_EPDIS */
+#define _USB_DIEPCTL_EPDIS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_EPDIS_DEFAULT (_USB_DIEPCTL_EPDIS_DEFAULT << 30) /* Shifted mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_EPENA (0x1UL << 31) /* Endpoint Enable */
+#define _USB_DIEPCTL_EPENA_SHIFT 31 /* Shift value for USB_EPENA */
+#define _USB_DIEPCTL_EPENA_MASK 0x80000000UL /* Bit mask for USB_EPENA */
+#define _USB_DIEPCTL_EPENA_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPCTL */
+#define USB_DIEPCTL_EPENA_DEFAULT (_USB_DIEPCTL_EPENA_DEFAULT << 31) /* Shifted mode DEFAULT for USB_DIEPCTL */
+
+/* Bit fields for USB DIEPINT */
+
+#define _USB_DIEPINT_RESETVALUE 0x00000080UL /* Default value for USB_DIEPINT */
+#define _USB_DIEPINT_MASK 0x000038DFUL /* Mask for USB_DIEPINT */
+
+#define USB_DIEPINT_XFERCOMPL (0x1UL << 0) /* Transfer Completed Interrupt */
+#define _USB_DIEPINT_XFERCOMPL_SHIFT 0 /* Shift value for USB_XFERCOMPL */
+#define _USB_DIEPINT_XFERCOMPL_MASK 0x1UL /* Bit mask for USB_XFERCOMPL */
+#define _USB_DIEPINT_XFERCOMPL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_XFERCOMPL_DEFAULT (_USB_DIEPINT_XFERCOMPL_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_EPDISBLD (0x1UL << 1) /* Endpoint Disabled Interrupt */
+#define _USB_DIEPINT_EPDISBLD_SHIFT 1 /* Shift value for USB_EPDISBLD */
+#define _USB_DIEPINT_EPDISBLD_MASK 0x2UL /* Bit mask for USB_EPDISBLD */
+#define _USB_DIEPINT_EPDISBLD_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_EPDISBLD_DEFAULT (_USB_DIEPINT_EPDISBLD_DEFAULT << 1) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_AHBERR (0x1UL << 2) /* AHB Error */
+#define _USB_DIEPINT_AHBERR_SHIFT 2 /* Shift value for USB_AHBERR */
+#define _USB_DIEPINT_AHBERR_MASK 0x4UL /* Bit mask for USB_AHBERR */
+#define _USB_DIEPINT_AHBERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_AHBERR_DEFAULT (_USB_DIEPINT_AHBERR_DEFAULT << 2) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_TIMEOUT (0x1UL << 3) /* Timeout Condition */
+#define _USB_DIEPINT_TIMEOUT_SHIFT 3 /* Shift value for USB_TIMEOUT */
+#define _USB_DIEPINT_TIMEOUT_MASK 0x8UL /* Bit mask for USB_TIMEOUT */
+#define _USB_DIEPINT_TIMEOUT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_TIMEOUT_DEFAULT (_USB_DIEPINT_TIMEOUT_DEFAULT << 3) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_INTKNTXFEMP (0x1UL << 4) /* IN Token Received When TxFIFO is Empty */
+#define _USB_DIEPINT_INTKNTXFEMP_SHIFT 4 /* Shift value for USB_INTKNTXFEMP */
+#define _USB_DIEPINT_INTKNTXFEMP_MASK 0x10UL /* Bit mask for USB_INTKNTXFEMP */
+#define _USB_DIEPINT_INTKNTXFEMP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_INTKNTXFEMP_DEFAULT (_USB_DIEPINT_INTKNTXFEMP_DEFAULT << 4) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_INEPNAKEFF (0x1UL << 6) /* IN Endpoint NAK Effective */
+#define _USB_DIEPINT_INEPNAKEFF_SHIFT 6 /* Shift value for USB_INEPNAKEFF */
+#define _USB_DIEPINT_INEPNAKEFF_MASK 0x40UL /* Bit mask for USB_INEPNAKEFF */
+#define _USB_DIEPINT_INEPNAKEFF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_INEPNAKEFF_DEFAULT (_USB_DIEPINT_INEPNAKEFF_DEFAULT << 6) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_TXFEMP (0x1UL << 7) /* Transmit FIFO Empty */
+#define _USB_DIEPINT_TXFEMP_SHIFT 7 /* Shift value for USB_TXFEMP */
+#define _USB_DIEPINT_TXFEMP_MASK 0x80UL /* Bit mask for USB_TXFEMP */
+#define _USB_DIEPINT_TXFEMP_DEFAULT 0x00000001UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_TXFEMP_DEFAULT (_USB_DIEPINT_TXFEMP_DEFAULT << 7) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_PKTDRPSTS (0x1UL << 11) /* Packet Drop Status */
+#define _USB_DIEPINT_PKTDRPSTS_SHIFT 11 /* Shift value for USB_PKTDRPSTS */
+#define _USB_DIEPINT_PKTDRPSTS_MASK 0x800UL /* Bit mask for USB_PKTDRPSTS */
+#define _USB_DIEPINT_PKTDRPSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_PKTDRPSTS_DEFAULT (_USB_DIEPINT_PKTDRPSTS_DEFAULT << 11) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_BBLEERR (0x1UL << 12) /* NAK Interrupt */
+#define _USB_DIEPINT_BBLEERR_SHIFT 12 /* Shift value for USB_BBLEERR */
+#define _USB_DIEPINT_BBLEERR_MASK 0x1000UL /* Bit mask for USB_BBLEERR */
+#define _USB_DIEPINT_BBLEERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_BBLEERR_DEFAULT (_USB_DIEPINT_BBLEERR_DEFAULT << 12) /* Shifted mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_NAKINTRPT (0x1UL << 13) /* NAK Interrupt */
+#define _USB_DIEPINT_NAKINTRPT_SHIFT 13 /* Shift value for USB_NAKINTRPT */
+#define _USB_DIEPINT_NAKINTRPT_MASK 0x2000UL /* Bit mask for USB_NAKINTRPT */
+#define _USB_DIEPINT_NAKINTRPT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPINT */
+#define USB_DIEPINT_NAKINTRPT_DEFAULT (_USB_DIEPINT_NAKINTRPT_DEFAULT << 13) /* Shifted mode DEFAULT for USB_DIEPINT */
+
+/* Bit fields for USB DIEPTSIZ */
+
+#define _USB_DIEPTSIZ_RESETVALUE 0x00000000UL /* Default value for USB_DIEPTSIZ */
+#define _USB_DIEPTSIZ_MASK 0x7FFFFFFFUL /* Mask for USB_DIEPTSIZ */
+
+#define _USB_DIEPTSIZ_XFERSIZE_SHIFT 0 /* Shift value for USB_XFERSIZE */
+#define _USB_DIEPTSIZ_XFERSIZE_MASK 0x7FFFFUL /* Bit mask for USB_XFERSIZE */
+#define _USB_DIEPTSIZ_XFERSIZE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPTSIZ */
+#define USB_DIEPTSIZ_XFERSIZE_DEFAULT (_USB_DIEPTSIZ_XFERSIZE_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEPTSIZ */
+#define _USB_DIEPTSIZ_PKTCNT_SHIFT 19 /* Shift value for USB_PKTCNT */
+#define _USB_DIEPTSIZ_PKTCNT_MASK 0x1FF80000UL /* Bit mask for USB_PKTCNT */
+#define _USB_DIEPTSIZ_PKTCNT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPTSIZ */
+#define USB_DIEPTSIZ_PKTCNT_DEFAULT (_USB_DIEPTSIZ_PKTCNT_DEFAULT << 19) /* Shifted mode DEFAULT for USB_DIEPTSIZ */
+#define _USB_DIEPTSIZ_MC_SHIFT 29 /* Shift value for USB_MC */
+#define _USB_DIEPTSIZ_MC_MASK 0x60000000UL /* Bit mask for USB_MC */
+#define _USB_DIEPTSIZ_MC_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPTSIZ */
+#define USB_DIEPTSIZ_MC_DEFAULT (_USB_DIEPTSIZ_MC_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DIEPTSIZ */
+
+/* Bit fields for USB DIEPDMAADDR */
+
+#define _USB_DIEPDMAADDR_RESETVALUE 0x00000000UL /* Default value for USB_DIEPDMAADDR */
+#define _USB_DIEPDMAADDR_MASK 0xFFFFFFFFUL /* Mask for USB_DIEPDMAADDR */
+
+#define _USB_DIEPDMAADDR_DMAADDR_SHIFT 0 /* Shift value for USB_DMAADDR */
+#define _USB_DIEPDMAADDR_DMAADDR_MASK 0xFFFFFFFFUL /* Bit mask for USB_DMAADDR */
+#define _USB_DIEPDMAADDR_DMAADDR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DIEPDMAADDR */
+#define USB_DIEPDMAADDR_DMAADDR_DEFAULT (_USB_DIEPDMAADDR_DMAADDR_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEPDMAADDR */
+
+/* Bit fields for USB DIEPTXFSTS */
+
+#define _USB_DIEPTXFSTS_RESETVALUE 0x00000200UL /* Default value for USB_DIEPTXFSTS */
+#define _USB_DIEPTXFSTS_MASK 0x0000FFFFUL /* Mask for USB_DIEPTXFSTS */
+
+#define _USB_DIEPTXFSTS_SPCAVAIL_SHIFT 0 /* Shift value for USB_SPCAVAIL */
+#define _USB_DIEPTXFSTS_SPCAVAIL_MASK 0xFFFFUL /* Bit mask for USB_SPCAVAIL */
+#define _USB_DIEPTXFSTS_SPCAVAIL_DEFAULT 0x00000200UL /* Mode DEFAULT for USB_DIEPTXFSTS */
+#define USB_DIEPTXFSTS_SPCAVAIL_DEFAULT (_USB_DIEPTXFSTS_SPCAVAIL_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DIEPTXFSTS */
/* Bit fields for USB DOEP0CTL */
@@ -2757,173 +2757,173 @@
#define _USB_DOEP0DMAADDR_DOEP0DMAADDR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP0DMAADDR */
#define USB_DOEP0DMAADDR_DOEP0DMAADDR_DEFAULT (_USB_DOEP0DMAADDR_DOEP0DMAADDR_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEP0DMAADDR */
-/* Bit fields for USB DOEP_CTL */
-
-#define _USB_DOEP_CTL_RESETVALUE 0x00000000UL /* Default value for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_MASK 0xFC3F87FFUL /* Mask for USB_DOEP_CTL */
-
-#define _USB_DOEP_CTL_MPS_SHIFT 0 /* Shift value for USB_MPS */
-#define _USB_DOEP_CTL_MPS_MASK 0x7FFUL /* Bit mask for USB_MPS */
-#define _USB_DOEP_CTL_MPS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_MPS_DEFAULT (_USB_DOEP_CTL_MPS_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_USBACTEP (0x1UL << 15) /* USB Active Endpoint */
-#define _USB_DOEP_CTL_USBACTEP_SHIFT 15 /* Shift value for USB_USBACTEP */
-#define _USB_DOEP_CTL_USBACTEP_MASK 0x8000UL /* Bit mask for USB_USBACTEP */
-#define _USB_DOEP_CTL_USBACTEP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_USBACTEP_DEFAULT (_USB_DOEP_CTL_USBACTEP_DEFAULT << 15) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_DPIDEOF (0x1UL << 16) /* Endpoint Data PID / Even-odd Frame */
-#define _USB_DOEP_CTL_DPIDEOF_SHIFT 16 /* Shift value for USB_DPIDEOF */
-#define _USB_DOEP_CTL_DPIDEOF_MASK 0x10000UL /* Bit mask for USB_DPIDEOF */
-#define _USB_DOEP_CTL_DPIDEOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_DPIDEOF_DATA0EVEN 0x00000000UL /* Mode DATA0EVEN for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_DPIDEOF_DATA1ODD 0x00000001UL /* Mode DATA1ODD for USB_DOEP_CTL */
-#define USB_DOEP_CTL_DPIDEOF_DEFAULT (_USB_DOEP_CTL_DPIDEOF_DEFAULT << 16) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_DPIDEOF_DATA0EVEN (_USB_DOEP_CTL_DPIDEOF_DATA0EVEN << 16) /* Shifted mode DATA0EVEN for USB_DOEP_CTL */
-#define USB_DOEP_CTL_DPIDEOF_DATA1ODD (_USB_DOEP_CTL_DPIDEOF_DATA1ODD << 16) /* Shifted mode DATA1ODD for USB_DOEP_CTL */
-#define USB_DOEP_CTL_NAKSTS (0x1UL << 17) /* NAK Status */
-#define _USB_DOEP_CTL_NAKSTS_SHIFT 17 /* Shift value for USB_NAKSTS */
-#define _USB_DOEP_CTL_NAKSTS_MASK 0x20000UL /* Bit mask for USB_NAKSTS */
-#define _USB_DOEP_CTL_NAKSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_NAKSTS_DEFAULT (_USB_DOEP_CTL_NAKSTS_DEFAULT << 17) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_EPTYPE_SHIFT 18 /* Shift value for USB_EPTYPE */
-#define _USB_DOEP_CTL_EPTYPE_MASK 0xC0000UL /* Bit mask for USB_EPTYPE */
-#define _USB_DOEP_CTL_EPTYPE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_EPTYPE_CONTROL 0x00000000UL /* Mode CONTROL for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_EPTYPE_ISO 0x00000001UL /* Mode ISO for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_EPTYPE_BULK 0x00000002UL /* Mode BULK for USB_DOEP_CTL */
-#define _USB_DOEP_CTL_EPTYPE_INT 0x00000003UL /* Mode INT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPTYPE_DEFAULT (_USB_DOEP_CTL_EPTYPE_DEFAULT << 18) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPTYPE_CONTROL (_USB_DOEP_CTL_EPTYPE_CONTROL << 18) /* Shifted mode CONTROL for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPTYPE_ISO (_USB_DOEP_CTL_EPTYPE_ISO << 18) /* Shifted mode ISO for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPTYPE_BULK (_USB_DOEP_CTL_EPTYPE_BULK << 18) /* Shifted mode BULK for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPTYPE_INT (_USB_DOEP_CTL_EPTYPE_INT << 18) /* Shifted mode INT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SNP (0x1UL << 20) /* Snoop Mode */
-#define _USB_DOEP_CTL_SNP_SHIFT 20 /* Shift value for USB_SNP */
-#define _USB_DOEP_CTL_SNP_MASK 0x100000UL /* Bit mask for USB_SNP */
-#define _USB_DOEP_CTL_SNP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SNP_DEFAULT (_USB_DOEP_CTL_SNP_DEFAULT << 20) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_STALL (0x1UL << 21) /* STALL Handshake */
-#define _USB_DOEP_CTL_STALL_SHIFT 21 /* Shift value for USB_STALL */
-#define _USB_DOEP_CTL_STALL_MASK 0x200000UL /* Bit mask for USB_STALL */
-#define _USB_DOEP_CTL_STALL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_STALL_DEFAULT (_USB_DOEP_CTL_STALL_DEFAULT << 21) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_CNAK (0x1UL << 26) /* Clear NAK */
-#define _USB_DOEP_CTL_CNAK_SHIFT 26 /* Shift value for USB_CNAK */
-#define _USB_DOEP_CTL_CNAK_MASK 0x4000000UL /* Bit mask for USB_CNAK */
-#define _USB_DOEP_CTL_CNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_CNAK_DEFAULT (_USB_DOEP_CTL_CNAK_DEFAULT << 26) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SNAK (0x1UL << 27) /* Set NAK */
-#define _USB_DOEP_CTL_SNAK_SHIFT 27 /* Shift value for USB_SNAK */
-#define _USB_DOEP_CTL_SNAK_MASK 0x8000000UL /* Bit mask for USB_SNAK */
-#define _USB_DOEP_CTL_SNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SNAK_DEFAULT (_USB_DOEP_CTL_SNAK_DEFAULT << 27) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SETD0PIDEF (0x1UL << 28) /* Set DATA0 PID / Even Frame */
-#define _USB_DOEP_CTL_SETD0PIDEF_SHIFT 28 /* Shift value for USB_SETD0PIDEF */
-#define _USB_DOEP_CTL_SETD0PIDEF_MASK 0x10000000UL /* Bit mask for USB_SETD0PIDEF */
-#define _USB_DOEP_CTL_SETD0PIDEF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SETD0PIDEF_DEFAULT (_USB_DOEP_CTL_SETD0PIDEF_DEFAULT << 28) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SETD1PIDOF (0x1UL << 29) /* Set DATA1 PID / Odd Frame */
-#define _USB_DOEP_CTL_SETD1PIDOF_SHIFT 29 /* Shift value for USB_SETD1PIDOF */
-#define _USB_DOEP_CTL_SETD1PIDOF_MASK 0x20000000UL /* Bit mask for USB_SETD1PIDOF */
-#define _USB_DOEP_CTL_SETD1PIDOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_SETD1PIDOF_DEFAULT (_USB_DOEP_CTL_SETD1PIDOF_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPDIS (0x1UL << 30) /* Endpoint Disable */
-#define _USB_DOEP_CTL_EPDIS_SHIFT 30 /* Shift value for USB_EPDIS */
-#define _USB_DOEP_CTL_EPDIS_MASK 0x40000000UL /* Bit mask for USB_EPDIS */
-#define _USB_DOEP_CTL_EPDIS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPDIS_DEFAULT (_USB_DOEP_CTL_EPDIS_DEFAULT << 30) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPENA (0x1UL << 31) /* Endpoint Enable */
-#define _USB_DOEP_CTL_EPENA_SHIFT 31 /* Shift value for USB_EPENA */
-#define _USB_DOEP_CTL_EPENA_MASK 0x80000000UL /* Bit mask for USB_EPENA */
-#define _USB_DOEP_CTL_EPENA_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_CTL */
-#define USB_DOEP_CTL_EPENA_DEFAULT (_USB_DOEP_CTL_EPENA_DEFAULT << 31) /* Shifted mode DEFAULT for USB_DOEP_CTL */
-
-/* Bit fields for USB DOEP_INT */
-
-#define _USB_DOEP_INT_RESETVALUE 0x00000000UL /* Default value for USB_DOEP_INT */
-#define _USB_DOEP_INT_MASK 0x0000385FUL /* Mask for USB_DOEP_INT */
-
-#define USB_DOEP_INT_XFERCOMPL (0x1UL << 0) /* Transfer Completed Interrupt */
-#define _USB_DOEP_INT_XFERCOMPL_SHIFT 0 /* Shift value for USB_XFERCOMPL */
-#define _USB_DOEP_INT_XFERCOMPL_MASK 0x1UL /* Bit mask for USB_XFERCOMPL */
-#define _USB_DOEP_INT_XFERCOMPL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_XFERCOMPL_DEFAULT (_USB_DOEP_INT_XFERCOMPL_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_EPDISBLD (0x1UL << 1) /* Endpoint Disabled Interrupt */
-#define _USB_DOEP_INT_EPDISBLD_SHIFT 1 /* Shift value for USB_EPDISBLD */
-#define _USB_DOEP_INT_EPDISBLD_MASK 0x2UL /* Bit mask for USB_EPDISBLD */
-#define _USB_DOEP_INT_EPDISBLD_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_EPDISBLD_DEFAULT (_USB_DOEP_INT_EPDISBLD_DEFAULT << 1) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_AHBERR (0x1UL << 2) /* AHB Error */
-#define _USB_DOEP_INT_AHBERR_SHIFT 2 /* Shift value for USB_AHBERR */
-#define _USB_DOEP_INT_AHBERR_MASK 0x4UL /* Bit mask for USB_AHBERR */
-#define _USB_DOEP_INT_AHBERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_AHBERR_DEFAULT (_USB_DOEP_INT_AHBERR_DEFAULT << 2) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_SETUP (0x1UL << 3) /* Setup Phase Done */
-#define _USB_DOEP_INT_SETUP_SHIFT 3 /* Shift value for USB_SETUP */
-#define _USB_DOEP_INT_SETUP_MASK 0x8UL /* Bit mask for USB_SETUP */
-#define _USB_DOEP_INT_SETUP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_SETUP_DEFAULT (_USB_DOEP_INT_SETUP_DEFAULT << 3) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_OUTTKNEPDIS (0x1UL << 4) /* OUT Token Received When Endpoint Disabled */
-#define _USB_DOEP_INT_OUTTKNEPDIS_SHIFT 4 /* Shift value for USB_OUTTKNEPDIS */
-#define _USB_DOEP_INT_OUTTKNEPDIS_MASK 0x10UL /* Bit mask for USB_OUTTKNEPDIS */
-#define _USB_DOEP_INT_OUTTKNEPDIS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_OUTTKNEPDIS_DEFAULT (_USB_DOEP_INT_OUTTKNEPDIS_DEFAULT << 4) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_BACK2BACKSETUP (0x1UL << 6) /* Back-to-Back SETUP Packets Received */
-#define _USB_DOEP_INT_BACK2BACKSETUP_SHIFT 6 /* Shift value for USB_BACK2BACKSETUP */
-#define _USB_DOEP_INT_BACK2BACKSETUP_MASK 0x40UL /* Bit mask for USB_BACK2BACKSETUP */
-#define _USB_DOEP_INT_BACK2BACKSETUP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_BACK2BACKSETUP_DEFAULT (_USB_DOEP_INT_BACK2BACKSETUP_DEFAULT << 6) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_PKTDRPSTS (0x1UL << 11) /* Packet Drop Status */
-#define _USB_DOEP_INT_PKTDRPSTS_SHIFT 11 /* Shift value for USB_PKTDRPSTS */
-#define _USB_DOEP_INT_PKTDRPSTS_MASK 0x800UL /* Bit mask for USB_PKTDRPSTS */
-#define _USB_DOEP_INT_PKTDRPSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_PKTDRPSTS_DEFAULT (_USB_DOEP_INT_PKTDRPSTS_DEFAULT << 11) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_BBLEERR (0x1UL << 12) /* Babble Error */
-#define _USB_DOEP_INT_BBLEERR_SHIFT 12 /* Shift value for USB_BBLEERR */
-#define _USB_DOEP_INT_BBLEERR_MASK 0x1000UL /* Bit mask for USB_BBLEERR */
-#define _USB_DOEP_INT_BBLEERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_BBLEERR_DEFAULT (_USB_DOEP_INT_BBLEERR_DEFAULT << 12) /* Shifted mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_NAKINTRPT (0x1UL << 13) /* NAK Interrupt */
-#define _USB_DOEP_INT_NAKINTRPT_SHIFT 13 /* Shift value for USB_NAKINTRPT */
-#define _USB_DOEP_INT_NAKINTRPT_MASK 0x2000UL /* Bit mask for USB_NAKINTRPT */
-#define _USB_DOEP_INT_NAKINTRPT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_INT */
-#define USB_DOEP_INT_NAKINTRPT_DEFAULT (_USB_DOEP_INT_NAKINTRPT_DEFAULT << 13) /* Shifted mode DEFAULT for USB_DOEP_INT */
-
-/* Bit fields for USB DOEP_TSIZ */
-
-#define _USB_DOEP_TSIZ_RESETVALUE 0x00000000UL /* Default value for USB_DOEP_TSIZ */
-#define _USB_DOEP_TSIZ_MASK 0x7FFFFFFFUL /* Mask for USB_DOEP_TSIZ */
-
-#define _USB_DOEP_TSIZ_XFERSIZE_SHIFT 0 /* Shift value for USB_XFERSIZE */
-#define _USB_DOEP_TSIZ_XFERSIZE_MASK 0x7FFFFUL /* Bit mask for USB_XFERSIZE */
-#define _USB_DOEP_TSIZ_XFERSIZE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_TSIZ */
-#define USB_DOEP_TSIZ_XFERSIZE_DEFAULT (_USB_DOEP_TSIZ_XFERSIZE_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEP_TSIZ */
-#define _USB_DOEP_TSIZ_PKTCNT_SHIFT 19 /* Shift value for USB_PKTCNT */
-#define _USB_DOEP_TSIZ_PKTCNT_MASK 0x1FF80000UL /* Bit mask for USB_PKTCNT */
-#define _USB_DOEP_TSIZ_PKTCNT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_TSIZ */
-#define USB_DOEP_TSIZ_PKTCNT_DEFAULT (_USB_DOEP_TSIZ_PKTCNT_DEFAULT << 19) /* Shifted mode DEFAULT for USB_DOEP_TSIZ */
-#define _USB_DOEP_TSIZ_RXDPIDSUPCNT_SHIFT 29 /* Shift value for USB_RXDPIDSUPCNT */
-#define _USB_DOEP_TSIZ_RXDPIDSUPCNT_MASK 0x60000000UL /* Bit mask for USB_RXDPIDSUPCNT */
-#define _USB_DOEP_TSIZ_RXDPIDSUPCNT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_TSIZ */
-#define _USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA0 0x00000000UL /* Mode DATA0 for USB_DOEP_TSIZ */
-#define _USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA2 0x00000001UL /* Mode DATA2 for USB_DOEP_TSIZ */
-#define _USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA1 0x00000002UL /* Mode DATA1 for USB_DOEP_TSIZ */
-#define _USB_DOEP_TSIZ_RXDPIDSUPCNT_MDATA 0x00000003UL /* Mode MDATA for USB_DOEP_TSIZ */
-#define USB_DOEP_TSIZ_RXDPIDSUPCNT_DEFAULT (_USB_DOEP_TSIZ_RXDPIDSUPCNT_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DOEP_TSIZ */
-#define USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA0 (_USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA0 << 29) /* Shifted mode DATA0 for USB_DOEP_TSIZ */
-#define USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA2 (_USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA2 << 29) /* Shifted mode DATA2 for USB_DOEP_TSIZ */
-#define USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA1 (_USB_DOEP_TSIZ_RXDPIDSUPCNT_DATA1 << 29) /* Shifted mode DATA1 for USB_DOEP_TSIZ */
-#define USB_DOEP_TSIZ_RXDPIDSUPCNT_MDATA (_USB_DOEP_TSIZ_RXDPIDSUPCNT_MDATA << 29) /* Shifted mode MDATA for USB_DOEP_TSIZ */
-
-/* Bit fields for USB DOEP_DMAADDR */
-
-#define _USB_DOEP_DMAADDR_RESETVALUE 0x00000000UL /* Default value for USB_DOEP_DMAADDR */
-#define _USB_DOEP_DMAADDR_MASK 0xFFFFFFFFUL /* Mask for USB_DOEP_DMAADDR */
-
-#define _USB_DOEP_DMAADDR_DMAADDR_SHIFT 0 /* Shift value for USB_DMAADDR */
-#define _USB_DOEP_DMAADDR_DMAADDR_MASK 0xFFFFFFFFUL /* Bit mask for USB_DMAADDR */
-#define _USB_DOEP_DMAADDR_DMAADDR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEP_DMAADDR */
-#define USB_DOEP_DMAADDR_DMAADDR_DEFAULT (_USB_DOEP_DMAADDR_DMAADDR_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEP_DMAADDR */
+/* Bit fields for USB DOEPCTL */
+
+#define _USB_DOEPCTL_RESETVALUE 0x00000000UL /* Default value for USB_DOEPCTL */
+#define _USB_DOEPCTL_MASK 0xFC3F87FFUL /* Mask for USB_DOEPCTL */
+
+#define _USB_DOEPCTL_MPS_SHIFT 0 /* Shift value for USB_MPS */
+#define _USB_DOEPCTL_MPS_MASK 0x7FFUL /* Bit mask for USB_MPS */
+#define _USB_DOEPCTL_MPS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_MPS_DEFAULT (_USB_DOEPCTL_MPS_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_USBACTEP (0x1UL << 15) /* USB Active Endpoint */
+#define _USB_DOEPCTL_USBACTEP_SHIFT 15 /* Shift value for USB_USBACTEP */
+#define _USB_DOEPCTL_USBACTEP_MASK 0x8000UL /* Bit mask for USB_USBACTEP */
+#define _USB_DOEPCTL_USBACTEP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_USBACTEP_DEFAULT (_USB_DOEPCTL_USBACTEP_DEFAULT << 15) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_DPIDEOF (0x1UL << 16) /* Endpoint Data PID / Even-odd Frame */
+#define _USB_DOEPCTL_DPIDEOF_SHIFT 16 /* Shift value for USB_DPIDEOF */
+#define _USB_DOEPCTL_DPIDEOF_MASK 0x10000UL /* Bit mask for USB_DPIDEOF */
+#define _USB_DOEPCTL_DPIDEOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define _USB_DOEPCTL_DPIDEOF_DATA0EVEN 0x00000000UL /* Mode DATA0EVEN for USB_DOEPCTL */
+#define _USB_DOEPCTL_DPIDEOF_DATA1ODD 0x00000001UL /* Mode DATA1ODD for USB_DOEPCTL */
+#define USB_DOEPCTL_DPIDEOF_DEFAULT (_USB_DOEPCTL_DPIDEOF_DEFAULT << 16) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_DPIDEOF_DATA0EVEN (_USB_DOEPCTL_DPIDEOF_DATA0EVEN << 16) /* Shifted mode DATA0EVEN for USB_DOEPCTL */
+#define USB_DOEPCTL_DPIDEOF_DATA1ODD (_USB_DOEPCTL_DPIDEOF_DATA1ODD << 16) /* Shifted mode DATA1ODD for USB_DOEPCTL */
+#define USB_DOEPCTL_NAKSTS (0x1UL << 17) /* NAK Status */
+#define _USB_DOEPCTL_NAKSTS_SHIFT 17 /* Shift value for USB_NAKSTS */
+#define _USB_DOEPCTL_NAKSTS_MASK 0x20000UL /* Bit mask for USB_NAKSTS */
+#define _USB_DOEPCTL_NAKSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_NAKSTS_DEFAULT (_USB_DOEPCTL_NAKSTS_DEFAULT << 17) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define _USB_DOEPCTL_EPTYPE_SHIFT 18 /* Shift value for USB_EPTYPE */
+#define _USB_DOEPCTL_EPTYPE_MASK 0xC0000UL /* Bit mask for USB_EPTYPE */
+#define _USB_DOEPCTL_EPTYPE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define _USB_DOEPCTL_EPTYPE_CONTROL 0x00000000UL /* Mode CONTROL for USB_DOEPCTL */
+#define _USB_DOEPCTL_EPTYPE_ISO 0x00000001UL /* Mode ISO for USB_DOEPCTL */
+#define _USB_DOEPCTL_EPTYPE_BULK 0x00000002UL /* Mode BULK for USB_DOEPCTL */
+#define _USB_DOEPCTL_EPTYPE_INT 0x00000003UL /* Mode INT for USB_DOEPCTL */
+#define USB_DOEPCTL_EPTYPE_DEFAULT (_USB_DOEPCTL_EPTYPE_DEFAULT << 18) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_EPTYPE_CONTROL (_USB_DOEPCTL_EPTYPE_CONTROL << 18) /* Shifted mode CONTROL for USB_DOEPCTL */
+#define USB_DOEPCTL_EPTYPE_ISO (_USB_DOEPCTL_EPTYPE_ISO << 18) /* Shifted mode ISO for USB_DOEPCTL */
+#define USB_DOEPCTL_EPTYPE_BULK (_USB_DOEPCTL_EPTYPE_BULK << 18) /* Shifted mode BULK for USB_DOEPCTL */
+#define USB_DOEPCTL_EPTYPE_INT (_USB_DOEPCTL_EPTYPE_INT << 18) /* Shifted mode INT for USB_DOEPCTL */
+#define USB_DOEPCTL_SNP (0x1UL << 20) /* Snoop Mode */
+#define _USB_DOEPCTL_SNP_SHIFT 20 /* Shift value for USB_SNP */
+#define _USB_DOEPCTL_SNP_MASK 0x100000UL /* Bit mask for USB_SNP */
+#define _USB_DOEPCTL_SNP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_SNP_DEFAULT (_USB_DOEPCTL_SNP_DEFAULT << 20) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_STALL (0x1UL << 21) /* STALL Handshake */
+#define _USB_DOEPCTL_STALL_SHIFT 21 /* Shift value for USB_STALL */
+#define _USB_DOEPCTL_STALL_MASK 0x200000UL /* Bit mask for USB_STALL */
+#define _USB_DOEPCTL_STALL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_STALL_DEFAULT (_USB_DOEPCTL_STALL_DEFAULT << 21) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_CNAK (0x1UL << 26) /* Clear NAK */
+#define _USB_DOEPCTL_CNAK_SHIFT 26 /* Shift value for USB_CNAK */
+#define _USB_DOEPCTL_CNAK_MASK 0x4000000UL /* Bit mask for USB_CNAK */
+#define _USB_DOEPCTL_CNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_CNAK_DEFAULT (_USB_DOEPCTL_CNAK_DEFAULT << 26) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_SNAK (0x1UL << 27) /* Set NAK */
+#define _USB_DOEPCTL_SNAK_SHIFT 27 /* Shift value for USB_SNAK */
+#define _USB_DOEPCTL_SNAK_MASK 0x8000000UL /* Bit mask for USB_SNAK */
+#define _USB_DOEPCTL_SNAK_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_SNAK_DEFAULT (_USB_DOEPCTL_SNAK_DEFAULT << 27) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_SETD0PIDEF (0x1UL << 28) /* Set DATA0 PID / Even Frame */
+#define _USB_DOEPCTL_SETD0PIDEF_SHIFT 28 /* Shift value for USB_SETD0PIDEF */
+#define _USB_DOEPCTL_SETD0PIDEF_MASK 0x10000000UL /* Bit mask for USB_SETD0PIDEF */
+#define _USB_DOEPCTL_SETD0PIDEF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_SETD0PIDEF_DEFAULT (_USB_DOEPCTL_SETD0PIDEF_DEFAULT << 28) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_SETD1PIDOF (0x1UL << 29) /* Set DATA1 PID / Odd Frame */
+#define _USB_DOEPCTL_SETD1PIDOF_SHIFT 29 /* Shift value for USB_SETD1PIDOF */
+#define _USB_DOEPCTL_SETD1PIDOF_MASK 0x20000000UL /* Bit mask for USB_SETD1PIDOF */
+#define _USB_DOEPCTL_SETD1PIDOF_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_SETD1PIDOF_DEFAULT (_USB_DOEPCTL_SETD1PIDOF_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_EPDIS (0x1UL << 30) /* Endpoint Disable */
+#define _USB_DOEPCTL_EPDIS_SHIFT 30 /* Shift value for USB_EPDIS */
+#define _USB_DOEPCTL_EPDIS_MASK 0x40000000UL /* Bit mask for USB_EPDIS */
+#define _USB_DOEPCTL_EPDIS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_EPDIS_DEFAULT (_USB_DOEPCTL_EPDIS_DEFAULT << 30) /* Shifted mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_EPENA (0x1UL << 31) /* Endpoint Enable */
+#define _USB_DOEPCTL_EPENA_SHIFT 31 /* Shift value for USB_EPENA */
+#define _USB_DOEPCTL_EPENA_MASK 0x80000000UL /* Bit mask for USB_EPENA */
+#define _USB_DOEPCTL_EPENA_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPCTL */
+#define USB_DOEPCTL_EPENA_DEFAULT (_USB_DOEPCTL_EPENA_DEFAULT << 31) /* Shifted mode DEFAULT for USB_DOEPCTL */
+
+/* Bit fields for USB DOEPINT */
+
+#define _USB_DOEPINT_RESETVALUE 0x00000000UL /* Default value for USB_DOEPINT */
+#define _USB_DOEPINT_MASK 0x0000385FUL /* Mask for USB_DOEPINT */
+
+#define USB_DOEPINT_XFERCOMPL (0x1UL << 0) /* Transfer Completed Interrupt */
+#define _USB_DOEPINT_XFERCOMPL_SHIFT 0 /* Shift value for USB_XFERCOMPL */
+#define _USB_DOEPINT_XFERCOMPL_MASK 0x1UL /* Bit mask for USB_XFERCOMPL */
+#define _USB_DOEPINT_XFERCOMPL_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_XFERCOMPL_DEFAULT (_USB_DOEPINT_XFERCOMPL_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_EPDISBLD (0x1UL << 1) /* Endpoint Disabled Interrupt */
+#define _USB_DOEPINT_EPDISBLD_SHIFT 1 /* Shift value for USB_EPDISBLD */
+#define _USB_DOEPINT_EPDISBLD_MASK 0x2UL /* Bit mask for USB_EPDISBLD */
+#define _USB_DOEPINT_EPDISBLD_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_EPDISBLD_DEFAULT (_USB_DOEPINT_EPDISBLD_DEFAULT << 1) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_AHBERR (0x1UL << 2) /* AHB Error */
+#define _USB_DOEPINT_AHBERR_SHIFT 2 /* Shift value for USB_AHBERR */
+#define _USB_DOEPINT_AHBERR_MASK 0x4UL /* Bit mask for USB_AHBERR */
+#define _USB_DOEPINT_AHBERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_AHBERR_DEFAULT (_USB_DOEPINT_AHBERR_DEFAULT << 2) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_SETUP (0x1UL << 3) /* Setup Phase Done */
+#define _USB_DOEPINT_SETUP_SHIFT 3 /* Shift value for USB_SETUP */
+#define _USB_DOEPINT_SETUP_MASK 0x8UL /* Bit mask for USB_SETUP */
+#define _USB_DOEPINT_SETUP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_SETUP_DEFAULT (_USB_DOEPINT_SETUP_DEFAULT << 3) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_OUTTKNEPDIS (0x1UL << 4) /* OUT Token Received When Endpoint Disabled */
+#define _USB_DOEPINT_OUTTKNEPDIS_SHIFT 4 /* Shift value for USB_OUTTKNEPDIS */
+#define _USB_DOEPINT_OUTTKNEPDIS_MASK 0x10UL /* Bit mask for USB_OUTTKNEPDIS */
+#define _USB_DOEPINT_OUTTKNEPDIS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_OUTTKNEPDIS_DEFAULT (_USB_DOEPINT_OUTTKNEPDIS_DEFAULT << 4) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_BACK2BACKSETUP (0x1UL << 6) /* Back-to-Back SETUP Packets Received */
+#define _USB_DOEPINT_BACK2BACKSETUP_SHIFT 6 /* Shift value for USB_BACK2BACKSETUP */
+#define _USB_DOEPINT_BACK2BACKSETUP_MASK 0x40UL /* Bit mask for USB_BACK2BACKSETUP */
+#define _USB_DOEPINT_BACK2BACKSETUP_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_BACK2BACKSETUP_DEFAULT (_USB_DOEPINT_BACK2BACKSETUP_DEFAULT << 6) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_PKTDRPSTS (0x1UL << 11) /* Packet Drop Status */
+#define _USB_DOEPINT_PKTDRPSTS_SHIFT 11 /* Shift value for USB_PKTDRPSTS */
+#define _USB_DOEPINT_PKTDRPSTS_MASK 0x800UL /* Bit mask for USB_PKTDRPSTS */
+#define _USB_DOEPINT_PKTDRPSTS_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_PKTDRPSTS_DEFAULT (_USB_DOEPINT_PKTDRPSTS_DEFAULT << 11) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_BBLEERR (0x1UL << 12) /* Babble Error */
+#define _USB_DOEPINT_BBLEERR_SHIFT 12 /* Shift value for USB_BBLEERR */
+#define _USB_DOEPINT_BBLEERR_MASK 0x1000UL /* Bit mask for USB_BBLEERR */
+#define _USB_DOEPINT_BBLEERR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_BBLEERR_DEFAULT (_USB_DOEPINT_BBLEERR_DEFAULT << 12) /* Shifted mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_NAKINTRPT (0x1UL << 13) /* NAK Interrupt */
+#define _USB_DOEPINT_NAKINTRPT_SHIFT 13 /* Shift value for USB_NAKINTRPT */
+#define _USB_DOEPINT_NAKINTRPT_MASK 0x2000UL /* Bit mask for USB_NAKINTRPT */
+#define _USB_DOEPINT_NAKINTRPT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPINT */
+#define USB_DOEPINT_NAKINTRPT_DEFAULT (_USB_DOEPINT_NAKINTRPT_DEFAULT << 13) /* Shifted mode DEFAULT for USB_DOEPINT */
+
+/* Bit fields for USB DOEPTSIZ */
+
+#define _USB_DOEPTSIZ_RESETVALUE 0x00000000UL /* Default value for USB_DOEPTSIZ */
+#define _USB_DOEPTSIZ_MASK 0x7FFFFFFFUL /* Mask for USB_DOEPTSIZ */
+
+#define _USB_DOEPTSIZ_XFERSIZE_SHIFT 0 /* Shift value for USB_XFERSIZE */
+#define _USB_DOEPTSIZ_XFERSIZE_MASK 0x7FFFFUL /* Bit mask for USB_XFERSIZE */
+#define _USB_DOEPTSIZ_XFERSIZE_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPTSIZ */
+#define USB_DOEPTSIZ_XFERSIZE_DEFAULT (_USB_DOEPTSIZ_XFERSIZE_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEPTSIZ */
+#define _USB_DOEPTSIZ_PKTCNT_SHIFT 19 /* Shift value for USB_PKTCNT */
+#define _USB_DOEPTSIZ_PKTCNT_MASK 0x1FF80000UL /* Bit mask for USB_PKTCNT */
+#define _USB_DOEPTSIZ_PKTCNT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPTSIZ */
+#define USB_DOEPTSIZ_PKTCNT_DEFAULT (_USB_DOEPTSIZ_PKTCNT_DEFAULT << 19) /* Shifted mode DEFAULT for USB_DOEPTSIZ */
+#define _USB_DOEPTSIZ_RXDPIDSUPCNT_SHIFT 29 /* Shift value for USB_RXDPIDSUPCNT */
+#define _USB_DOEPTSIZ_RXDPIDSUPCNT_MASK 0x60000000UL /* Bit mask for USB_RXDPIDSUPCNT */
+#define _USB_DOEPTSIZ_RXDPIDSUPCNT_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPTSIZ */
+#define _USB_DOEPTSIZ_RXDPIDSUPCNT_DATA0 0x00000000UL /* Mode DATA0 for USB_DOEPTSIZ */
+#define _USB_DOEPTSIZ_RXDPIDSUPCNT_DATA2 0x00000001UL /* Mode DATA2 for USB_DOEPTSIZ */
+#define _USB_DOEPTSIZ_RXDPIDSUPCNT_DATA1 0x00000002UL /* Mode DATA1 for USB_DOEPTSIZ */
+#define _USB_DOEPTSIZ_RXDPIDSUPCNT_MDATA 0x00000003UL /* Mode MDATA for USB_DOEPTSIZ */
+#define USB_DOEPTSIZ_RXDPIDSUPCNT_DEFAULT (_USB_DOEPTSIZ_RXDPIDSUPCNT_DEFAULT << 29) /* Shifted mode DEFAULT for USB_DOEPTSIZ */
+#define USB_DOEPTSIZ_RXDPIDSUPCNT_DATA0 (_USB_DOEPTSIZ_RXDPIDSUPCNT_DATA0 << 29) /* Shifted mode DATA0 for USB_DOEPTSIZ */
+#define USB_DOEPTSIZ_RXDPIDSUPCNT_DATA2 (_USB_DOEPTSIZ_RXDPIDSUPCNT_DATA2 << 29) /* Shifted mode DATA2 for USB_DOEPTSIZ */
+#define USB_DOEPTSIZ_RXDPIDSUPCNT_DATA1 (_USB_DOEPTSIZ_RXDPIDSUPCNT_DATA1 << 29) /* Shifted mode DATA1 for USB_DOEPTSIZ */
+#define USB_DOEPTSIZ_RXDPIDSUPCNT_MDATA (_USB_DOEPTSIZ_RXDPIDSUPCNT_MDATA << 29) /* Shifted mode MDATA for USB_DOEPTSIZ */
+
+/* Bit fields for USB DOEPDMAADDR */
+
+#define _USB_DOEPDMAADDR_RESETVALUE 0x00000000UL /* Default value for USB_DOEPDMAADDR */
+#define _USB_DOEPDMAADDR_MASK 0xFFFFFFFFUL /* Mask for USB_DOEPDMAADDR */
+
+#define _USB_DOEPDMAADDR_DMAADDR_SHIFT 0 /* Shift value for USB_DMAADDR */
+#define _USB_DOEPDMAADDR_DMAADDR_MASK 0xFFFFFFFFUL /* Bit mask for USB_DMAADDR */
+#define _USB_DOEPDMAADDR_DMAADDR_DEFAULT 0x00000000UL /* Mode DEFAULT for USB_DOEPDMAADDR */
+#define USB_DOEPDMAADDR_DMAADDR_DEFAULT (_USB_DOEPDMAADDR_DMAADDR_DEFAULT << 0) /* Shifted mode DEFAULT for USB_DOEPDMAADDR */
/* Bit fields for USB PCGCCTL */
diff --git a/nuttx/arch/arm/src/efm32/efm32_usb.h b/nuttx/arch/arm/src/efm32/efm32_usb.h
new file mode 100644
index 000000000..f08fc0ecb
--- /dev/null
+++ b/nuttx/arch/arm/src/efm32/efm32_usb.h
@@ -0,0 +1,126 @@
+/************************************************************************************
+ * arch/arm/src/efm32/efm32_usb.h
+ *
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_EFM32_EFM32_OTGFS_H
+#define __ARCH_ARM_SRC_EFM32_EFM32_OTGFS_H
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#include "chip/efm32_usb.h"
+
+#if defined(CONFIG_EFM32_OTGFS)
+
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+/* Configuration ********************************************************************/
+
+#ifndef CONFIG_OTGFS_PRI
+# define CONFIG_OTGFS_PRI NVIC_SYSH_PRIORITY_DEFAULT
+#endif
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/*******************************************************************************
+ * Name: efm32_otgfshost_initialize
+ *
+ * Description:
+ * Initialize USB host device controller hardware.
+ *
+ * Input Parameters:
+ * controller -- If the device supports more than USB host controller, then
+ * this identifies which controller is being initializeed. Normally, this
+ * is just zero.
+ *
+ * Returned Value:
+ * And instance of the USB host interface. The controlling task should
+ * use this interface to (1) call the wait() method to wait for a device
+ * to be connected, and (2) call the enumerate() method to bind the device
+ * to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ * to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ * Otherwise, there is a race condition if the device is already connected.
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBHOST
+struct usbhost_connection_s;
+FAR struct usbhost_connection_s *efm32_otgfshost_initialize(int controller);
+#endif
+
+/************************************************************************************
+ * Name: efm32_usbsuspend
+ *
+ * Description:
+ * Board logic must provide the efm32_usbsuspend logic if the OTG FS device driver
+ * is used. This function is called whenever the USB enters or leaves suspend
+ * mode. This is an opportunity for the board logic to shutdown clocks, power,
+ * etc. while the USB is suspended.
+ *
+ ************************************************************************************/
+
+void efm32_usbsuspend(FAR struct usbdev_s *dev, bool resume);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_EFM32_OTGFS */
+#endif /* __ARCH_ARM_SRC_EFM32_EFM32_OTGFS_H */
+
diff --git a/nuttx/arch/arm/src/efm32/efm32_usbdev.c b/nuttx/arch/arm/src/efm32/efm32_usbdev.c
new file mode 100644
index 000000000..c1af01ad2
--- /dev/null
+++ b/nuttx/arch/arm/src/efm32/efm32_usbdev.c
@@ -0,0 +1,5701 @@
+/*******************************************************************************
+ * arch/arm/src/efm32/efm32_otgfsdev.c
+ *
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Included Files
+ *******************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/usb/usbdev_trace.h>
+
+#include <arch/irq.h>
+#include <arch/board/board.h>
+
+#include "chip.h"
+#include "up_arch.h"
+#include "up_internal.h"
+
+#include "efm32_usb.h"
+
+#if defined(CONFIG_USBDEV) && (defined(CONFIG_EFM32_OTGFS))
+
+/*******************************************************************************
+ * Preprocessor Definitions
+ *******************************************************************************/
+/* Configuration ***************************************************************/
+
+#ifndef CONFIG_USBDEV_EP0_MAXSIZE
+# define CONFIG_USBDEV_EP0_MAXSIZE 64
+#endif
+
+#ifndef CONFIG_USBDEV_SETUP_MAXDATASIZE
+# define CONFIG_USBDEV_SETUP_MAXDATASIZE CONFIG_USBDEV_EP0_MAXSIZE
+#endif
+
+#ifndef CONFIG_USBDEV_MAXPOWER
+# define CONFIG_USBDEV_MAXPOWER 100 /* mA */
+#endif
+
+/* There is 1.25Kb of FIFO memory. The default partitions this memory
+ * so that there is a TxFIFO allocated for each endpoint and with more
+ * memory provided for the common RxFIFO. A more knowledge-able
+ * configuration would not allocate any TxFIFO space to OUT endpoints.
+ */
+
+#ifndef CONFIG_USBDEV_RXFIFO_SIZE
+# define CONFIG_USBDEV_RXFIFO_SIZE 512
+#endif
+
+#ifndef CONFIG_USBDEV_EP0_TXFIFO_SIZE
+# define CONFIG_USBDEV_EP0_TXFIFO_SIZE 192
+#endif
+
+#ifndef CONFIG_USBDEV_EP1_TXFIFO_SIZE
+# define CONFIG_USBDEV_EP1_TXFIFO_SIZE 192
+#endif
+
+#ifndef CONFIG_USBDEV_EP2_TXFIFO_SIZE
+# define CONFIG_USBDEV_EP2_TXFIFO_SIZE 192
+#endif
+
+#ifndef CONFIG_USBDEV_EP3_TXFIFO_SIZE
+# define CONFIG_USBDEV_EP3_TXFIFO_SIZE 192
+#endif
+
+#if (CONFIG_USBDEV_RXFIFO_SIZE + CONFIG_USBDEV_EP0_TXFIFO_SIZE + \
+ CONFIG_USBDEV_EP2_TXFIFO_SIZE + CONFIG_USBDEV_EP3_TXFIFO_SIZE) > 1280
+# error "FIFO allocations exceed FIFO memory size"
+#endif
+
+/* The actual FIFO addresses that we use must be aligned to 4-byte boundaries;
+ * FIFO sizes must be provided in units of 32-bit words.
+ */
+
+#define EFM32_RXFIFO_BYTES ((CONFIG_USBDEV_RXFIFO_SIZE + 3) & ~3)
+#define EFM32_RXFIFO_WORDS ((CONFIG_USBDEV_RXFIFO_SIZE + 3) >> 2)
+
+#define EFM32_EP0_TXFIFO_BYTES ((CONFIG_USBDEV_EP0_TXFIFO_SIZE + 3) & ~3)
+#define EFM32_EP0_TXFIFO_WORDS ((CONFIG_USBDEV_EP0_TXFIFO_SIZE + 3) >> 2)
+
+#if EFM32_EP0_TXFIFO_WORDS < 16 || EFM32_EP0_TXFIFO_WORDS > 256
+# error "CONFIG_USBDEV_EP0_TXFIFO_SIZE is out of range"
+#endif
+
+#define EFM32_EP1_TXFIFO_BYTES ((CONFIG_USBDEV_EP1_TXFIFO_SIZE + 3) & ~3)
+#define EFM32_EP1_TXFIFO_WORDS ((CONFIG_USBDEV_EP1_TXFIFO_SIZE + 3) >> 2)
+
+#if EFM32_EP1_TXFIFO_WORDS < 16
+# error "CONFIG_USBDEV_EP1_TXFIFO_SIZE is out of range"
+#endif
+
+#define EFM32_EP2_TXFIFO_BYTES ((CONFIG_USBDEV_EP2_TXFIFO_SIZE + 3) & ~3)
+#define EFM32_EP2_TXFIFO_WORDS ((CONFIG_USBDEV_EP2_TXFIFO_SIZE + 3) >> 2)
+
+#if EFM32_EP2_TXFIFO_WORDS < 16
+# error "CONFIG_USBDEV_EP2_TXFIFO_SIZE is out of range"
+#endif
+
+#define EFM32_EP3_TXFIFO_BYTES ((CONFIG_USBDEV_EP3_TXFIFO_SIZE + 3) & ~3)
+#define EFM32_EP3_TXFIFO_WORDS ((CONFIG_USBDEV_EP3_TXFIFO_SIZE + 3) >> 2)
+
+#if EFM32_EP3_TXFIFO_WORDS < 16
+# error "CONFIG_USBDEV_EP3_TXFIFO_SIZE is out of range"
+#endif
+
+/* Debug ***********************************************************************/
+/* Trace error codes */
+
+#define EFM32_TRACEERR_ALLOCFAIL 0x01
+#define EFM32_TRACEERR_BADCLEARFEATURE 0x02
+#define EFM32_TRACEERR_BADDEVGETSTATUS 0x03
+#define EFM32_TRACEERR_BADEPNO 0x04
+#define EFM32_TRACEERR_BADEPGETSTATUS 0x05
+#define EFM32_TRACEERR_BADGETCONFIG 0x06
+#define EFM32_TRACEERR_BADGETSETDESC 0x07
+#define EFM32_TRACEERR_BADGETSTATUS 0x08
+#define EFM32_TRACEERR_BADSETADDRESS 0x09
+#define EFM32_TRACEERR_BADSETCONFIG 0x0a
+#define EFM32_TRACEERR_BADSETFEATURE 0x0b
+#define EFM32_TRACEERR_BADTESTMODE 0x0c
+#define EFM32_TRACEERR_BINDFAILED 0x0d
+#define EFM32_TRACEERR_DISPATCHSTALL 0x0e
+#define EFM32_TRACEERR_DRIVER 0x0f
+#define EFM32_TRACEERR_DRIVERREGISTERED 0x10
+#define EFM32_TRACEERR_EP0NOSETUP 0x11
+#define EFM32_TRACEERR_EP0SETUPSTALLED 0x12
+#define EFM32_TRACEERR_EPINNULLPACKET 0x13
+#define EFM32_TRACEERR_EPINUNEXPECTED 0x14
+#define EFM32_TRACEERR_EPOUTNULLPACKET 0x15
+#define EFM32_TRACEERR_EPOUTUNEXPECTED 0x16
+#define EFM32_TRACEERR_INVALIDCTRLREQ 0x17
+#define EFM32_TRACEERR_INVALIDPARMS 0x18
+#define EFM32_TRACEERR_IRQREGISTRATION 0x19
+#define EFM32_TRACEERR_NOEP 0x1a
+#define EFM32_TRACEERR_NOTCONFIGURED 0x1b
+#define EFM32_TRACEERR_EPOUTQEMPTY 0x1c
+#define EFM32_TRACEERR_EPINREQEMPTY 0x1d
+#define EFM32_TRACEERR_NOOUTSETUP 0x1e
+#define EFM32_TRACEERR_POLLTIMEOUT 0x1f
+
+/* Trace interrupt codes */
+
+#define EFM32_TRACEINTID_USB 1 /* USB Interrupt entry/exit */
+#define EFM32_TRACEINTID_INTPENDING 2 /* On each pass through the loop */
+
+#define EFM32_TRACEINTID_EPOUT (10 + 0) /* First level interrupt decode */
+#define EFM32_TRACEINTID_EPIN (10 + 1)
+#define EFM32_TRACEINTID_MISMATCH (10 + 2)
+#define EFM32_TRACEINTID_WAKEUP (10 + 3)
+#define EFM32_TRACEINTID_SUSPEND (10 + 4)
+#define EFM32_TRACEINTID_SOF (10 + 5)
+#define EFM32_TRACEINTID_RXFIFO (10 + 6)
+#define EFM32_TRACEINTID_DEVRESET (10 + 7)
+#define EFM32_TRACEINTID_ENUMDNE (10 + 8)
+#define EFM32_TRACEINTID_IISOIXFR (10 + 9)
+#define EFM32_TRACEINTID_IISOOXFR (10 + 10)
+#define EFM32_TRACEINTID_SRQ (10 + 11)
+#define EFM32_TRACEINTID_OTG (10 + 12)
+
+#define EFM32_TRACEINTID_EPOUT_XFRC (40 + 0) /* EPOUT second level decode */
+#define EFM32_TRACEINTID_EPOUT_EPDISD (40 + 1)
+#define EFM32_TRACEINTID_EPOUT_SETUP (40 + 2)
+#define EFM32_TRACEINTID_DISPATCH (40 + 3)
+
+#define EFM32_TRACEINTID_GETSTATUS (50 + 0) /* EPOUT third level decode */
+#define EFM32_TRACEINTID_EPGETSTATUS (50 + 1)
+#define EFM32_TRACEINTID_DEVGETSTATUS (50 + 2)
+#define EFM32_TRACEINTID_IFGETSTATUS (50 + 3)
+#define EFM32_TRACEINTID_CLEARFEATURE (50 + 4)
+#define EFM32_TRACEINTID_SETFEATURE (50 + 5)
+#define EFM32_TRACEINTID_SETADDRESS (50 + 6)
+#define EFM32_TRACEINTID_GETSETDESC (50 + 7)
+#define EFM32_TRACEINTID_GETCONFIG (50 + 8)
+#define EFM32_TRACEINTID_SETCONFIG (50 + 9)
+#define EFM32_TRACEINTID_GETSETIF (50 + 10)
+#define EFM32_TRACEINTID_SYNCHFRAME (50 + 11)
+
+#define EFM32_TRACEINTID_EPIN_XFRC (70 + 0) /* EPIN second level decode */
+#define EFM32_TRACEINTID_EPIN_TOC (70 + 1)
+#define EFM32_TRACEINTID_EPIN_ITTXFE (70 + 2)
+#define EFM32_TRACEINTID_EPIN_EPDISD (70 + 3)
+#define EFM32_TRACEINTID_EPIN_TXFE (70 + 4)
+
+#define EFM32_TRACEINTID_EPIN_EMPWAIT (80 + 0) /* EPIN second level decode */
+
+#define EFM32_TRACEINTID_OUTNAK (90 + 0) /* RXFLVL second level decode */
+#define EFM32_TRACEINTID_OUTRECVD (90 + 1)
+#define EFM32_TRACEINTID_OUTDONE (90 + 2)
+#define EFM32_TRACEINTID_SETUPDONE (90 + 3)
+#define EFM32_TRACEINTID_SETUPRECVD (90 + 4)
+
+/* Endpoints ******************************************************************/
+
+/* Number of endpoints */
+
+#define EFM32_NENDPOINTS (4) /* ep0-3 x 2 for IN and OUT */
+
+/* Odd physical endpoint numbers are IN; even are OUT */
+
+#define EFM32_EPPHYIN2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_IN)
+#define EFM32_EPPHYOUT2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_OUT)
+
+/* Endpoint 0 */
+
+#define EP0 (0)
+
+/* The set of all enpoints available to the class implementation (1-3) */
+
+#define EFM32_EP_AVAILABLE (0x0e) /* All available endpoints */
+
+/* Maximum packet sizes for full speed endpoints */
+
+#define EFM32_MAXPACKET (64) /* Max packet size (1-64) */
+
+/* Delays **********************************************************************/
+
+#define EFM32_READY_DELAY 200000
+#define EFM32_FLUSH_DELAY 200000
+
+/* Request queue operations ****************************************************/
+
+#define efm32_rqempty(ep) ((ep)->head == NULL)
+#define efm32_rqpeek(ep) ((ep)->head)
+
+/* Standard stuff **************************************************************/
+
+#ifndef MIN
+# define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+/*******************************************************************************
+ * Private Types
+ *******************************************************************************/
+
+/* Overall device state */
+
+enum efm32_devstate_e
+{
+ DEVSTATE_DEFAULT = 0, /* Power-up, unconfigured state. This state simply
+ * means that the device is not yet been given an
+ * address.
+ * SET: At initialization, uninitialization,
+ * reset, and whenever the device address
+ * is set to zero
+ * TESTED: Never
+ */
+ DEVSTATE_ADDRESSED, /* Device address has been assigned, not no
+ * configuration has yet been selected.
+ * SET: When either a non-zero device address
+ * is first assigned or when the device
+ * is unconfigured (with configuration == 0)
+ * TESTED: never
+ */
+ DEVSTATE_CONFIGURED, /* Address assigned and configured:
+ * SET: When the device has been addressed and
+ * an non-zero configuration has been selected.
+ * TESTED: In many places to assure that the USB device
+ * has been properly configured by the host.
+ */
+};
+
+/* Endpoint 0 states */
+
+enum efm32_ep0state_e
+{
+ EP0STATE_IDLE = 0, /* Idle State, leave on receiving a SETUP packet or
+ * epsubmit:
+ * SET: In efm32_epin() and efm32_epout() when
+ * we revert from request processing to
+ * SETUP processing.
+ * TESTED: Never
+ */
+ EP0STATE_SETUP_OUT, /* OUT SETUP packet received. Waiting for the DATA
+ * OUT phase of SETUP Packet to complete before
+ * processing a SETUP command (without a USB request):
+ * SET: Set in efm32_rxinterrupt() when SETUP OUT
+ * packet is received.
+ * TESTED: In efm32_ep0out_receive()
+ */
+ EP0STATE_SETUP_READY, /* IN SETUP packet received -OR- OUT SETUP packet and
+ * accompanying data have been received. Processing
+ * of SETUP command will happen soon.
+ * SET: (1) efm32_ep0out_receive() when the OUT
+ * SETUP data phase completes, or (2)
+ * efm32_rxinterrupt() when an IN SETUP is
+ * packet received.
+ * TESTED: Tested in efm32_epout_interrupt() when
+ * SETUP phase is done to see if the SETUP
+ * command is ready to be processed. Also
+ * tested in efm32_ep0out_setup() just to
+ * double-check that we have a SETUP request
+ * and any accompanying data.
+ */
+ EP0STATE_SETUP_PROCESS, /* SETUP Packet is being processed by efm32_ep0out_setup():
+ * SET: When SETUP packet received in EP0 OUT
+ * TESTED: Never
+ */
+ EP0STATE_SETUPRESPONSE, /* Short SETUP response write (without a USB request):
+ * SET: When SETUP response is sent by
+ * efm32_ep0in_setupresponse()
+ * TESTED: Never
+ */
+ EP0STATE_DATA_IN, /* Waiting for data out stage (with a USB request):
+ * SET: In efm32_epin_request() when a write
+ * request is processed on EP0.
+ * TESTED: In efm32_epin() to see if we should
+ * revert to SETUP processing.
+ */
+ EP0STATE_DATA_OUT /* Waiting for data in phase to complete ( with a
+ * USB request)
+ * SET: In efm32_epout_request() when a read
+ * request is processed on EP0.
+ * TESTED: In efm32_epout() to see if we should
+ * revert to SETUP processing
+ */
+};
+
+/* Parsed control request */
+
+struct efm32_ctrlreq_s
+{
+ uint8_t type;
+ uint8_t req;
+ uint16_t value;
+ uint16_t index;
+ uint16_t len;
+};
+
+/* A container for a request so that the request may be retained in a list */
+
+struct efm32_req_s
+{
+ struct usbdev_req_s req; /* Standard USB request */
+ struct efm32_req_s *flink; /* Supports a singly linked list */
+};
+
+/* This is the internal representation of an endpoint */
+
+struct efm32_ep_s
+{
+ /* Common endpoint fields. This must be the first thing defined in the
+ * structure so that it is possible to simply cast from struct usbdev_ep_s
+ * to struct efm32_ep_s.
+ */
+
+ struct usbdev_ep_s ep; /* Standard endpoint structure */
+
+ /* EFM32-specific fields */
+
+ struct efm32_usbdev_s *dev; /* Reference to private driver data */
+ struct efm32_req_s *head; /* Request list for this endpoint */
+ struct efm32_req_s *tail;
+ uint8_t epphy; /* Physical EP address */
+ uint8_t eptype:2; /* Endpoint type */
+ uint8_t active:1; /* 1: A request is being processed */
+ uint8_t stalled:1; /* 1: Endpoint is stalled */
+ uint8_t isin:1; /* 1: IN Endpoint */
+ uint8_t odd:1; /* 1: Odd frame */
+ uint8_t zlp:1; /* 1: Transmit a zero-length-packet (IN EPs only) */
+};
+
+/* This structure retains the state of the USB device controller */
+
+struct efm32_usbdev_s
+{
+ /* Common device fields. This must be the first thing defined in the
+ * structure so that it is possible to simply cast from struct usbdev_s
+ * to struct efm32_usbdev_s.
+ */
+
+ struct usbdev_s usbdev;
+
+ /* The bound device class driver */
+
+ struct usbdevclass_driver_s *driver;
+
+ /* EFM32-specific fields */
+
+ uint8_t stalled:1; /* 1: Protocol stalled */
+ uint8_t selfpowered:1; /* 1: Device is self powered */
+ uint8_t addressed:1; /* 1: Peripheral address has been set */
+ uint8_t configured:1; /* 1: Class driver has been configured */
+ uint8_t wakeup:1; /* 1: Device remote wake-up */
+ uint8_t dotest:1; /* 1: Test mode selected */
+
+ uint8_t devstate:4; /* See enum efm32_devstate_e */
+ uint8_t ep0state:4; /* See enum efm32_ep0state_e */
+ uint8_t testmode:4; /* Selected test mode */
+ uint8_t epavail[2]; /* Bitset of available OUT/IN endpoints */
+
+ /* E0 SETUP data buffering.
+ *
+ * ctrlreq:
+ * The 8-byte SETUP request is received on the EP0 OUT endpoint and is
+ * saved.
+ *
+ * ep0data
+ * For OUT SETUP requests, the SETUP data phase must also complete before
+ * the SETUP command can be processed. The pack receipt logic will save
+ * the accompanying EP0 IN data in ep0data[] before the SETUP command is
+ * processed.
+ *
+ * For IN SETUP requests, the DATA phase will occurr AFTER the SETUP
+ * control request is processed. In that case, ep0data[] may be used as
+ * the response buffer.
+ *
+ * ep0datlen
+ * Lenght of OUT DATA received in ep0data[] (Not used with OUT data)
+ */
+
+ struct usb_ctrlreq_s ctrlreq;
+ uint8_t ep0data[CONFIG_USBDEV_SETUP_MAXDATASIZE];
+ uint16_t ep0datlen;
+
+ /* The endpoint lists */
+
+ struct efm32_ep_s epin[EFM32_NENDPOINTS];
+ struct efm32_ep_s epout[EFM32_NENDPOINTS];
+};
+
+/*******************************************************************************
+ * Private Function Prototypes
+ *******************************************************************************/
+
+/* Register operations ********************************************************/
+
+#if defined(CONFIG_EFM32_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
+static uint32_t efm32_getreg(uint32_t addr);
+static void efm32_putreg(uint32_t val, uint32_t addr);
+#else
+# define efm32_getreg(addr) getreg32(addr)
+# define efm32_putreg(val,addr) putreg32(val,addr)
+#endif
+
+/* Request queue operations ****************************************************/
+
+static FAR struct efm32_req_s *efm32_req_remfirst(FAR struct efm32_ep_s *privep);
+static bool efm32_req_addlast(FAR struct efm32_ep_s *privep,
+ FAR struct efm32_req_s *req);
+
+/* Low level data transfers and request operations *****************************/
+/* Special endpoint 0 data transfer logic */
+
+static void efm32_ep0in_setupresponse(FAR struct efm32_usbdev_s *priv,
+ FAR uint8_t *data, uint32_t nbytes);
+static inline void efm32_ep0in_transmitzlp(FAR struct efm32_usbdev_s *priv);
+static void efm32_ep0in_activate(void);
+
+static void efm32_ep0out_ctrlsetup(FAR struct efm32_usbdev_s *priv);
+
+/* IN request and TxFIFO handling */
+
+static void efm32_txfifo_write(FAR struct efm32_ep_s *privep,
+ FAR uint8_t *buf, int nbytes);
+static void efm32_epin_transfer(FAR struct efm32_ep_s *privep,
+ FAR uint8_t *buf, int nbytes);
+static void efm32_epin_request(FAR struct efm32_usbdev_s *priv,
+ FAR struct efm32_ep_s *privep);
+
+/* OUT request and RxFIFO handling */
+
+static void efm32_rxfifo_read(FAR struct efm32_ep_s *privep,
+ FAR uint8_t *dest, uint16_t len);
+static void efm32_rxfifo_discard(FAR struct efm32_ep_s *privep, int len);
+static void efm32_epout_complete(FAR struct efm32_usbdev_s *priv,
+ FAR struct efm32_ep_s *privep);
+static inline void efm32_ep0out_receive(FAR struct efm32_ep_s *privep, int bcnt);
+static inline void efm32_epout_receive(FAR struct efm32_ep_s *privep, int bcnt);
+static void efm32_epout_request(FAR struct efm32_usbdev_s *priv,
+ FAR struct efm32_ep_s *privep);
+
+/* General request handling */
+
+static void efm32_ep_flush(FAR struct efm32_ep_s *privep);
+static void efm32_req_complete(FAR struct efm32_ep_s *privep,
+ int16_t result);
+static void efm32_req_cancel(FAR struct efm32_ep_s *privep,
+ int16_t status);
+
+/* Interrupt handling **********************************************************/
+
+static struct efm32_ep_s *efm32_ep_findbyaddr(struct efm32_usbdev_s *priv,
+ uint16_t eplog);
+static int efm32_req_dispatch(FAR struct efm32_usbdev_s *priv,
+ FAR const struct usb_ctrlreq_s *ctrl);
+static void efm32_usbreset(FAR struct efm32_usbdev_s *priv);
+
+/* Second level OUT endpoint interrupt processing */
+
+static inline void efm32_ep0out_testmode(FAR struct efm32_usbdev_s *priv,
+ uint16_t index);
+static inline void efm32_ep0out_stdrequest(struct efm32_usbdev_s *priv,
+ FAR struct efm32_ctrlreq_s *ctrlreq);
+static inline void efm32_ep0out_setup(struct efm32_usbdev_s *priv);
+static inline void efm32_epout(FAR struct efm32_usbdev_s *priv,
+ uint8_t epno);
+static inline void efm32_epout_interrupt(FAR struct efm32_usbdev_s *priv);
+
+/* Second level IN endpoint interrupt processing */
+
+static inline void efm32_epin_runtestmode(FAR struct efm32_usbdev_s *priv);
+static inline void efm32_epin(FAR struct efm32_usbdev_s *priv, uint8_t epno);
+static inline void efm32_epin_txfifoempty(FAR struct efm32_usbdev_s *priv, int epno);
+static inline void efm32_epin_interrupt(FAR struct efm32_usbdev_s *priv);
+
+/* Other second level interrupt processing */
+
+static inline void efm32_resumeinterrupt(FAR struct efm32_usbdev_s *priv);
+static inline void efm32_suspendinterrupt(FAR struct efm32_usbdev_s *priv);
+static inline void efm32_rxinterrupt(FAR struct efm32_usbdev_s *priv);
+static inline void efm32_enuminterrupt(FAR struct efm32_usbdev_s *priv);
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+static inline void efm32_isocininterrupt(FAR struct efm32_usbdev_s *priv);
+static inline void efm32_isocoutinterrupt(FAR struct efm32_usbdev_s *priv);
+#endif
+#ifdef CONFIG_USBDEV_VBUSSENSING
+static inline void efm32_sessioninterrupt(FAR struct efm32_usbdev_s *priv);
+static inline void efm32_otginterrupt(FAR struct efm32_usbdev_s *priv);
+#endif
+
+/* First level interrupt processing */
+
+static int efm32_usbinterrupt(int irq, FAR void *context);
+
+/* Endpoint operations *********************************************************/
+/* Global OUT NAK controls */
+
+static void efm32_enablegonak(FAR struct efm32_ep_s *privep);
+static void efm32_disablegonak(FAR struct efm32_ep_s *privep);
+
+/* Endpoint configuration */
+
+static int efm32_epout_configure(FAR struct efm32_ep_s *privep,
+ uint8_t eptype, uint16_t maxpacket);
+static int efm32_epin_configure(FAR struct efm32_ep_s *privep,
+ uint8_t eptype, uint16_t maxpacket);
+static int efm32_ep_configure(FAR struct usbdev_ep_s *ep,
+ FAR const struct usb_epdesc_s *desc, bool last);
+static void efm32_ep0_configure(FAR struct efm32_usbdev_s *priv);
+
+/* Endpoint disable */
+
+static void efm32_epout_disable(FAR struct efm32_ep_s *privep);
+static void efm32_epin_disable(FAR struct efm32_ep_s *privep);
+static int efm32_ep_disable(FAR struct usbdev_ep_s *ep);
+
+/* Endpoint request management */
+
+static FAR struct usbdev_req_s *efm32_ep_allocreq(FAR struct usbdev_ep_s *ep);
+static void efm32_ep_freereq(FAR struct usbdev_ep_s *ep,
+ FAR struct usbdev_req_s *);
+
+/* Endpoint buffer management */
+
+#ifdef CONFIG_USBDEV_DMA
+static void *efm32_ep_allocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes);
+static void efm32_ep_freebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf);
+#endif
+
+/* Endpoint request submission */
+
+static int efm32_ep_submit(FAR struct usbdev_ep_s *ep,
+ struct usbdev_req_s *req);
+
+/* Endpoint request cancellation */
+
+static int efm32_ep_cancel(FAR struct usbdev_ep_s *ep,
+ struct usbdev_req_s *req);
+
+/* Stall handling */
+
+static int efm32_epout_setstall(FAR struct efm32_ep_s *privep);
+static int efm32_epin_setstall(FAR struct efm32_ep_s *privep);
+static int efm32_ep_setstall(FAR struct efm32_ep_s *privep);
+static int efm32_ep_clrstall(FAR struct efm32_ep_s *privep);
+static int efm32_ep_stall(FAR struct usbdev_ep_s *ep, bool resume);
+static void efm32_ep0_stall(FAR struct efm32_usbdev_s *priv);
+
+/* Endpoint allocation */
+
+static FAR struct usbdev_ep_s *efm32_ep_alloc(FAR struct usbdev_s *dev,
+ uint8_t epno, bool in, uint8_t eptype);
+static void efm32_ep_free(FAR struct usbdev_s *dev,
+ FAR struct usbdev_ep_s *ep);
+
+/* USB device controller operations ********************************************/
+
+static int efm32_getframe(struct usbdev_s *dev);
+static int efm32_wakeup(struct usbdev_s *dev);
+static int efm32_selfpowered(struct usbdev_s *dev, bool selfpowered);
+static int efm32_pullup(struct usbdev_s *dev, bool enable);
+static void efm32_setaddress(struct efm32_usbdev_s *priv,
+ uint16_t address);
+static int efm32_txfifo_flush(uint32_t txfnum);
+static int efm32_rxfifo_flush(void);
+
+/* Initialization **************************************************************/
+
+static void efm32_swinitialize(FAR struct efm32_usbdev_s *priv);
+static void efm32_hwinitialize(FAR struct efm32_usbdev_s *priv);
+
+/*******************************************************************************
+ * Private Data
+ *******************************************************************************/
+/* Since there is only a single USB interface, all status information can be
+ * be simply retained in a single global instance.
+ */
+
+static struct efm32_usbdev_s g_otgfsdev;
+
+static const struct usbdev_epops_s g_epops =
+{
+ .configure = efm32_ep_configure,
+ .disable = efm32_ep_disable,
+ .allocreq = efm32_ep_allocreq,
+ .freereq = efm32_ep_freereq,
+#ifdef CONFIG_USBDEV_DMA
+ .allocbuffer = efm32_ep_allocbuffer,
+ .freebuffer = efm32_ep_freebuffer,
+#endif
+ .submit = efm32_ep_submit,
+ .cancel = efm32_ep_cancel,
+ .stall = efm32_ep_stall,
+};
+
+static const struct usbdev_ops_s g_devops =
+{
+ .allocep = efm32_ep_alloc,
+ .freeep = efm32_ep_free,
+ .getframe = efm32_getframe,
+ .wakeup = efm32_wakeup,
+ .selfpowered = efm32_selfpowered,
+ .pullup = efm32_pullup,
+};
+
+/* Device error strings that may be enabled for more desciptive USB trace
+ * output.
+ */
+
+#ifdef CONFIG_USBDEV_TRACE_STRINGS
+const struct trace_msg_t g_usb_trace_strings_deverror[] =
+{
+ TRACE_STR(EFM32_TRACEERR_ALLOCFAIL ),
+ TRACE_STR(EFM32_TRACEERR_BADCLEARFEATURE ),
+ TRACE_STR(EFM32_TRACEERR_BADDEVGETSTATUS ),
+ TRACE_STR(EFM32_TRACEERR_BADEPNO ),
+ TRACE_STR(EFM32_TRACEERR_BADEPGETSTATUS ),
+ TRACE_STR(EFM32_TRACEERR_BADGETCONFIG ),
+ TRACE_STR(EFM32_TRACEERR_BADGETSETDESC ),
+ TRACE_STR(EFM32_TRACEERR_BADGETSTATUS ),
+ TRACE_STR(EFM32_TRACEERR_BADSETADDRESS ),
+ TRACE_STR(EFM32_TRACEERR_BADSETCONFIG ),
+ TRACE_STR(EFM32_TRACEERR_BADSETFEATURE ),
+ TRACE_STR(EFM32_TRACEERR_BADTESTMODE ),
+ TRACE_STR(EFM32_TRACEERR_BINDFAILED ),
+ TRACE_STR(EFM32_TRACEERR_DISPATCHSTALL ),
+ TRACE_STR(EFM32_TRACEERR_DRIVER ),
+ TRACE_STR(EFM32_TRACEERR_DRIVERREGISTERED),
+ TRACE_STR(EFM32_TRACEERR_EP0NOSETUP ),
+ TRACE_STR(EFM32_TRACEERR_EP0SETUPSTALLED ),
+ TRACE_STR(EFM32_TRACEERR_EPINNULLPACKET ),
+ TRACE_STR(EFM32_TRACEERR_EPINUNEXPECTED ),
+ TRACE_STR(EFM32_TRACEERR_EPOUTNULLPACKET ),
+ TRACE_STR(EFM32_TRACEERR_EPOUTUNEXPECTED ),
+ TRACE_STR(EFM32_TRACEERR_INVALIDCTRLREQ ),
+ TRACE_STR(EFM32_TRACEERR_INVALIDPARMS ),
+ TRACE_STR(EFM32_TRACEERR_IRQREGISTRATION ),
+ TRACE_STR(EFM32_TRACEERR_NOEP ),
+ TRACE_STR(EFM32_TRACEERR_NOTCONFIGURED ),
+ TRACE_STR(EFM32_TRACEERR_EPOUTQEMPTY ),
+ TRACE_STR(EFM32_TRACEERR_EPINREQEMPTY ),
+ TRACE_STR(EFM32_TRACEERR_NOOUTSETUP ),
+ TRACE_STR(EFM32_TRACEERR_POLLTIMEOUT ),
+ TRACE_STR_END
+};
+#endif
+
+/* Interrupt event strings that may be enabled for more desciptive USB trace
+ * output.
+ */
+
+#ifdef CONFIG_USBDEV_TRACE_STRINGS
+const struct trace_msg_t g_usb_trace_strings_intdecode[] =
+{
+ TRACE_STR(EFM32_TRACEINTID_USB ),
+ TRACE_STR(EFM32_TRACEINTID_INTPENDING ),
+ TRACE_STR(EFM32_TRACEINTID_EPOUT ),
+ TRACE_STR(EFM32_TRACEINTID_EPIN ),
+ TRACE_STR(EFM32_TRACEINTID_MISMATCH ),
+ TRACE_STR(EFM32_TRACEINTID_WAKEUP ),
+ TRACE_STR(EFM32_TRACEINTID_SUSPEND ),
+ TRACE_STR(EFM32_TRACEINTID_SOF ),
+ TRACE_STR(EFM32_TRACEINTID_RXFIFO ),
+ TRACE_STR(EFM32_TRACEINTID_DEVRESET ),
+ TRACE_STR(EFM32_TRACEINTID_ENUMDNE ),
+ TRACE_STR(EFM32_TRACEINTID_IISOIXFR ),
+ TRACE_STR(EFM32_TRACEINTID_IISOOXFR ),
+ TRACE_STR(EFM32_TRACEINTID_SRQ ),
+ TRACE_STR(EFM32_TRACEINTID_OTG ),
+ TRACE_STR(EFM32_TRACEINTID_EPOUT_XFRC ),
+ TRACE_STR(EFM32_TRACEINTID_EPOUT_EPDISD),
+ TRACE_STR(EFM32_TRACEINTID_EPOUT_SETUP ),
+ TRACE_STR(EFM32_TRACEINTID_DISPATCH ),
+ TRACE_STR(EFM32_TRACEINTID_GETSTATUS ),
+ TRACE_STR(EFM32_TRACEINTID_EPGETSTATUS ),
+ TRACE_STR(EFM32_TRACEINTID_DEVGETSTATUS),
+ TRACE_STR(EFM32_TRACEINTID_IFGETSTATUS ),
+ TRACE_STR(EFM32_TRACEINTID_CLEARFEATURE),
+ TRACE_STR(EFM32_TRACEINTID_SETFEATURE ),
+ TRACE_STR(EFM32_TRACEINTID_SETADDRESS ),
+ TRACE_STR(EFM32_TRACEINTID_GETSETDESC ),
+ TRACE_STR(EFM32_TRACEINTID_GETCONFIG ),
+ TRACE_STR(EFM32_TRACEINTID_SETCONFIG ),
+ TRACE_STR(EFM32_TRACEINTID_GETSETIF ),
+ TRACE_STR(EFM32_TRACEINTID_SYNCHFRAME ),
+ TRACE_STR(EFM32_TRACEINTID_EPIN_XFRC ),
+ TRACE_STR(EFM32_TRACEINTID_EPIN_TOC ),
+ TRACE_STR(EFM32_TRACEINTID_EPIN_ITTXFE ),
+ TRACE_STR(EFM32_TRACEINTID_EPIN_EPDISD ),
+ TRACE_STR(EFM32_TRACEINTID_EPIN_TXFE ),
+ TRACE_STR(EFM32_TRACEINTID_EPIN_EMPWAIT),
+ TRACE_STR(EFM32_TRACEINTID_OUTNAK ),
+ TRACE_STR(EFM32_TRACEINTID_OUTRECVD ),
+ TRACE_STR(EFM32_TRACEINTID_OUTDONE ),
+ TRACE_STR(EFM32_TRACEINTID_SETUPDONE ),
+ TRACE_STR(EFM32_TRACEINTID_SETUPRECVD ),
+ TRACE_STR_END
+};
+#endif
+
+/*******************************************************************************
+ * Public Data
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Private Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: efm32_getreg
+ *
+ * Description:
+ * Get the contents of an EFM32 register
+ *
+ *******************************************************************************/
+
+#if defined(CONFIG_EFM32_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
+static uint32_t efm32_getreg(uint32_t addr)
+{
+ static uint32_t prevaddr = 0;
+ static uint32_t preval = 0;
+ static uint32_t count = 0;
+
+ /* Read the value from the register */
+
+ uint32_t val = getreg32(addr);
+
+ /* Is this the same value that we read from the same registe last time? Are
+ * we polling the register? If so, suppress some of the output.
+ */
+
+ if (addr == prevaddr && val == preval)
+ {
+ if (count == 0xffffffff || ++count > 3)
+ {
+ if (count == 4)
+ {
+ lldbg("...\n");
+ }
+ return val;
+ }
+ }
+
+ /* No this is a new address or value */
+
+ else
+ {
+ /* Did we print "..." for the previous value? */
+
+ if (count > 3)
+ {
+ /* Yes.. then show how many times the value repeated */
+
+ lldbg("[repeats %d more times]\n", count-3);
+ }
+
+ /* Save the new address, value, and count */
+
+ prevaddr = addr;
+ preval = val;
+ count = 1;
+ }
+
+ /* Show the register value read */
+
+ lldbg("%08x->%08x\n", addr, val);
+ return val;
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_putreg
+ *
+ * Description:
+ * Set the contents of an EFM32 register to a value
+ *
+ *******************************************************************************/
+
+#if defined(CONFIG_EFM32_USBDEV_REGDEBUG) && defined(CONFIG_DEBUG)
+static void efm32_putreg(uint32_t val, uint32_t addr)
+{
+ /* Show the register value being written */
+
+ lldbg("%08x<-%08x\n", addr, val);
+
+ /* Write the value */
+
+ putreg32(val, addr);
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_req_remfirst
+ *
+ * Description:
+ * Remove a request from the head of an endpoint request queue
+ *
+ *******************************************************************************/
+
+static FAR struct efm32_req_s *efm32_req_remfirst(FAR struct efm32_ep_s *privep)
+{
+ FAR struct efm32_req_s *ret = privep->head;
+
+ if (ret)
+ {
+ privep->head = ret->flink;
+ if (!privep->head)
+ {
+ privep->tail = NULL;
+ }
+
+ ret->flink = NULL;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_req_addlast
+ *
+ * Description:
+ * Add a request to the end of an endpoint request queue
+ *
+ *******************************************************************************/
+
+static bool efm32_req_addlast(FAR struct efm32_ep_s *privep,
+ FAR struct efm32_req_s *req)
+{
+ bool is_empty = !privep->head;
+
+ req->flink = NULL;
+ if (is_empty)
+ {
+ privep->head = req;
+ privep->tail = req;
+ }
+ else
+ {
+ privep->tail->flink = req;
+ privep->tail = req;
+ }
+ return is_empty;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0in_setupresponse
+ *
+ * Description:
+ * Schedule a short transfer on Endpoint 0 (IN or OUT)
+ *
+ *******************************************************************************/
+
+static void efm32_ep0in_setupresponse(FAR struct efm32_usbdev_s *priv,
+ FAR uint8_t *buf, uint32_t nbytes)
+{
+ efm32_epin_transfer(&priv->epin[EP0], buf, nbytes);
+ priv->ep0state = EP0STATE_SETUPRESPONSE;
+ efm32_ep0out_ctrlsetup(priv);
+}
+
+/****************************************************************************
+ * Name: efm32_ep0in_transmitzlp
+ *
+ * Description:
+ * Send a zero length packet (ZLP) on endpoint 0 IN
+ *
+ ****************************************************************************/
+
+static inline void efm32_ep0in_transmitzlp(FAR struct efm32_usbdev_s *priv)
+{
+ efm32_ep0in_setupresponse(priv, NULL, 0);
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0in_activate
+ *
+ * Description:
+ * Activate the endpoint 0 IN endpoint.
+ *
+ *******************************************************************************/
+
+static void efm32_ep0in_activate(void)
+{
+ uint32_t regval;
+
+ /* Set the max packet size of the IN EP. */
+
+ regval = efm32_getreg(EFM32_USB_DIEP0CTL);
+ regval &= ~_USB_DIEP0CTL_MPS_MASK;
+
+#if CONFIG_USBDEV_EP0_MAXSIZE == 8
+ regval |= _USB_DIEP0CTL_MPS_8B;
+#elif CONFIG_USBDEV_EP0_MAXSIZE == 16
+ regval |= _USB_DIEP0CTL_MPS_16B;
+#elif CONFIG_USBDEV_EP0_MAXSIZE == 32
+ regval |= _USB_DIEP0CTL_MPS_32B;
+#elif CONFIG_USBDEV_EP0_MAXSIZE == 64
+ regval |= _USB_DIEP0CTL_MPS_64B;
+#else
+# error "Unsupported value of CONFIG_USBDEV_EP0_MAXSIZE"
+#endif
+
+ efm32_putreg(regval, EFM32_USB_DIEP0CTL);
+
+ /* Clear global IN NAK */
+
+ regval = efm32_getreg(EFM32_USB_DCTL);
+ regval |= USB_DCTL_CGINAK;
+ efm32_putreg(regval, EFM32_USB_DCTL);
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0out_ctrlsetup
+ *
+ * Description:
+ * Setup to receive a SETUP packet.
+ *
+ *******************************************************************************/
+
+static void efm32_ep0out_ctrlsetup(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t regval;
+
+ /* Setup the hardware to perform the SETUP transfer */
+
+ regval = (USB_SIZEOF_CTRLREQ * 3 << _USB_DOEP0TSIZ_XFERSIZE_SHIFT) |
+ (USB_DOEP0TSIZ_PKTCNT) |
+ (3 << _USB_DOEP0TSIZ_SUPCNT_SHIFT);
+ efm32_putreg(regval,EFM32_USB_DOEP0TSIZ);
+
+ /* Then clear NAKing and enable the transfer */
+
+ regval = efm32_getreg(EFM32_USB_DOEP0CTL);
+ regval |= (USB_DOEP0CTL_CNAK | USB_DOEP0CTL_EPENA);
+ efm32_putreg(regval, EFM32_USB_DOEP0CTL);
+}
+
+/****************************************************************************
+ * Name: efm32_txfifo_write
+ *
+ * Description:
+ * Send data to the endpoint's TxFIFO.
+ *
+ ****************************************************************************/
+
+static void efm32_txfifo_write(FAR struct efm32_ep_s *privep,
+ FAR uint8_t *buf, int nbytes)
+{
+ uint32_t regaddr;
+ uint32_t regval;
+ int nwords;
+ int i;
+
+ /* Convert the number of bytes to words */
+
+ nwords = (nbytes + 3) >> 2;
+
+ /* Get the TxFIFO for this endpoint (same as the endpoint number) */
+
+ regaddr = EFM32_USB_DFIFO_DEP(privep->epphy);
+
+ /* Then transfer each word to the TxFIFO */
+
+ for (i = 0; i < nwords; i++)
+ {
+ /* Read four bytes from the source buffer (to avoid unaligned accesses)
+ * and pack these into one 32-bit word (little endian).
+ */
+
+ regval = (uint32_t)*buf++;
+ regval |= ((uint32_t)*buf++) << 8;
+ regval |= ((uint32_t)*buf++) << 16;
+ regval |= ((uint32_t)*buf++) << 24;
+
+ /* Then write the packet data to the TxFIFO */
+
+ efm32_putreg(regval, regaddr);
+ }
+}
+
+/****************************************************************************
+ * Name: efm32_epin_transfer
+ *
+ * Description:
+ * Start the Tx data transfer
+ *
+ ****************************************************************************/
+
+static void efm32_epin_transfer(FAR struct efm32_ep_s *privep,
+ FAR uint8_t *buf, int nbytes)
+{
+ uint32_t pktcnt;
+ uint32_t regval;
+
+ /* Read the DIEPSIZx register */
+
+ regval = efm32_getreg(EFM32_USB_DIEPTSIZ(privep->epphy));
+
+ /* Clear the XFERSIZE, PKTCNT, and MCNT field of the DIEPSIZx register */
+
+ regval &= ~(_USB_DIEPTSIZ_XFERSIZE_MASK | _USB_DIEPTSIZ_PKTCNT_MASK |
+ _USB_DIEPTSIZ_MCNT_MASK);
+
+ /* Are we sending a zero length packet (ZLP) */
+
+ if (nbytes == 0)
+ {
+ /* Yes.. leave the transfer size at zero and set the packet count to 1 */
+
+ pktcnt = 1;
+ }
+ else
+ {
+ /* No.. Program the transfer size and packet count . First calculate:
+ *
+ * xfrsize = The total number of bytes to be sent.
+ * pktcnt = the number of packets (of maxpacket bytes) required to
+ * perform the transfer.
+ */
+
+ pktcnt = ((uint32_t)nbytes + (privep->ep.maxpacket - 1)) / privep->ep.maxpacket;
+ }
+
+ /* Set the XFERSIZE and PKTCNT */
+
+ regval |= (pktcnt << _USB_DIEPTSIZ_PKTCNT_SHIFT);
+ regval |= ((uint32_t)nbytes << _USB_DIEPTSIZ_XFERSIZE_SHIFT);
+
+ /* If this is an isconchronous endpoint, then set the multi-count field to
+ * the PKTCNT as well.
+ */
+
+ if (privep->eptype == USB_EP_ATTR_XFER_ISOC)
+ {
+ regval |= (pktcnt << _USB_DIEPTSIZ_MCNT_SHIFT);
+ }
+
+ /* Save DIEPSIZx register value */
+
+ efm32_putreg(regval, EFM32_USB_DIEPTSIZ(privep->epphy));
+
+ /* Read the DIEPCTLx register */
+
+ regval = efm32_getreg(EFM32_USB_DIEPCTL(privep->epphy));
+
+ /* If this is an isochronous endpoint, then set the even/odd frame bit
+ * the DIEPCTLx register.
+ */
+
+ if (privep->eptype == USB_EP_ATTR_XFER_ISOC)
+ {
+ /* Check bit 0 of the frame number of the received SOF and set the
+ * even/odd frame to match.
+ */
+
+ uint32_t status = efm32_getreg(EFM32_USB_DSTS);
+ if ((status & USB_DSTS_SOFFN0) == USB_DSTS_SOFFN_EVEN)
+ {
+ regval |= USB_DIEPCTL_SEVNFRM;
+ }
+ else
+ {
+ regval |= USB_DIEPCTL_SODDFRM;
+ }
+ }
+
+ /* EP enable, IN data in FIFO */
+
+ regval &= ~USB_DIEPCTL_EPDIS;
+ regval |= (USB_DIEPCTL_CNAK | USB_DIEPCTL_EPENA);
+ efm32_putreg(regval, EFM32_USB_DIEPCTL(privep->epphy));
+
+ /* Transfer the data to the TxFIFO. At this point, the caller has already
+ * assured that there is sufficient space in the TxFIFO to hold the transfer
+ * we can just blindly continue.
+ */
+
+ efm32_txfifo_write(privep, buf, nbytes);
+}
+
+/****************************************************************************
+ * Name: efm32_epin_request
+ *
+ * Description:
+ * Begin or continue write request processing.
+ *
+ ****************************************************************************/
+
+static void efm32_epin_request(FAR struct efm32_usbdev_s *priv,
+ FAR struct efm32_ep_s *privep)
+{
+ struct efm32_req_s *privreq;
+ uint32_t regaddr;
+ uint32_t regval;
+ uint8_t *buf;
+ int nbytes;
+ int nwords;
+ int bytesleft;
+
+ /* We get here in one of four possible ways. From three interrupting
+ * events:
+ *
+ * 1. From efm32_epin as part of the transfer complete interrupt processing
+ * This interrupt indicates that the last transfer has completed.
+ * 2. As part of the ITTXFE interrupt processing. That interrupt indicates
+ * that an IN token was received when the associated TxFIFO was empty.
+ * 3. From efm32_epin_txfifoempty as part of the TXFE interrupt processing.
+ * The TXFE interrupt is only enabled when the TxFIFO is full and the
+ * software must wait for space to become available in the TxFIFO.
+ *
+ * And this function may be called immediately when the write request is
+ * queue to start up the next transaction.
+ *
+ * 4. From efm32_ep_submit when a new write request is received WHILE the
+ * endpoint is not active (privep->active == false).
+ */
+
+ /* Check the request from the head of the endpoint request queue */
+
+ privreq = efm32_rqpeek(privep);
+ if (!privreq)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EPINREQEMPTY), privep->epphy);
+
+ /* There is no TX transfer in progress and no new pending TX
+ * requests to send. To stop transmitting any data on a particular
+ * IN endpoint, the application must set the IN NAK bit. To set this
+ * bit, the following field must be programmed.
+ */
+
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval |= USB_DIEPCTL_SNAK;
+ efm32_putreg(regval, regaddr);
+
+ /* The endpoint is no longer active */
+
+ privep->active = false;
+ return;
+ }
+
+ ullvdbg("EP%d req=%p: len=%d xfrd=%d zlp=%d\n",
+ privep->epphy, privreq, privreq->req.len,
+ privreq->req.xfrd, privep->zlp);
+
+ /* Check for a special case: If we are just starting a request (xfrd==0) and
+ * the class driver is trying to send a zero-length packet (len==0). Then set
+ * the ZLP flag so that the packet will be sent.
+ */
+
+ if (privreq->req.len == 0)
+ {
+ /* The ZLP flag is set TRUE whenever we want to force the driver to
+ * send a zero-length-packet on the next pass through the loop (below).
+ * The flag is cleared whenever a packet is sent in the loop below.
+ */
+
+ privep->zlp = true;
+ }
+
+ /* Add one more packet to the TxFIFO. We will wait for the transfer
+ * complete event before we add the next packet (or part of a packet
+ * to the TxFIFO).
+ *
+ * The documentation says that we can can multiple packets to the TxFIFO,
+ * but it seems that we need to get the transfer complete event before
+ * we can add the next (or maybe I have got something wrong?)
+ */
+
+#if 0
+ while (privreq->req.xfrd < privreq->req.len || privep->zlp)
+#else
+ if (privreq->req.xfrd < privreq->req.len || privep->zlp)
+#endif
+ {
+ /* Get the number of bytes left to be sent in the request */
+
+ bytesleft = privreq->req.len - privreq->req.xfrd;
+ nbytes = bytesleft;
+
+ /* Assume no zero-length-packet on the next pass through this loop */
+
+ privep->zlp = false;
+
+ /* Limit the size of the transfer to one full packet and handle
+ * zero-length packets (ZLPs).
+ */
+
+ if (nbytes > 0)
+ {
+ /* Either send the maxpacketsize or all of the remaining data in
+ * the request.
+ */
+
+ if (nbytes >= privep->ep.maxpacket)
+ {
+ nbytes = privep->ep.maxpacket;
+
+ /* Handle the case where this packet is exactly the
+ * maxpacketsize. Do we need to send a zero-length packet
+ * in this case?
+ */
+
+ if (bytesleft == privep->ep.maxpacket &&
+ (privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
+ {
+ /* The ZLP flag is set TRUE whenever we want to force
+ * the driver to send a zero-length-packet on the next
+ * pass through this loop. The flag is cleared (above)
+ * whenever we are committed to sending any packet and
+ * set here when we want to force one more pass through
+ * the loop.
+ */
+
+ privep->zlp = true;
+ }
+ }
+ }
+
+ /* Get the transfer size in 32-bit words */
+
+ nwords = (nbytes + 3) >> 2;
+
+ /* Get the number of 32-bit words available in the TxFIFO. The
+ * DXTFSTS indicates the amount of free space available in the
+ * endpoint TxFIFO. Values are in terms of 32-bit words:
+ *
+ * 0: Endpoint TxFIFO is full
+ * 1: 1 word available
+ * 2: 2 words available
+ * n: n words available
+ */
+
+ regaddr = EFM32_USB_DTXFSTS(privep->epphy);
+
+ /* Check for space in the TxFIFO. If space in the TxFIFO is not
+ * available, then set up an interrupt to resume the transfer when
+ * the TxFIFO is empty.
+ */
+
+ regval = efm32_getreg(regaddr);
+ if ((int)(regval & _USB_DTXFSTS_MASK) < nwords)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN_EMPWAIT), (uint16_t)regval);
+
+ /* There is insufficient space in the TxFIFO. Wait for a TxFIFO
+ * empty interrupt and try again.
+ */
+
+ uint32_t empmsk = efm32_getreg(EFM32_USB_DIEPEMPMSK);
+ empmsk |= USB_DIEPEMPMSK(privep->epphy);
+ efm32_putreg(empmsk, EFM32_USB_DIEPEMPMSK);
+
+ /* Terminate the transfer. We will try again when the TxFIFO empty
+ * interrupt is received.
+ */
+
+ return;
+ }
+
+ /* Transfer data to the TxFIFO */
+
+ buf = privreq->req.buf + privreq->req.xfrd;
+ efm32_epin_transfer(privep, buf, nbytes);
+
+ /* If it was not before, the OUT endpoint is now actively transferring
+ * data.
+ */
+
+ privep->active = true;
+
+ /* EP0 is a special case */
+
+ if (privep->epphy == EP0)
+ {
+ priv->ep0state = EP0STATE_DATA_IN;
+ }
+
+ /* Update for the next time through the loop */
+
+ privreq->req.xfrd += nbytes;
+ }
+
+ /* Note that the ZLP, if any, must be sent as a separate transfer. The need
+ * for a ZLP is indicated by privep->zlp. If all of the bytes were sent
+ * (including any final null packet) then we are finished with the transfer
+ */
+
+ if (privreq->req.xfrd >= privreq->req.len && !privep->zlp)
+ {
+ usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
+
+ /* We are finished with the request (although the transfer has not
+ * yet completed).
+ */
+
+ efm32_req_complete(privep, OK);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_rxfifo_read
+ *
+ * Description:
+ * Read packet from the RxFIFO into a read request.
+ *
+ *******************************************************************************/
+
+static void efm32_rxfifo_read(FAR struct efm32_ep_s *privep,
+ FAR uint8_t *dest, uint16_t len)
+{
+ uint32_t regaddr;
+ int i;
+
+ /* Get the address of the RxFIFO. Note: there is only one RxFIFO so
+ * we might as well use the addess associated with EP0.
+ */
+
+ regaddr = EFM32_USB_DFIFO_DEP(EP0);
+
+ /* Read 32-bits and write 4 x 8-bits at time (to avoid unaligned accesses) */
+
+ for (i = 0; i < len; i += 4)
+ {
+ union
+ {
+ uint32_t w;
+ uint8_t b[4];
+ } data;
+
+ /* Read 1 x 32-bits of EP0 packet data */
+
+ data.w = efm32_getreg(regaddr);
+
+ /* Write 4 x 8-bits of EP0 packet data */
+
+ *dest++ = data.b[0];
+ *dest++ = data.b[1];
+ *dest++ = data.b[2];
+ *dest++ = data.b[3];
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_rxfifo_discard
+ *
+ * Description:
+ * Discard packet data from the RxFIFO.
+ *
+ *******************************************************************************/
+
+static void efm32_rxfifo_discard(FAR struct efm32_ep_s *privep, int len)
+{
+ if (len > 0)
+ {
+ uint32_t regaddr;
+ int i;
+
+ /* Get the address of the RxFIFO Note: there is only one RxFIFO so
+ * we might as well use the addess associated with EP0.
+ */
+
+ regaddr = EFM32_USB_DFIFO_DEP(EP0);
+
+ /* Read 32-bits at time */
+
+ for (i = 0; i < len; i += 4)
+ {
+ volatile uint32_t data = efm32_getreg(regaddr);
+ (void)data;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_epout_complete
+ *
+ * Description:
+ * This function is called when an OUT transfer complete interrupt is
+ * received. It completes the read request at the head of the endpoint's
+ * request queue.
+ *
+ *******************************************************************************/
+
+static void efm32_epout_complete(FAR struct efm32_usbdev_s *priv,
+ FAR struct efm32_ep_s *privep)
+{
+ struct efm32_req_s *privreq;
+
+ /* Since a transfer just completed, there must be a read request at the head of
+ * the endpoint request queue.
+ */
+
+ privreq = efm32_rqpeek(privep);
+ DEBUGASSERT(privreq);
+
+ if (!privreq)
+ {
+ /* An OUT transfer completed, but no packet to receive the data. This
+ * should not happen.
+ */
+
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EPOUTQEMPTY), privep->epphy);
+ privep->active = false;
+ return;
+ }
+
+ ullvdbg("EP%d: len=%d xfrd=%d\n",
+ privep->epphy, privreq->req.len, privreq->req.xfrd);
+
+ /* Return the completed read request to the class driver and mark the state
+ * IDLE.
+ */
+
+ usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
+ efm32_req_complete(privep, OK);
+ privep->active = false;
+
+ /* Now set up the next read request (if any) */
+
+ efm32_epout_request(priv, privep);
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0out_receive
+ *
+ * Description:
+ * This function is called from the RXFLVL interrupt handler when new incoming
+ * data is available in the endpoint's RxFIFO. This function will simply
+ * copy the incoming data into pending request's data buffer.
+ *
+ *******************************************************************************/
+
+static inline void efm32_ep0out_receive(FAR struct efm32_ep_s *privep, int bcnt)
+{
+ FAR struct efm32_usbdev_s *priv;
+
+ /* Sanity Checking */
+
+ DEBUGASSERT(privep && privep->ep.priv);
+ priv = (FAR struct efm32_usbdev_s *)privep->ep.priv;
+
+ ullvdbg("EP0: bcnt=%d\n", bcnt);
+ usbtrace(TRACE_READ(EP0), bcnt);
+
+ /* Verify that an OUT SETUP request as received before this data was
+ * received in the RxFIFO.
+ */
+
+ if (priv->ep0state == EP0STATE_SETUP_OUT)
+ {
+ /* Read the data into our special buffer for SETUP data */
+
+ int readlen = MIN(CONFIG_USBDEV_SETUP_MAXDATASIZE, bcnt);
+ efm32_rxfifo_read(privep, priv->ep0data, readlen);
+
+ /* Do we have to discard any excess bytes? */
+
+ efm32_rxfifo_discard(privep, bcnt - readlen);
+
+ /* Now we can process the setup command */
+
+ privep->active = false;
+ priv->ep0state = EP0STATE_SETUP_READY;
+ priv->ep0datlen = readlen;
+
+ efm32_ep0out_setup(priv);
+ }
+ else
+ {
+ /* This is an error. We don't have any idea what to do with the EP0
+ * data in this case. Just read and discard it so that the RxFIFO
+ * does not become constipated.
+ */
+
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_NOOUTSETUP), priv->ep0state);
+ efm32_rxfifo_discard(privep, bcnt);
+ privep->active = false;
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_epout_receive
+ *
+ * Description:
+ * This function is called from the RXFLVL interrupt handler when new incoming
+ * data is available in the endpoint's RxFIFO. This function will simply
+ * copy the incoming data into pending request's data buffer.
+ *
+ *******************************************************************************/
+
+static inline void efm32_epout_receive(FAR struct efm32_ep_s *privep, int bcnt)
+{
+ struct efm32_req_s *privreq;
+ uint8_t *dest;
+ int buflen;
+ int readlen;
+
+ /* Get a reference to the request at the head of the endpoint's request
+ * queue.
+ */
+
+ privreq = efm32_rqpeek(privep);
+ if (!privreq)
+ {
+ /* Incoming data is available in the RxFIFO, but there is no read setup
+ * to receive the receive the data. This should not happen for data
+ * endpoints; those endpoints should have been NAKing any OUT data tokens.
+ *
+ * We should get here normally on OUT data phase following an OUT
+ * SETUP command. EP0 data will still receive data in this case and it
+ * should not be NAKing.
+ */
+
+ if (privep->epphy == 0)
+ {
+ efm32_ep0out_receive(privep, bcnt);
+ }
+ else
+ {
+ /* Otherwise, the data is lost. This really should not happen if
+ * NAKing is working as expected.
+ */
+
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EPOUTQEMPTY), privep->epphy);
+
+ /* Discard the data in the RxFIFO */
+
+ efm32_rxfifo_discard(privep, bcnt);
+ }
+
+ privep->active = false;
+ return;
+ }
+
+ ullvdbg("EP%d: len=%d xfrd=%d\n", privep->epphy, privreq->req.len, privreq->req.xfrd);
+ usbtrace(TRACE_READ(privep->epphy), bcnt);
+
+ /* Get the number of bytes to transfer from the RxFIFO */
+
+ buflen = privreq->req.len - privreq->req.xfrd;
+ DEBUGASSERT(buflen > 0 && buflen >= bcnt);
+ readlen = MIN(buflen, bcnt);
+
+ /* Get the destination of the data transfer */
+
+ dest = privreq->req.buf + privreq->req.xfrd;
+
+ /* Transfer the data from the RxFIFO to the request's data buffer */
+
+ efm32_rxfifo_read(privep, dest, readlen);
+
+ /* If there were more bytes in the RxFIFO than could be held in the read
+ * request, then we will have to discard those.
+ */
+
+ efm32_rxfifo_discard(privep, bcnt - readlen);
+
+ /* Update the number of bytes transferred */
+
+ privreq->req.xfrd += readlen;
+}
+
+/*******************************************************************************
+ * Name: efm32_epout_request
+ *
+ * Description:
+ * This function is called when either (1) new read request is received, or
+ * (2) a pending receive request completes. If there is no read in pending,
+ * then this function will initiate the next OUT (read) operation.
+ *
+ *******************************************************************************/
+
+static void efm32_epout_request(FAR struct efm32_usbdev_s *priv,
+ FAR struct efm32_ep_s *privep)
+{
+ struct efm32_req_s *privreq;
+ uint32_t regaddr;
+ uint32_t regval;
+ uint32_t xfrsize;
+ uint32_t pktcnt;
+
+ /* Make sure that there is not already a pending request request. If there is,
+ * just return, leaving the newly received request in the request queue.
+ */
+
+ if (!privep->active)
+ {
+ /* Loop until a valid request is found (or the request queue is empty).
+ * The loop is only need to look at the request queue again is an invalid
+ * read request is encountered.
+ */
+
+ for (;;)
+ {
+ /* Get a reference to the request at the head of the endpoint's request queue */
+
+ privreq = efm32_rqpeek(privep);
+ if (!privreq)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EPOUTQEMPTY), privep->epphy);
+
+ /* There are no read requests to be setup. Configure the hardware to
+ * NAK any incoming packets. (This should already be the case. I
+ * think that the hardware will automatically NAK after a transfer is
+ * completed until SNAK is cleared).
+ */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval |= USB_DOEPCTL_SNAK;
+ efm32_putreg(regval, regaddr);
+
+ /* This endpoint is no longer actively transferring */
+
+ privep->active = false;
+ return;
+ }
+
+ ullvdbg("EP%d: len=%d\n", privep->epphy, privreq->req.len);
+
+ /* Ignore any attempt to receive a zero length packet (this really
+ * should not happen.
+ */
+
+ if (privreq->req.len <= 0)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EPOUTNULLPACKET), 0);
+ efm32_req_complete(privep, OK);
+ }
+
+ /* Otherwise, we have a usable read request... break out of the loop */
+
+ else
+ {
+ break;
+ }
+ }
+
+ /* Setup the pending read into the request buffer. First calculate:
+ *
+ * pktcnt = the number of packets (of maxpacket bytes) required to
+ * perform the transfer.
+ * xfrsize = The total number of bytes required (in units of
+ * maxpacket bytes).
+ */
+
+ pktcnt = (privreq->req.len + (privep->ep.maxpacket - 1)) / privep->ep.maxpacket;
+ xfrsize = pktcnt * privep->ep.maxpacket;
+
+ /* Then setup the hardware to perform this transfer */
+
+ regaddr = EFM32_USB_DOEPTSIZ(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval &= ~(_USB_DOEPTSIZ_XFERSIZE_MASK | _USB_DOEPTSIZ_PKTCNT_MASK);
+ regval |= (xfrsize << _USB_DOEPTSIZ_XFERSIZE_SHIFT);
+ regval |= (pktcnt << _USB_DOEPTSIZ_PKTCNT_SHIFT);
+ efm32_putreg(regval, regaddr);
+
+ /* Then enable the transfer */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+
+ /* When an isochronous transfer is enabled the Even/Odd frame bit must
+ * also be set appropriately.
+ */
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+ if (privep->eptype == USB_EP_ATTR_XFER_ISOC)
+ {
+ if (privep->odd)
+ {
+ regval |= USB_DOEPCTL_SODDFRM;
+ }
+ else
+ {
+ regval |= USB_DOEPCTL_SEVNFRM;
+ }
+ }
+#endif
+
+ /* Clearing NAKing and enable the transfer. */
+
+ regval |= (USB_DOEPCTL_CNAK | USB_DOEPCTL_EPENA);
+ efm32_putreg(regval, regaddr);
+
+ /* A transfer is now active on this endpoint */
+
+ privep->active = true;
+
+ /* EP0 is a special case. We need to know when to switch back to
+ * normal SETUP processing.
+ */
+
+ if (privep->epphy == EP0)
+ {
+ priv->ep0state = EP0STATE_DATA_OUT;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_flush
+ *
+ * Description:
+ * Flush any primed descriptors from this ep
+ *
+ *******************************************************************************/
+
+static void efm32_ep_flush(struct efm32_ep_s *privep)
+{
+ if (privep->isin)
+ {
+ efm32_txfifo_flush(USB_GRSTCTL_TXFNUM_D(privep->epphy));
+ }
+ else
+ {
+ efm32_rxfifo_flush();
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_req_complete
+ *
+ * Description:
+ * Handle termination of the request at the head of the endpoint request queue.
+ *
+ *******************************************************************************/
+
+static void efm32_req_complete(struct efm32_ep_s *privep, int16_t result)
+{
+ FAR struct efm32_req_s *privreq;
+
+ /* Remove the request at the head of the request list */
+
+ privreq = efm32_req_remfirst(privep);
+ DEBUGASSERT(privreq != NULL);
+
+ /* If endpoint 0, temporarily reflect the state of protocol stalled
+ * in the callback.
+ */
+
+ bool stalled = privep->stalled;
+ if (privep->epphy == EP0)
+ {
+ privep->stalled = privep->dev->stalled;
+ }
+
+ /* Save the result in the request structure */
+
+ privreq->req.result = result;
+
+ /* Callback to the request completion handler */
+
+ privreq->req.callback(&privep->ep, &privreq->req);
+
+ /* Restore the stalled indication */
+
+ privep->stalled = stalled;
+}
+
+/*******************************************************************************
+ * Name: efm32_req_cancel
+ *
+ * Description:
+ * Cancel all pending requests for an endpoint
+ *
+ *******************************************************************************/
+
+static void efm32_req_cancel(struct efm32_ep_s *privep, int16_t status)
+{
+ if (!efm32_rqempty(privep))
+ {
+ efm32_ep_flush(privep);
+ }
+
+ while (!efm32_rqempty(privep))
+ {
+ usbtrace(TRACE_COMPLETE(privep->epphy),
+ (efm32_rqpeek(privep))->req.xfrd);
+ efm32_req_complete(privep, status);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_findbyaddr
+ *
+ * Description:
+ * Find the physical endpoint structure corresponding to a logic endpoint
+ * address
+ *
+ *******************************************************************************/
+
+static struct efm32_ep_s *efm32_ep_findbyaddr(struct efm32_usbdev_s *priv,
+ uint16_t eplog)
+{
+ struct efm32_ep_s *privep;
+ uint8_t epphy = USB_EPNO(eplog);
+
+ if (epphy >= EFM32_NENDPOINTS)
+ {
+ return NULL;
+ }
+
+ /* Is this an IN or an OUT endpoint? */
+
+ if (USB_ISEPIN(eplog))
+ {
+ privep = &priv->epin[epphy];
+ }
+ else
+ {
+ privep = &priv->epout[epphy];
+ }
+
+ /* Return endpoint reference */
+
+ DEBUGASSERT(privep->epphy == epphy);
+ return privep;
+}
+
+/*******************************************************************************
+ * Name: efm32_req_dispatch
+ *
+ * Description:
+ * Provide unhandled setup actions to the class driver. This is logically part
+ * of the USB interrupt handler.
+ *
+ *******************************************************************************/
+
+static int efm32_req_dispatch(struct efm32_usbdev_s *priv,
+ const struct usb_ctrlreq_s *ctrl)
+{
+ int ret = -EIO;
+
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_DISPATCH), 0);
+ if (priv->driver)
+ {
+ /* Forward to the control request to the class driver implementation */
+
+ ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl,
+ priv->ep0data, priv->ep0datlen);
+ }
+
+ if (ret < 0)
+ {
+ /* Stall on failure */
+
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_DISPATCHSTALL), 0);
+ priv->stalled = true;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_usbreset
+ *
+ * Description:
+ * Reset Usb engine
+ *
+ *******************************************************************************/
+
+static void efm32_usbreset(struct efm32_usbdev_s *priv)
+{
+ FAR struct efm32_ep_s *privep;
+ uint32_t regval;
+ int i;
+
+ /* Clear the Remote Wake-up Signaling */
+
+ regval = efm32_getreg(EFM32_USB_DCTL);
+ regval &= ~USB_DCTL_RWUSIG;
+ efm32_putreg(regval, EFM32_USB_DCTL);
+
+ /* Flush the EP0 Tx FIFO */
+
+ efm32_txfifo_flush(USB_GRSTCTL_TXFNUM_D(EP0));
+
+ /* Tell the class driver that we are disconnected. The class
+ * driver should then accept any new configurations.
+ */
+
+ if (priv->driver)
+ {
+ CLASS_DISCONNECT(priv->driver, &priv->usbdev);
+ }
+
+ /* Mark all endpoints as available */
+
+ priv->epavail[0] = EFM32_EP_AVAILABLE;
+ priv->epavail[1] = EFM32_EP_AVAILABLE;
+
+ /* Disable all end point interrupts */
+
+ for (i = 0; i < EFM32_NENDPOINTS ; i++)
+ {
+ /* Disable endpoint interrupts */
+
+ efm32_putreg(0xff, EFM32_USB_DIEPINT(i));
+ efm32_putreg(0xff, EFM32_USB_DOEPINT(i));
+
+ /* Return write requests to the class implementation */
+
+ privep = &priv->epin[i];
+ efm32_req_cancel(privep, -ESHUTDOWN);
+
+ /* Reset IN endpoint status */
+
+ privep->stalled = false;
+
+ /* Return read requests to the class implementation */
+
+ privep = &priv->epout[i];
+ efm32_req_cancel(privep, -ESHUTDOWN);
+
+ /* Reset endpoint status */
+
+ privep->stalled = false;
+ }
+
+ efm32_putreg(0xffffffff, EFM32_USB_DAINT);
+
+ /* Mask all device endpoint interrupts except EP0 */
+
+ regval = (USB_DAINT_IEP(EP0) | USB_DAINT_OEP(EP0));
+ efm32_putreg(regval, EFM32_USB_DAINTMSK);
+
+ /* Unmask OUT interrupts */
+
+ regval = (USB_DOEPMSK_XFERCOMPLMSK | USB_DOEPMSK_SETUPMSK |
+ USB_DOEPMSK_EPDISBLDMSK);
+ efm32_putreg(regval, EFM32_USB_DOEPMSK);
+
+ /* Unmask IN interrupts */
+
+ regval = (USB_DIEPMSK_XFERCOMPLMSK | USB_DIEPMSK_EPDISBLDMSK |
+ USB_DIEPMSK_TIMEOUTMSK);
+ efm32_putreg(regval, EFM32_USB_DIEPMSK);
+
+ /* Reset device address to 0 */
+
+ efm32_setaddress(priv, 0);
+ priv->devstate = DEVSTATE_DEFAULT;
+ priv->usbdev.speed = USB_SPEED_FULL;
+
+ /* Re-configure EP0 */
+
+ efm32_ep0_configure(priv);
+
+ /* Setup EP0 to receive SETUP packets */
+
+ efm32_ep0out_ctrlsetup(priv);
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0out_testmode
+ *
+ * Description:
+ * Select test mode
+ *
+ *******************************************************************************/
+
+static inline void efm32_ep0out_testmode(FAR struct efm32_usbdev_s *priv,
+ uint16_t index)
+{
+ uint8_t testmode;
+
+ testmode = index >> 8;
+ switch (testmode)
+ {
+ case 1:
+ priv->testmode = USB_TESTMODE_J;
+ break;
+
+ case 2:
+ priv->testmode = USB_TESTMODE_K;
+ break;
+
+ case 3:
+ priv->testmode = USB_TESTMODE_SE0_NAK;
+ break;
+
+ case 4:
+ priv->testmode = USB_TESTMODE_PACKET;
+ break;
+
+ case 5:
+ priv->testmode = USB_TESTMODE_FORCE;
+ break;
+
+ default:
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADTESTMODE), testmode);
+ priv->dotest = false;
+ priv->testmode = USB_TESTMODE_DISABLED;
+ priv->stalled = true;
+ }
+
+ priv->dotest = true;
+ efm32_ep0in_transmitzlp(priv);
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0out_stdrequest
+ *
+ * Description:
+ * Handle a stanard request on EP0. Pick off the things of interest to the
+ * USB device controller driver; pass what is left to the class driver.
+ *
+ *******************************************************************************/
+
+static inline void efm32_ep0out_stdrequest(struct efm32_usbdev_s *priv,
+ FAR struct efm32_ctrlreq_s *ctrlreq)
+{
+ FAR struct efm32_ep_s *privep;
+
+ /* Handle standard request */
+
+ switch (ctrlreq->req)
+ {
+ case USB_REQ_GETSTATUS:
+ {
+ /* type: device-to-host; recipient = device, interface, endpoint
+ * value: 0
+ * index: zero interface endpoint
+ * len: 2; data = status
+ */
+
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_GETSTATUS), 0);
+ if (!priv->addressed ||
+ ctrlreq->len != 2 ||
+ USB_REQ_ISOUT(ctrlreq->type) ||
+ ctrlreq->value != 0)
+ {
+ priv->stalled = true;
+ }
+ else
+ {
+ switch (ctrlreq->type & USB_REQ_RECIPIENT_MASK)
+ {
+ case USB_REQ_RECIPIENT_ENDPOINT:
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPGETSTATUS), 0);
+ privep = efm32_ep_findbyaddr(priv, ctrlreq->index);
+ if (!privep)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADEPGETSTATUS), 0);
+ priv->stalled = true;
+ }
+ else
+ {
+ if (privep->stalled)
+ {
+ priv->ep0data[0] = (1 << USB_FEATURE_ENDPOINTHALT);
+ }
+ else
+ {
+ priv->ep0data[0] = 0; /* Not stalled */
+ }
+
+ priv->ep0data[1] = 0;
+ efm32_ep0in_setupresponse(priv, priv->ep0data, 2);
+ }
+ }
+ break;
+
+ case USB_REQ_RECIPIENT_DEVICE:
+ {
+ if (ctrlreq->index == 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_DEVGETSTATUS), 0);
+
+ /* Features: Remote Wakeup and selfpowered */
+
+ priv->ep0data[0] = (priv->selfpowered << USB_FEATURE_SELFPOWERED);
+ priv->ep0data[0] |= (priv->wakeup << USB_FEATURE_REMOTEWAKEUP);
+ priv->ep0data[1] = 0;
+
+ efm32_ep0in_setupresponse(priv, priv->ep0data, 2);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADDEVGETSTATUS), 0);
+ priv->stalled = true;
+ }
+ }
+ break;
+
+ case USB_REQ_RECIPIENT_INTERFACE:
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_IFGETSTATUS), 0);
+ priv->ep0data[0] = 0;
+ priv->ep0data[1] = 0;
+
+ efm32_ep0in_setupresponse(priv, priv->ep0data, 2);
+ }
+ break;
+
+ default:
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADGETSTATUS), 0);
+ priv->stalled = true;
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case USB_REQ_CLEARFEATURE:
+ {
+ /* type: host-to-device; recipient = device, interface or endpoint
+ * value: feature selector
+ * index: zero interface endpoint;
+ * len: zero, data = none
+ */
+
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_CLEARFEATURE), 0);
+ if (priv->addressed != 0 && ctrlreq->len == 0)
+ {
+ uint8_t recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK;
+ if (recipient == USB_REQ_RECIPIENT_ENDPOINT &&
+ ctrlreq->value == USB_FEATURE_ENDPOINTHALT &&
+ (privep = efm32_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
+ {
+ efm32_ep_clrstall(privep);
+ efm32_ep0in_transmitzlp(priv);
+ }
+ else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
+ {
+ priv->wakeup = 0;
+ efm32_ep0in_transmitzlp(priv);
+ }
+ else
+ {
+ /* Actually, I think we could just stall here. */
+
+ (void)efm32_req_dispatch(priv, &priv->ctrlreq);
+ }
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADCLEARFEATURE), 0);
+ priv->stalled = true;
+ }
+ }
+ break;
+
+ case USB_REQ_SETFEATURE:
+ {
+ /* type: host-to-device; recipient = device, interface, endpoint
+ * value: feature selector
+ * index: zero interface endpoint;
+ * len: 0; data = none
+ */
+
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SETFEATURE), 0);
+ if (priv->addressed != 0 && ctrlreq->len == 0)
+ {
+ uint8_t recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK;
+ if (recipient == USB_REQ_RECIPIENT_ENDPOINT &&
+ ctrlreq->value == USB_FEATURE_ENDPOINTHALT &&
+ (privep = efm32_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
+ {
+ efm32_ep_setstall(privep);
+ efm32_ep0in_transmitzlp(priv);
+ }
+ else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
+ {
+ priv->wakeup = 1;
+ efm32_ep0in_transmitzlp(priv);
+ }
+ else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->value == USB_FEATURE_TESTMODE &&
+ ((ctrlreq->index & 0xff) == 0))
+ {
+ efm32_ep0out_testmode(priv, ctrlreq->index);
+ }
+ else if (priv->configured)
+ {
+ /* Actually, I think we could just stall here. */
+
+ (void)efm32_req_dispatch(priv, &priv->ctrlreq);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADSETFEATURE), 0);
+ priv->stalled = true;
+ }
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADSETFEATURE), 0);
+ priv->stalled = true;
+ }
+ }
+ break;
+
+ case USB_REQ_SETADDRESS:
+ {
+ /* type: host-to-device; recipient = device
+ * value: device address
+ * index: 0
+ * len: 0; data = none
+ */
+
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SETADDRESS), ctrlreq->value);
+ if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->index == 0 &&
+ ctrlreq->len == 0 &&
+ ctrlreq->value < 128 &&
+ priv->devstate != DEVSTATE_CONFIGURED)
+ {
+ /* Save the address. We cannot actually change to the next address until
+ * the completion of the status phase.
+ */
+
+ efm32_setaddress(priv, (uint16_t)priv->ctrlreq.value[0]);
+ efm32_ep0in_transmitzlp(priv);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADSETADDRESS), 0);
+ priv->stalled = true;
+ }
+ }
+ break;
+
+ case USB_REQ_GETDESCRIPTOR:
+ /* type: device-to-host; recipient = device
+ * value: descriptor type and index
+ * index: 0 or language ID;
+ * len: descriptor len; data = descriptor
+ */
+
+ case USB_REQ_SETDESCRIPTOR:
+ /* type: host-to-device; recipient = device
+ * value: descriptor type and index
+ * index: 0 or language ID;
+ * len: descriptor len; data = descriptor
+ */
+
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_GETSETDESC), 0);
+ if ((ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE)
+ {
+ (void)efm32_req_dispatch(priv, &priv->ctrlreq);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADGETSETDESC), 0);
+ priv->stalled = true;
+ }
+ }
+ break;
+
+ case USB_REQ_GETCONFIGURATION:
+ /* type: device-to-host; recipient = device
+ * value: 0;
+ * index: 0;
+ * len: 1; data = configuration value
+ */
+
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_GETCONFIG), 0);
+ if (priv->addressed &&
+ (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->value == 0 &&
+ ctrlreq->index == 0 &&
+ ctrlreq->len == 1)
+ {
+ (void)efm32_req_dispatch(priv, &priv->ctrlreq);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADGETCONFIG), 0);
+ priv->stalled = true;
+ }
+ }
+ break;
+
+ case USB_REQ_SETCONFIGURATION:
+ /* type: host-to-device; recipient = device
+ * value: configuration value
+ * index: 0;
+ * len: 0; data = none
+ */
+
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SETCONFIG), 0);
+ if (priv->addressed &&
+ (ctrlreq->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->index == 0 &&
+ ctrlreq->len == 0)
+ {
+ /* Give the configuration to the class driver */
+
+ int ret = efm32_req_dispatch(priv, &priv->ctrlreq);
+
+ /* If the class driver accepted the configuration, then mark the
+ * device state as configured (or not, depending on the
+ * configuration).
+ */
+
+ if (ret == OK)
+ {
+ uint8_t cfg = (uint8_t)ctrlreq->value;
+ if (cfg != 0)
+ {
+ priv->devstate = DEVSTATE_CONFIGURED;
+ priv->configured = true;
+ }
+ else
+ {
+ priv->devstate = DEVSTATE_ADDRESSED;
+ priv->configured = false;
+ }
+ }
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADSETCONFIG), 0);
+ priv->stalled = true;
+ }
+ }
+ break;
+
+ case USB_REQ_GETINTERFACE:
+ /* type: device-to-host; recipient = interface
+ * value: 0
+ * index: interface;
+ * len: 1; data = alt interface
+ */
+
+ case USB_REQ_SETINTERFACE:
+ /* type: host-to-device; recipient = interface
+ * value: alternate setting
+ * index: interface;
+ * len: 0; data = none
+ */
+
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_GETSETIF), 0);
+ (void)efm32_req_dispatch(priv, &priv->ctrlreq);
+ }
+ break;
+
+ case USB_REQ_SYNCHFRAME:
+ /* type: device-to-host; recipient = endpoint
+ * value: 0
+ * index: endpoint;
+ * len: 2; data = frame number
+ */
+
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SYNCHFRAME), 0);
+ }
+ break;
+
+ default:
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDCTRLREQ), 0);
+ priv->stalled = true;
+ }
+ break;
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0out_setup
+ *
+ * Description:
+ * USB Ctrl EP Setup Event. This is logically part of the USB interrupt
+ * handler. This event occurs when a setup packet is receive on EP0 OUT.
+ *
+ *******************************************************************************/
+
+static inline void efm32_ep0out_setup(struct efm32_usbdev_s *priv)
+{
+ struct efm32_ctrlreq_s ctrlreq;
+
+ /* Verify that a SETUP was received */
+
+ if (priv->ep0state != EP0STATE_SETUP_READY)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EP0NOSETUP), priv->ep0state);
+ return;
+ }
+
+ /* Terminate any pending requests */
+
+ efm32_req_cancel(&priv->epout[EP0], -EPROTO);
+ efm32_req_cancel(&priv->epin[EP0], -EPROTO);
+
+ /* Assume NOT stalled */
+
+ priv->epout[EP0].stalled = false;
+ priv->epin[EP0].stalled = false;
+ priv->stalled = false;
+
+ /* Starting to process a control request - update state */
+
+ priv->ep0state = EP0STATE_SETUP_PROCESS;
+
+ /* And extract the little-endian 16-bit values to host order */
+
+ ctrlreq.type = priv->ctrlreq.type;
+ ctrlreq.req = priv->ctrlreq.req;
+ ctrlreq.value = GETUINT16(priv->ctrlreq.value);
+ ctrlreq.index = GETUINT16(priv->ctrlreq.index);
+ ctrlreq.len = GETUINT16(priv->ctrlreq.len);
+
+ ullvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
+ ctrlreq.type, ctrlreq.req, ctrlreq.value, ctrlreq.index, ctrlreq.len);
+
+ /* Check for a standard request */
+
+ if ((ctrlreq.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
+ {
+ /* Dispatch any non-standard requests */
+
+ (void)efm32_req_dispatch(priv, &priv->ctrlreq);
+ }
+ else
+ {
+ /* Handle standard requests. */
+
+ efm32_ep0out_stdrequest(priv, &ctrlreq);
+ }
+
+ /* Check if the setup processing resulted in a STALL */
+
+ if (priv->stalled)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EP0SETUPSTALLED), priv->ep0state);
+ efm32_ep0_stall(priv);
+ }
+
+ /* Reset state/data associated with thie SETUP request */
+
+ priv->ep0datlen = 0;
+}
+
+/*******************************************************************************
+ * Name: efm32_epout
+ *
+ * Description:
+ * This is part of the OUT endpoint interrupt processing. This function
+ * handles the OUT event for a single endpoint.
+ *
+ *******************************************************************************/
+
+static inline void efm32_epout(FAR struct efm32_usbdev_s *priv, uint8_t epno)
+{
+ FAR struct efm32_ep_s *privep;
+
+ /* Endpoint 0 is a special case. */
+
+ if (epno == 0)
+ {
+ privep = &priv->epout[EP0];
+
+ /* In the EP0STATE_DATA_OUT state, we are receiving data into the
+ * request buffer. In that case, we must continue the request
+ * processing.
+ */
+
+ if (priv->ep0state == EP0STATE_DATA_OUT)
+ {
+ /* Continue processing data from the EP0 OUT request queue */
+
+ efm32_epout_complete(priv, privep);
+
+ /* If we are not actively processing an OUT request, then we
+ * need to setup to receive the next control request.
+ */
+
+ if (!privep->active)
+ {
+ efm32_ep0out_ctrlsetup(priv);
+ priv->ep0state = EP0STATE_IDLE;
+ }
+ }
+ }
+
+ /* For other endpoints, the only possibility is that we are continuing
+ * or finishing an OUT request.
+ */
+
+ else if (priv->devstate == DEVSTATE_CONFIGURED)
+ {
+ efm32_epout_complete(priv, &priv->epout[epno]);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_epout_interrupt
+ *
+ * Description:
+ * USB OUT endpoint interrupt handler. The core generates this interrupt when
+ * there is an interrupt is pending on one of the OUT endpoints of the core.
+ * The driver must read the OTGFS DAINT register to determine the exact number
+ * of the OUT endpoint on which the interrupt occurred, and then read the
+ * corresponding OTGFS DOEPINTx register to determine the exact cause of the
+ * interrupt.
+ *
+ *******************************************************************************/
+
+static inline void efm32_epout_interrupt(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t daint;
+ uint32_t regval;
+ uint32_t doepint;
+ int epno;
+
+ /* Get the pending, enabled interrupts for the OUT endpoint from the endpoint
+ * interrupt status register.
+ */
+
+ regval = efm32_getreg(EFM32_USB_DAINT);
+ regval &= efm32_getreg(EFM32_USB_DAINTMSK);
+ daint = (regval & _USB_DAINT_OEP_MASK) >> _USB_DAINT_OEP_SHIFT;
+
+ if (daint == 0)
+ {
+ /* We got an interrupt, but there is no unmasked endpoint that caused
+ * it ?! When this happens, the interrupt flag never gets cleared and
+ * we are stuck in infinite interrupt loop.
+ *
+ * This shouldn't happen if we are diligent about handling timing
+ * issues when masking endpoint interrupts. However, this workaround
+ * avoids infinite loop and allows operation to continue normally. It
+ * works by clearing each endpoint flags, masked or not.
+ */
+
+ regval = efm32_getreg(EFM32_USB_DAINT);
+ daint = (regval & _USB_DAINT_OEP_MASK) >> _USB_DAINT_OEP_SHIFT;
+
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EPOUTUNEXPECTED),
+ (uint16_t)regval);
+
+ epno = 0;
+ while (daint)
+ {
+ if ((daint & 1) != 0)
+ {
+ regval = efm32_getreg(EFM32_USB_DOEPINT(epno));
+ ulldbg("DOEPINT(%d) = %08x\n", epno, regval);
+ efm32_putreg(0xFF, EFM32_USB_DOEPINT(epno));
+ }
+
+ epno++;
+ daint >>= 1;
+ }
+
+ return;
+ }
+
+ /* Process each pending IN endpoint interrupt */
+
+ epno = 0;
+ while (daint)
+ {
+ /* Is an OUT interrupt pending for this endpoint? */
+
+ if ((daint & 1) != 0)
+ {
+ /* Yes.. get the OUT endpoint interrupt status */
+
+ doepint = efm32_getreg(EFM32_USB_DOEPINT(epno));
+ doepint &= efm32_getreg(EFM32_USB_DOEPMSK);
+
+ /* Transfer completed interrupt. This interrupt is trigged when
+ * efm32_rxinterrupt() removes the last packet data from the RxFIFO.
+ * In this case, core internally sets the NAK bit for this endpoint to
+ * prevent it from receiving any more packets.
+ */
+
+ if ((doepint & USB_DOEPINT_XFRC) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPOUT_XFRC), (uint16_t)doepint);
+
+ /* Clear the bit in DOEPINTn for this interrupt */
+
+ efm32_putreg(USB_DOEPINT_XFRC, EFM32_USB_DOEPINT(epno));
+
+ /* Handle the RX transfer data ready event */
+
+ efm32_epout(priv, epno);
+ }
+
+ /* Endpoint disabled interrupt (ignored because this interrrupt is
+ * used in polled mode by the endpoint disable logic).
+ */
+#if 1
+ /* REVISIT: */
+ if ((doepint & USB_DOEPINT_EPDISD) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPOUT_EPDISD), (uint16_t)doepint);
+
+ /* Clear the bit in DOEPINTn for this interrupt */
+
+ efm32_putreg(USB_DOEPINT_EPDISD, EFM32_USB_DOEPINT(epno));
+ }
+#endif
+ /* Setup Phase Done (control EPs) */
+
+ if ((doepint & USB_DOEPINT_SETUP) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPOUT_SETUP), priv->ep0state);
+
+ /* Handle the receipt of the IN SETUP packets now (OUT setup
+ * packet processing may be delayed until the accompanying
+ * OUT DATA is received)
+ */
+
+ if (priv->ep0state == EP0STATE_SETUP_READY)
+ {
+ efm32_ep0out_setup(priv);
+ }
+ efm32_putreg(USB_DOEPINT_SETUP, EFM32_USB_DOEPINT(epno));
+ }
+ }
+
+ epno++;
+ daint >>= 1;
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_epin_runtestmode
+ *
+ * Description:
+ * Execute the test mode setup by the SET FEATURE request
+ *
+ *******************************************************************************/
+
+static inline void efm32_epin_runtestmode(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t regval = efm32_getreg(EFM32_USB_DCTL);
+ regval &= _USB_DCTL_TCTL_MASK;
+ regval |= (uint32_t)priv->testmode << _USB_DCTL_TCTL_SHIFT;
+ efm32_putreg(regval , EFM32_USB_DCTL);
+
+ priv->dotest = 0;
+ priv->testmode = USB_TESTMODE_DISABLED;
+}
+
+/*******************************************************************************
+ * Name: efm32_epin
+ *
+ * Description:
+ * This is part of the IN endpoint interrupt processing. This function
+ * handles the IN event for a single endpoint.
+ *
+ *******************************************************************************/
+
+static inline void efm32_epin(FAR struct efm32_usbdev_s *priv, uint8_t epno)
+{
+ FAR struct efm32_ep_s *privep = &priv->epin[epno];
+
+ /* Endpoint 0 is a special case. */
+
+ if (epno == 0)
+ {
+ /* In the EP0STATE_DATA_IN state, we are sending data from request
+ * buffer. In that case, we must continue the request processing.
+ */
+
+ if (priv->ep0state == EP0STATE_DATA_IN)
+ {
+ /* Continue processing data from the EP0 OUT request queue */
+
+ efm32_epin_request(priv, privep);
+
+ /* If we are not actively processing an OUT request, then we
+ * need to setup to receive the next control request.
+ */
+
+ if (!privep->active)
+ {
+ efm32_ep0out_ctrlsetup(priv);
+ priv->ep0state = EP0STATE_IDLE;
+ }
+ }
+
+ /* Test mode is another special case */
+
+ if (priv->dotest)
+ {
+ efm32_epin_runtestmode(priv);
+ }
+ }
+
+ /* For other endpoints, the only possibility is that we are continuing
+ * or finishing an IN request.
+ */
+
+ else if (priv->devstate == DEVSTATE_CONFIGURED)
+ {
+ /* Continue processing data from the endpoint write request queue */
+
+ efm32_epin_request(priv, privep);
+ }
+}
+
+/****************************************************************************
+ * Name: efm32_epin_txfifoempty
+ *
+ * Description:
+ * TxFIFO empty interrupt handling
+ *
+ ****************************************************************************/
+
+static inline void efm32_epin_txfifoempty(FAR struct efm32_usbdev_s *priv, int epno)
+{
+ FAR struct efm32_ep_s *privep = &priv->epin[epno];
+
+ /* Continue processing the write request queue. This may mean sending
+ * more data from the exisiting request or terminating the current requests
+ * and (perhaps) starting the IN transfer from the next write request.
+ */
+
+ efm32_epin_request(priv, privep);
+}
+
+/*******************************************************************************
+ * Name: efm32_epin_interrupt
+ *
+ * Description:
+ * USB IN endpoint interrupt handler. The core generates this interrupt when
+ * an interrupt is pending on one of the IN endpoints of the core. The driver
+ * must read the OTGFS DAINT register to determine the exact number of the IN
+ * endpoint on which the interrupt occurred, and then read the corresponding
+ * OTGFS DIEPINTx register to determine the exact cause of the interrupt.
+ *
+ *******************************************************************************/
+
+static inline void efm32_epin_interrupt(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t diepint;
+ uint32_t daint;
+ uint32_t mask;
+ uint32_t empty;
+ int epno;
+
+ /* Get the pending, enabled interrupts for the IN endpoint from the endpoint
+ * interrupt status register.
+ */
+
+ daint = efm32_getreg(EFM32_USB_DAINT);
+ daint &= efm32_getreg(EFM32_USB_DAINTMSK);
+ daint &= _USB_DAINT_IEP_MASK;
+
+ if (daint == 0)
+ {
+ /* We got an interrupt, but there is no unmasked endpoint that caused
+ * it ?! When this happens, the interrupt flag never gets cleared and
+ * we are stuck in infinite interrupt loop.
+ *
+ * This shouldn't happen if we are diligent about handling timing
+ * issues when masking endpoint interrupts. However, this workaround
+ * avoids infinite loop and allows operation to continue normally. It
+ * works by clearing each endpoint flags, masked or not.
+ */
+
+ daint = efm32_getreg(EFM32_USB_DAINT);
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_EPINUNEXPECTED),
+ (uint16_t)daint);
+
+ daint &= _USB_DAINT_IEP_MASK;
+ epno = 0;
+
+ while (daint)
+ {
+ if ((daint & 1) != 0)
+ {
+ ulldbg("DIEPINT(%d) = %08x\n",
+ epno, efm32_getreg(EFM32_USB_DIEPINT(epno)));
+ efm32_putreg(0xFF, EFM32_USB_DIEPINT(epno));
+ }
+
+ epno++;
+ daint >>= 1;
+ }
+
+ return;
+ }
+
+ /* Process each pending IN endpoint interrupt */
+
+ epno = 0;
+ while (daint)
+ {
+ /* Is an IN interrupt pending for this endpoint? */
+
+ if ((daint & 1) != 0)
+ {
+ /* Get IN interrupt mask register. Bits 0-6 correspond to enabled
+ * interrupts as will be found in the DIEPINT interrupt status
+ * register.
+ */
+
+ mask = efm32_getreg(EFM32_USB_DIEPMSK);
+
+ /* Check if the TxFIFO not empty interrupt is enabled for this
+ * endpoint in the DIEPMSK register. Bits n corresponds to
+ * endpoint n in the register. That condition corresponds to
+ * bit 7 of the DIEPINT interrupt status register. There is
+ * no TXFE bit in the mask register, so we fake one here.
+ */
+
+ empty = efm32_getreg(EFM32_USB_DIEPEMPMSK);
+ if ((empty & USB_DIEPEMPMSK(epno)) != 0)
+ {
+ mask |= USB_DIEPINT_TXFE;
+ }
+
+ /* Now, read the interrupt status and mask out all disabled
+ * interrupts.
+ */
+
+ diepint = efm32_getreg(EFM32_USB_DIEPINT(epno)) & mask;
+
+ /* Decode and process the enabled, pending interrupts */
+ /* Transfer completed interrupt */
+
+ if ((diepint & USB_DIEPINT_XFRC) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN_XFRC),
+ (uint16_t)diepint);
+
+ /* It is possible that logic may be waiting for a the
+ * TxFIFO to become empty. We disable the TxFIFO empty
+ * interrupt here; it will be re-enabled if there is still
+ * insufficient space in the TxFIFO.
+ */
+
+ empty &= ~USB_DIEPEMPMSK(epno);
+ efm32_putreg(empty, EFM32_USB_DIEPEMPMSK);
+ efm32_putreg(USB_DIEPINT_XFRC, EFM32_USB_DIEPINT(epno));
+
+ /* IN transfer complete */
+
+ efm32_epin(priv, epno);
+ }
+
+ /* Timeout condition */
+
+ if ((diepint & USB_DIEPINT_TOC) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN_TOC), (uint16_t)diepint);
+ efm32_putreg(USB_DIEPINT_TOC, EFM32_USB_DIEPINT(epno));
+ }
+
+ /* IN token received when TxFIFO is empty. Applies to non-periodic IN
+ * endpoints only. This interrupt indicates that an IN token was received
+ * when the associated TxFIFO (periodic/non-periodic) was empty. This
+ * interrupt is asserted on the endpoint for which the IN token was
+ * received.
+ */
+
+ if ((diepint & USB_DIEPINT_ITTXFE) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN_ITTXFE), (uint16_t)diepint);
+ efm32_epin_request(priv, &priv->epin[epno]);
+ efm32_putreg(USB_DIEPINT_ITTXFE, EFM32_USB_DIEPINT(epno));
+ }
+
+ /* IN endpoint NAK effective (ignored as this used only in polled
+ * mode)
+ */
+#if 0
+ if ((diepint & USB_DIEPINT_INEPNE) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN_INEPNE), (uint16_t)diepint);
+ efm32_putreg(USB_DIEPINT_INEPNE, EFM32_USB_DIEPINT(epno));
+ }
+#endif
+ /* Endpoint disabled interrupt (ignored as this used only in polled
+ * mode)
+ */
+#if 0
+ if ((diepint & USB_DIEPINT_EPDISD) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN_EPDISD), (uint16_t)diepint);
+ efm32_putreg(USB_DIEPINT_EPDISD, EFM32_USB_DIEPINT(epno));
+ }
+#endif
+ /* Transmit FIFO empty */
+
+ if ((diepint & USB_DIEPINT_TXFE) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN_TXFE), (uint16_t)diepint);
+
+ /* If we were waiting for TxFIFO to become empty, the we might have both
+ * XFRC and TXFE interrupts pending. Since we do the same thing for both
+ * cases, ignore the TXFE if we have already processed the XFRC.
+ */
+
+ if ((diepint & USB_DIEPINT_XFRC) == 0)
+ {
+ /* Mask further FIFO empty interrupts. This will be re-enabled
+ * whenever we need to wait for a FIFO event.
+ */
+
+ empty &= ~USB_DIEPEMPMSK(epno);
+ efm32_putreg(empty, EFM32_USB_DIEPEMPMSK);
+
+ /* Handle TxFIFO empty */
+
+ efm32_epin_txfifoempty(priv, epno);
+ }
+
+ /* Clear the pending TxFIFO empty interrupt */
+
+ efm32_putreg(USB_DIEPINT_TXFE, EFM32_USB_DIEPINT(epno));
+ }
+ }
+
+ epno++;
+ daint >>= 1;
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_resumeinterrupt
+ *
+ * Description:
+ * Resume/remote wakeup detected interrupt
+ *
+ *******************************************************************************/
+
+static inline void efm32_resumeinterrupt(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t regval;
+
+ /* Restart the PHY clock and un-gate USB core clock (HCLK) */
+
+#ifdef CONFIG_USBDEV_LOWPOWER
+ regval = efm32_getreg(EFM32_USB_PCGCCTL);
+ regval &= ~(OTGFS_PCGCCTL_STPPCLK | OTGFS_PCGCCTL_GATEHCLK);
+ efm32_putreg(regval, EFM32_USB_PCGCCTL);
+#endif
+
+ /* Clear remote wake-up signaling */
+
+ regval = efm32_getreg(EFM32_USB_DCTL);
+ regval &= ~USB_DCTL_RWUSIG;
+ efm32_putreg(regval, EFM32_USB_DCTL);
+
+ /* Restore full power -- whatever that means for this particular board */
+
+ efm32_usbsuspend((struct usbdev_s *)priv, true);
+
+ /* Notify the class driver of the resume event */
+
+ if (priv->driver)
+ {
+ CLASS_RESUME(priv->driver, &priv->usbdev);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_suspendinterrupt
+ *
+ * Description:
+ * USB suspend interrupt
+ *
+ *******************************************************************************/
+
+static inline void efm32_suspendinterrupt(FAR struct efm32_usbdev_s *priv)
+{
+#ifdef CONFIG_USBDEV_LOWPOWER
+ uint32_t regval;
+#endif
+
+ /* Notify the class driver of the suspend event */
+
+ if (priv->driver)
+ {
+ CLASS_SUSPEND(priv->driver, &priv->usbdev);
+ }
+
+#ifdef CONFIG_USBDEV_LOWPOWER
+ /* USB_DSTS_SUSPSTS is set as long as the suspend condition is detected
+ * on USB. Check if we are still have the suspend condition, that we are
+ * connected to the host, and that we have been configured.
+ */
+
+ regval = efm32_getreg(EFM32_USB_DSTS);
+
+ if ((regval & USB_DSTS_SUSPSTS) != 0 && devstate == DEVSTATE_CONFIGURED)
+ {
+ /* Switch off OTG FS clocking. Setting OTGFS_PCGCCTL_STPPCLK stops the
+ * PHY clock.
+ */
+
+ regval = efm32_getreg(EFM32_USB_PCGCCTL);
+ regval |= OTGFS_PCGCCTL_STPPCLK;
+ efm32_putreg(regval, EFM32_USB_PCGCCTL);
+
+ /* Setting OTGFS_PCGCCTL_GATEHCLK gate HCLK to modules other than
+ * the AHB Slave and Master and wakeup logic.
+ */
+
+ regval |= OTGFS_PCGCCTL_GATEHCLK;
+ efm32_putreg(regval, EFM32_USB_PCGCCTL);
+ }
+#endif
+
+ /* Let the board-specific logic know that we have entered the suspend
+ * state
+ */
+
+ efm32_usbsuspend((FAR struct usbdev_s *)priv, false);
+}
+
+/*******************************************************************************
+ * Name: efm32_rxinterrupt
+ *
+ * Description:
+ * RxFIFO non-empty interrupt. This interrupt indicates that there is at
+ * least one packet pending to be read from the RxFIFO.
+ *
+ *******************************************************************************/
+
+static inline void efm32_rxinterrupt(FAR struct efm32_usbdev_s *priv)
+{
+ FAR struct efm32_ep_s *privep;
+ uint32_t regval;
+ int bcnt;
+ int epphy;
+
+ /* Disable the Rx status queue level interrupt */
+
+ regval = efm32_getreg(EFM32_USB_GINTMSK);
+ regval &= ~USB_GINT_RXFLVL;
+ efm32_putreg(regval, EFM32_USB_GINTMSK);
+
+ /* Get the status from the top of the FIFO */
+
+ regval = efm32_getreg(EFM32_USB_GRXSTSP);
+
+ /* Decode status fields */
+
+ epphy = (regval & _USB_GRXSTSD_EPNUM_MASK) >> _USB_GRXSTSD_EPNUM_SHIFT;
+ privep = &priv->epout[epphy];
+
+ /* Handle the RX event according to the packet status field */
+
+ switch (regval & _USB_GRXSTSD_PKTSTS_MASK)
+ {
+ /* Global OUT NAK. This indicate that the global OUT NAK bit has taken
+ * effect.
+ *
+ * PKTSTS = Global OUT NAK, BCNT = 0, EPNUM = Don't Care, DPID = Don't
+ * Care.
+ */
+
+ case USB_GRXSTSD_PKTSTS_OUTNAK:
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_OUTNAK), 0);
+ }
+ break;
+
+ /* OUT data packet received.
+ *
+ * PKTSTS = DataOUT, BCNT = size of the received data OUT packet,
+ * EPNUM = EPNUM on which the packet was received, DPID = Actual Data PID.
+ */
+
+ case USB_GRXSTSD_PKTSTS_OUTRECVD:
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_OUTRECVD), epphy);
+ bcnt = (regval & _USB_GRXSTSD_BCNT_MASK) >> _USB_GRXSTSD_BCNT_SHIFT;
+ if (bcnt > 0)
+ {
+ efm32_epout_receive(privep, bcnt);
+ }
+ }
+ break;
+
+ /* OUT transfer completed. This indicates that an OUT data transfer for
+ * the specified OUT endpoint has completed. After this entry is popped
+ * from the receive FIFO, the core asserts a Transfer Completed interrupt
+ * on the specified OUT endpoint.
+ *
+ * PKTSTS = Data OUT Transfer Done, BCNT = 0, EPNUM = OUT EP Num on
+ * which the data transfer is complete, DPID = Don't Care.
+ */
+
+ case USB_GRXSTSD_PKTSTS_OUTDONE:
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_OUTDONE), epphy);
+ }
+ break;
+
+ /* SETUP transaction completed. This indicates that the Setup stage for
+ * the specified endpoint has completed and the Data stage has started.
+ * After this entry is popped from the receive FIFO, the core asserts a
+ * Setup interrupt on the specified control OUT endpoint (triggers an
+ * interrupt).
+ *
+ * PKTSTS = Setup Stage Done, BCNT = 0, EPNUM = Control EP Num,
+ * DPID = Don't Care.
+ */
+
+ case USB_GRXSTSD_PKTSTS_SETUPDONE:
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SETUPDONE), epphy);
+ }
+ break;
+
+ /* SETUP data packet received. This indicates that a SETUP packet for the
+ * specified endpoint is now available for reading from the receive FIFO.
+ *
+ * PKTSTS = SETUP, BCNT = 8, EPNUM = Control EP Num, DPID = D0.
+ */
+
+ case USB_GRXSTSD_PKTSTS_SETUPRECVD:
+ {
+ uint16_t datlen;
+
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SETUPRECVD), epphy);
+
+ /* Read EP0 setup data. NOTE: If multiple SETUP packets are received,
+ * the last one overwrites the previous setup packets and only that
+ * last SETUP packet will be processed.
+ */
+
+ efm32_rxfifo_read(&priv->epout[EP0], (FAR uint8_t*)&priv->ctrlreq,
+ USB_SIZEOF_CTRLREQ);
+
+ /* Was this an IN or an OUT SETUP packet. If it is an OUT SETUP,
+ * then we need to wait for the completion of the data phase to
+ * process the setup command. If it is an IN SETUP packet, then
+ * we must processing the command BEFORE we enter the DATA phase.
+ *
+ * If the data associated with the OUT SETUP packet is zero length,
+ * then, of course, we don't need to wait.
+ */
+
+ datlen = GETUINT16(priv->ctrlreq.len);
+ if (USB_REQ_ISOUT(priv->ctrlreq.type) && datlen > 0)
+ {
+ /* Clear NAKSTS so that we can receive the data */
+
+ regval = efm32_getreg(EFM32_USB_DOEP0CTL);
+ regval |= USB_DOEP0CTL_CNAK;
+ efm32_putreg(regval, EFM32_USB_DOEP0CTL);
+
+ /* Wait for the data phase. */
+
+ priv->ep0state = EP0STATE_SETUP_OUT;
+ }
+ else
+ {
+ /* We can process the setup data as soon as SETUP done word is
+ * popped of the RxFIFO.
+ */
+
+ priv->ep0state = EP0STATE_SETUP_READY;
+ }
+ }
+ break;
+
+ default:
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS),
+ (regval & _USB_GRXSTSD_PKTSTS_MASK) >> _USB_GRXSTSD_PKTSTS_SHIFT);
+ }
+ break;
+ }
+
+ /* Enable the Rx Status Queue Level interrupt */
+
+ regval = efm32_getreg(EFM32_USB_GINTMSK);
+ regval |= USB_GINT_RXFLVL;
+ efm32_putreg(regval, EFM32_USB_GINTMSK);
+}
+
+/*******************************************************************************
+ * Name: efm32_enuminterrupt
+ *
+ * Description:
+ * Enumeration done interrupt
+ *
+ *******************************************************************************/
+
+static inline void efm32_enuminterrupt(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t regval;
+
+ /* Activate EP0 */
+
+ efm32_ep0in_activate();
+
+ /* Set USB turn-around time for the full speed device with internal PHY interface. */
+
+ regval = efm32_getreg(EFM32_USB_GUSBCFG);
+ regval &= ~_USB_GUSBCFG_TRDT_MASK;
+ regval |= USB_GUSBCFG_TRDT(5);
+ efm32_putreg(regval, EFM32_USB_GUSBCFG);
+}
+
+/*******************************************************************************
+ * Name: efm32_isocininterrupt
+ *
+ * Description:
+ * Incomplete isochronous IN transfer interrupt. Assertion of the incomplete
+ * isochronous IN transfer interrupt indicates an incomplete isochronous IN
+ * transfer on at least one of the isochronous IN endpoints.
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+static inline void efm32_isocininterrupt(FAR struct efm32_usbdev_s *priv)
+{
+ int i;
+
+ /* The application must read the endpoint control register for all isochronous
+ * IN endpoints to detect endpoints with incomplete IN data transfers.
+ */
+
+ for (i = 0; i < EFM32_NENDPOINTS; i++)
+ {
+ /* Is this an isochronous IN endpoint? */
+
+ privep = &priv->epin[i];
+ if (privep->eptype != USB_EP_ATTR_XFER_ISOC)
+ {
+ /* No... keep looking */
+
+ continue;
+ }
+
+ /* Is there an active read request on the isochronous OUT endpoint? */
+
+ if (!privep->active)
+ {
+ /* No.. the endpoint is not actively transmitting data */
+
+ continue;
+ }
+
+ /* Check if this is the endpoint that had the incomplete transfer */
+
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ doepctl = efm32_getreg(regaddr);
+ dsts = efm32_getreg(EFM32_USB_DSTS);
+
+ /* EONUM = 0:even frame, 1:odd frame
+ * SOFFN = Frame number of the received SOF
+ */
+
+ eonum = ((doepctl & USB_DIEPCTL_EONUM) != 0);
+ soffn = ((dsts & USB_DSTS_SOFFN0) != 0);
+
+ if (eonum != soffn)
+ {
+ /* Not this endpoint */
+
+ continue;
+ }
+
+ /* For isochronous IN endpoints with incomplete transfers,
+ * the application must discard the data in the memory and
+ * disable the endpoint.
+ */
+
+ efm32_req_complete(privep, -EIO);
+#warning "Will clear USB_DIEPCTL_USBAEP too"
+ efm32_epin_disable(privep);
+ break;
+ }
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_isocoutinterrupt
+ *
+ * Description:
+ * Incomplete periodic transfer interrupt
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+static inline void efm32_isocoutinterrupt(FAR struct efm32_usbdev_s *priv)
+{
+ FAR struct efm32_ep_s *privep;
+ FAR struct efm32_req_s *privreq;
+ uint32_t regaddr;
+ uint32_t doepctl;
+ uint32_t dsts;
+ bool eonum;
+ bool soffn;
+
+ /* When it receives an IISOOXFR interrupt, the application must read the
+ * control registers of all isochronous OUT endpoints to determine which
+ * endpoints had an incomplete transfer in the current microframe. An
+ * endpoint transfer is incomplete if both the following conditions are true:
+ *
+ * DOEPCTLx:EONUM = DSTS:SOFFN[0], and
+ * DOEPCTLx:EPENA = 1
+ */
+
+ for (i = 0; i < EFM32_NENDPOINTS; i++)
+ {
+ /* Is this an isochronous OUT endpoint? */
+
+ privep = &priv->epout[i];
+ if (privep->eptype != USB_EP_ATTR_XFER_ISOC)
+ {
+ /* No... keep looking */
+
+ continue;
+ }
+
+ /* Is there an active read request on the isochronous OUT endpoint? */
+
+ if (!privep->active)
+ {
+ /* No.. the endpoint is not actively transmitting data */
+
+ continue;
+ }
+
+ /* Check if this is the endpoint that had the incomplete transfer */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ doepctl = efm32_getreg(regaddr);
+ dsts = efm32_getreg(EFM32_USB_DSTS);
+
+ /* EONUM = 0:even frame, 1:odd frame
+ * SOFFN = Frame number of the received SOF
+ */
+
+ eonum = ((doepctl & USB_DOEPCTL_EONUM) != 0);
+ soffn = ((dsts & USB_DSTS_SOFFN0) != 0);
+
+ if (eonum != soffn)
+ {
+ /* Not this endpoint */
+
+ continue;
+ }
+
+ /* For isochronous OUT endpoints with incomplete transfers,
+ * the application must discard the data in the memory and
+ * disable the endpoint.
+ */
+
+ efm32_req_complete(privep, -EIO);
+#warning "Will clear USB_DOEPCTL_USBAEP too"
+ efm32_epout_disable(privep);
+ break;
+ }
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_sessioninterrupt
+ *
+ * Description:
+ * Session request/new session detected interrupt
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBDEV_VBUSSENSING
+static inline void efm32_sessioninterrupt(FAR struct efm32_usbdev_s *priv)
+{
+#warning "Missing logic"
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_otginterrupt
+ *
+ * Description:
+ * OTG interrupt
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBDEV_VBUSSENSING
+static inline void efm32_otginterrupt(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t regval;
+
+ /* Check for session end detected */
+
+ regval = efm32_getreg(EFM32_USB_GOTGINT);
+ if ((regval & OTGFS_GOTGINT_SEDET) != 0)
+ {
+#warning "Missing logic"
+ }
+
+ /* Clear OTG interrupt */
+
+ efm32_putreg(retval, EFM32_USB_GOTGINT);
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_usbinterrupt
+ *
+ * Description:
+ * USB interrupt handler
+ *
+ *******************************************************************************/
+
+static int efm32_usbinterrupt(int irq, FAR void *context)
+{
+ /* At present, there is only a single OTG FS device support. Hence it is
+ * pre-allocated as g_otgfsdev. However, in most code, the private data
+ * structure will be referenced using the 'priv' pointer (rather than the
+ * global data) in order to simplify any future support for multiple devices.
+ */
+
+ FAR struct efm32_usbdev_s *priv = &g_otgfsdev;
+ uint32_t regval;
+
+ usbtrace(TRACE_INTENTRY(EFM32_TRACEINTID_USB), 0);
+
+ /* Assure that we are in device mode */
+
+ DEBUGASSERT((efm32_getreg(EFM32_USB_GINTSTS) & USB_GINTSTS_CMOD) == USB_GINTSTS_DEVMODE);
+
+ /* Get the state of all enabled interrupts. We will do this repeatedly
+ * some interrupts (like RXFLVL) will generate additional interrupting
+ * events.
+ */
+
+ for (;;)
+ {
+ /* Get the set of pending, un-masked interrupts */
+
+ regval = efm32_getreg(EFM32_USB_GINTSTS);
+ regval &= efm32_getreg(EFM32_USB_GINTMSK);
+
+ /* Break out of the loop when there are no further pending (and
+ * unmasked) interrupts to be processes.
+ */
+
+ if (regval == 0)
+ {
+ break;
+ }
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_INTPENDING), (uint16_t)regval);
+
+ /* OUT endpoint interrupt. The core sets this bit to indicate that an
+ * interrupt is pending on one of the OUT endpoints of the core.
+ */
+
+ if ((regval & USB_GINT_OEP) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPOUT), (uint16_t)regval);
+ efm32_epout_interrupt(priv);
+ efm32_putreg(USB_GINT_OEP, EFM32_USB_GINTSTS);
+ }
+
+ /* IN endpoint interrupt. The core sets this bit to indicate that
+ * an interrupt is pending on one of the IN endpoints of the core.
+ */
+
+ if ((regval & USB_GINT_IEP) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_EPIN), (uint16_t)regval);
+ efm32_epin_interrupt(priv);
+ efm32_putreg(USB_GINT_IEP, EFM32_USB_GINTSTS);
+ }
+
+ /* Host/device mode mismatch error interrupt */
+
+#ifdef CONFIG_DEBUG_USB
+ if ((regval & USB_GINT_MMIS) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_MISMATCH), (uint16_t)regval);
+ efm32_putreg(USB_GINT_MMIS, EFM32_USB_GINTSTS);
+ }
+#endif
+
+ /* Resume/remote wakeup detected interrupt */
+
+ if ((regval & USB_GINT_WKUP) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_WAKEUP), (uint16_t)regval);
+ efm32_resumeinterrupt(priv);
+ efm32_putreg(USB_GINT_WKUP, EFM32_USB_GINTSTS);
+ }
+
+ /* USB suspend interrupt */
+
+ if ((regval & USB_GINT_USBSUSP) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SUSPEND), (uint16_t)regval);
+ efm32_suspendinterrupt(priv);
+ efm32_putreg(USB_GINT_USBSUSP, EFM32_USB_GINTSTS);
+ }
+
+ /* Start of frame interrupt */
+
+#ifdef CONFIG_USBDEV_SOFINTERRUPT
+ if ((regval & USB_GINT_SOF) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SOF), (uint16_t)regval);
+ efm32_putreg(USB_GINT_SOF, EFM32_USB_GINTSTS);
+ }
+#endif
+
+ /* RxFIFO non-empty interrupt. Indicates that there is at least one
+ * packet pending to be read from the RxFIFO.
+ */
+
+ if ((regval & USB_GINT_RXFLVL) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_RXFIFO), (uint16_t)regval);
+ efm32_rxinterrupt(priv);
+ efm32_putreg(USB_GINT_RXFLVL, EFM32_USB_GINTSTS);
+ }
+
+ /* USB reset interrupt */
+
+ if ((regval & USB_GINT_USBRST) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_DEVRESET), (uint16_t)regval);
+
+ /* Perform the device reset */
+
+ efm32_usbreset(priv);
+ usbtrace(TRACE_INTEXIT(EFM32_TRACEINTID_USB), 0);
+ efm32_putreg(USB_GINT_USBRST, EFM32_USB_GINTSTS);
+ return OK;
+ }
+
+ /* Enumeration done interrupt */
+
+ if ((regval & USB_GINT_ENUMDNE) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_ENUMDNE), (uint16_t)regval);
+ efm32_enuminterrupt(priv);
+ efm32_putreg(USB_GINT_ENUMDNE, EFM32_USB_GINTSTS);
+ }
+
+ /* Incomplete isochronous IN transfer interrupt. When the core finds
+ * non-empty any of the isochronous IN endpoint FIFOs scheduled for
+ * the current frame non-empty, the core generates an IISOIXFR
+ * interrupt.
+ */
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+ if ((regval & USB_GINT_IISOIXFR) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_IISOIXFR), (uint16_t)regval);
+ efm32_isocininterrupt(priv);
+ efm32_putreg(USB_GINT_IISOIXFR, EFM32_USB_GINTSTS);
+ }
+
+ /* Incomplete isochronous OUT transfer. For isochronous OUT
+ * endpoints, the XFRC interrupt may not always be asserted. If the
+ * core drops isochronous OUT data packets, the application could fail
+ * to detect the XFRC interrupt. The incomplete Isochronous OUT data
+ * interrupt indicates that an XFRC interrupt was not asserted on at
+ * least one of the isochronous OUT endpoints. At this point, the
+ * endpoint with the incomplete transfer remains enabled, but no active
+ * transfers remain in progress on this endpoint on the USB.
+ */
+
+ if ((regval & USB_GINT_IISOOXFR) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_IISOOXFR), (uint16_t)regval);
+ efm32_isocoutinterrupt(priv);
+ efm32_putreg(USB_GINT_IISOOXFR, EFM32_USB_GINTSTS);
+ }
+#endif
+
+ /* Session request/new session detected interrupt */
+
+#ifdef CONFIG_USBDEV_VBUSSENSING
+ if ((regval & USB_GINT_SRQ) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_SRQ), (uint16_t)regval);
+ efm32_sessioninterrupt(priv);
+ efm32_putreg(USB_GINT_SRQ, EFM32_USB_GINTSTS);
+ }
+
+ /* OTG interrupt */
+
+ if ((regval & USB_GINT_OTG) != 0)
+ {
+ usbtrace(TRACE_INTDECODE(EFM32_TRACEINTID_OTG), (uint16_t)regval);
+ efm32_otginterrupt(priv);
+ efm32_putreg(USB_GINT_OTG, EFM32_USB_GINTSTS);
+ }
+#endif
+ }
+
+ usbtrace(TRACE_INTEXIT(EFM32_TRACEINTID_USB), 0);
+ return OK;
+}
+
+/*******************************************************************************
+ * Endpoint operations
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: efm32_enablegonak
+ *
+ * Description:
+ * Enable global OUT NAK mode
+ *
+ *******************************************************************************/
+
+static void efm32_enablegonak(FAR struct efm32_ep_s *privep)
+{
+ uint32_t regval;
+
+ /* First, make sure that there is no GNOAKEFF interrupt pending. */
+
+#if 0
+ efm32_putreg(USB_GINT_GONAKEFF, EFM32_USB_GINTSTS);
+#endif
+
+ /* Enable Global OUT NAK mode in the core. */
+
+ regval = efm32_getreg(EFM32_USB_DCTL);
+ regval |= USB_DCTL_SGONAK;
+ efm32_putreg(regval, EFM32_USB_DCTL);
+
+#if 0
+ /* Wait for the GONAKEFF interrupt that indicates that the OUT NAK
+ * mode is in effect. When the interrupt handler pops the OUTNAK word
+ * from the RxFIFO, the core sets the GONAKEFF interrupt.
+ */
+
+ while ((efm32_getreg(EFM32_USB_GINTSTS) & USB_GINT_GONAKEFF) == 0);
+ efm32_putreg(USB_GINT_GONAKEFF, EFM32_USB_GINTSTS);
+
+#else
+ /* Since we are in the interrupt handler, we cannot wait inline for the
+ * GONAKEFF because it cannot occur until service th RXFLVL global interrupt
+ * and pop the OUTNAK word from the RxFIFO.
+ *
+ * Perhaps it is sufficient to wait for Global OUT NAK status to be reported
+ * in OTGFS DCTL register?
+ */
+
+ while ((efm32_getreg(EFM32_USB_DCTL) & USB_DCTL_GONSTS) == 0);
+#endif
+}
+
+/*******************************************************************************
+ * Name: efm32_disablegonak
+ *
+ * Description:
+ * Disable global OUT NAK mode
+ *
+ *******************************************************************************/
+
+static void efm32_disablegonak(FAR struct efm32_ep_s *privep)
+{
+ uint32_t regval;
+
+ /* Set the "Clear the Global OUT NAK bit" to disable global OUT NAK mode */
+
+ regval = efm32_getreg(EFM32_USB_DCTL);
+ regval |= USB_DCTL_CGONAK;
+ efm32_putreg(regval, EFM32_USB_DCTL);
+}
+
+/*******************************************************************************
+ * Name: efm32_epout_configure
+ *
+ * Description:
+ * Configure an OUT endpoint, making it usable
+ *
+ * Input Parameters:
+ * privep - a pointer to an internal endpoint structure
+ * eptype - The type of the endpoint
+ * maxpacket - The max packet size of the endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_epout_configure(FAR struct efm32_ep_s *privep, uint8_t eptype,
+ uint16_t maxpacket)
+{
+ uint32_t mpsiz;
+ uint32_t regaddr;
+ uint32_t regval;
+
+ usbtrace(TRACE_EPCONFIGURE, privep->epphy);
+
+ /* For EP0, the packet size is encoded */
+
+ if (privep->epphy == EP0)
+ {
+ DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
+
+ /* Map the size in bytes to the encoded value in the register */
+
+ switch (maxpacket)
+ {
+ case 8:
+ mpsiz = USB_DOEP0CTL_MPS_8;
+ break;
+
+ case 16:
+ mpsiz = USB_DOEP0CTL_MPS_16;
+ break;
+
+ case 32:
+ mpsiz = USB_DOEP0CTL_MPS_32;
+ break;
+
+ case 64:
+ mpsiz = USB_DOEP0CTL_MPS_64;
+ break;
+
+ default:
+ udbg("Unsupported maxpacket: %d\n", maxpacket);
+ return -EINVAL;
+ }
+ }
+
+ /* For other endpoints, the packet size is in bytes */
+
+ else
+ {
+ mpsiz = (maxpacket << _USB_DOEPCTL_MPS_SHIFT);
+ }
+
+ /* If the endpoint is already active don't change the endpoint control
+ * register.
+ */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ if ((regval & USB_DOEPCTL_USBAEP) == 0)
+ {
+ if (regval & USB_DOEPCTL_NAKSTS)
+ {
+ regval |= USB_DOEPCTL_CNAK;
+ }
+
+ regval &= ~(_USB_DOEPCTL_MPS_MASK | _USB_DOEPCTL_EPTYP_MASK);
+ regval |= mpsiz;
+ regval |= (eptype << _USB_DOEPCTL_EPTYP_SHIFT);
+ regval |= (USB_DOEPCTL_SD0PID | USB_DOEPCTL_USBAEP);
+ efm32_putreg(regval, regaddr);
+
+ /* Save the endpoint configuration */
+
+ privep->ep.maxpacket = maxpacket;
+ privep->eptype = eptype;
+ privep->stalled = false;
+ }
+
+ /* Enable the interrupt for this endpoint */
+
+ regval = efm32_getreg(EFM32_USB_DAINTMSK);
+ regval |= USB_DAINT_OEP(privep->epphy);
+ efm32_putreg(regval, EFM32_USB_DAINTMSK);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_epin_configure
+ *
+ * Description:
+ * Configure an IN endpoint, making it usable
+ *
+ * Input Parameters:
+ * privep - a pointer to an internal endpoint structure
+ * eptype - The type of the endpoint
+ * maxpacket - The max packet size of the endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_epin_configure(FAR struct efm32_ep_s *privep, uint8_t eptype,
+ uint16_t maxpacket)
+{
+ uint32_t mpsiz;
+ uint32_t regaddr;
+ uint32_t regval;
+
+ usbtrace(TRACE_EPCONFIGURE, privep->epphy);
+
+ /* For EP0, the packet size is encoded */
+
+ if (privep->epphy == EP0)
+ {
+ DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
+
+ /* Map the size in bytes to the encoded value in the register */
+
+ switch (maxpacket)
+ {
+ case 8:
+ mpsiz = _USB_DIEP0CTL_MPS_8;
+ break;
+
+ case 16:
+ mpsiz = _USB_DIEP0CTL_MPS_16;
+ break;
+
+ case 32:
+ mpsiz = _USB_DIEP0CTL_MPS_32;
+ break;
+
+ case 64:
+ mpsiz = _USB_DIEP0CTL_MPS_64;
+ break;
+
+ default:
+ udbg("Unsupported maxpacket: %d\n", maxpacket);
+ return -EINVAL;
+ }
+ }
+
+ /* For other endpoints, the packet size is in bytes */
+
+ else
+ {
+ mpsiz = (maxpacket << _USB_DIEPCTL_MPS_SHIFT);
+ }
+
+
+ /* If the endpoint is already active don't change the endpoint control
+ * register.
+ */
+
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ if ((regval & USB_DIEPCTL_USBAEP) == 0)
+ {
+ if (regval & USB_DIEPCTL_NAKSTS)
+ {
+ regval |= USB_DIEPCTL_CNAK;
+ }
+
+ regval &= ~(_USB_DIEPCTL_MPS_MASK | _USB_DIEPCTL_EPTYP_MASK | _USB_DIEPCTL_TXFNUM_MASK);
+ regval |= mpsiz;
+ regval |= (eptype << _USB_DIEPCTL_EPTYP_SHIFT);
+ regval |= (eptype << _USB_DIEPCTL_TXFNUM_SHIFT);
+ regval |= (USB_DIEPCTL_SD0PID | USB_DIEPCTL_USBAEP);
+ efm32_putreg(regval, regaddr);
+
+ /* Save the endpoint configuration */
+
+ privep->ep.maxpacket = maxpacket;
+ privep->eptype = eptype;
+ privep->stalled = false;
+ }
+
+ /* Enable the interrupt for this endpoint */
+
+ regval = efm32_getreg(EFM32_USB_DAINTMSK);
+ regval |= USB_DAINT_IEP(privep->epphy);
+ efm32_putreg(regval, EFM32_USB_DAINTMSK);
+
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_configure
+ *
+ * Description:
+ * Configure endpoint, making it usable
+ *
+ * Input Parameters:
+ * ep - the struct usbdev_ep_s instance obtained from allocep()
+ * desc - A struct usb_epdesc_s instance describing the endpoint
+ * last - true if this this last endpoint to be configured. Some hardware
+ * needs to take special action when all of the endpoints have been
+ * configured.
+ *
+ *******************************************************************************/
+
+static int efm32_ep_configure(FAR struct usbdev_ep_s *ep,
+ FAR const struct usb_epdesc_s *desc,
+ bool last)
+{
+ FAR struct efm32_ep_s *privep = (FAR struct efm32_ep_s *)ep;
+ uint16_t maxpacket;
+ uint8_t eptype;
+ int ret;
+
+ usbtrace(TRACE_EPCONFIGURE, privep->epphy);
+ DEBUGASSERT(desc->addr == ep->eplog);
+
+ /* Initialize EP capabilities */
+
+ maxpacket = GETUINT16(desc->mxpacketsize);
+ eptype = desc->attr & _USB_EP_ATTR_XFERTYPE_MASK;
+
+ /* Setup Endpoint Control Register */
+
+ if (privep->isin)
+ {
+ ret = efm32_epin_configure(privep, eptype, maxpacket);
+ }
+ else
+ {
+ ret = efm32_epout_configure(privep, eptype, maxpacket);
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0_configure
+ *
+ * Description:
+ * Reset Usb engine
+ *
+ *******************************************************************************/
+
+static void efm32_ep0_configure(FAR struct efm32_usbdev_s *priv)
+{
+ /* Enable EP0 IN and OUT */
+
+ (void)efm32_epin_configure(&priv->epin[EP0], USB_EP_ATTR_XFER_CONTROL,
+ CONFIG_USBDEV_EP0_MAXSIZE);
+ (void)efm32_epout_configure(&priv->epout[EP0], USB_EP_ATTR_XFER_CONTROL,
+ CONFIG_USBDEV_EP0_MAXSIZE);
+}
+
+/*******************************************************************************
+ * Name: efm32_epout_disable
+ *
+ * Description:
+ * Diable an OUT endpoint will no longer be used
+ *
+ *******************************************************************************/
+
+static void efm32_epout_disable(FAR struct efm32_ep_s *privep)
+{
+ uint32_t regaddr;
+ uint32_t regval;
+ irqstate_t flags;
+
+ usbtrace(TRACE_EPDISABLE, privep->epphy);
+
+ /* Is this an IN or an OUT endpoint */
+
+ /* Before disabling any OUT endpoint, the application must enable
+ * Global OUT NAK mode in the core.
+ */
+
+ flags = irqsave();
+ efm32_enablegonak(privep);
+
+ /* Disable the required OUT endpoint by setting the EPDIS and SNAK bits
+ * int DOECPTL register.
+ */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval &= ~USB_DOEPCTL_USBAEP;
+ regval |= (USB_DOEPCTL_EPDIS | USB_DOEPCTL_SNAK);
+ efm32_putreg(regval, regaddr);
+
+ /* Wait for the EPDISD interrupt which indicates that the OUT
+ * endpoint is completely disabled.
+ */
+
+#if 0 /* Doesn't happen */
+ regaddr = EFM32_USB_DOEPINT(privep->epphy);
+ while ((efm32_getreg(regaddr) & USB_DOEPINT_EPDISD) == 0);
+#else
+ /* REVISIT: */
+ up_udelay(10);
+#endif
+
+ /* Clear the EPDISD interrupt indication */
+
+ efm32_putreg(USB_DOEPINT_EPDISD, EFM32_USB_DOEPINT(privep->epphy));
+
+ /* Then disble the Global OUT NAK mode to continue receiving data
+ * from other non-disabled OUT endpoints.
+ */
+
+ efm32_disablegonak(privep);
+
+ /* Disable endpoint interrupts */
+
+ regval = efm32_getreg(EFM32_USB_DAINTMSK);
+ regval &= ~USB_DAINT_OEP(privep->epphy);
+ efm32_putreg(regval, EFM32_USB_DAINTMSK);
+
+ /* Cancel any queued read requests */
+
+ efm32_req_cancel(privep, -ESHUTDOWN);
+
+ irqrestore(flags);
+}
+
+/*******************************************************************************
+ * Name: efm32_epin_disable
+ *
+ * Description:
+ * Disable an IN endpoint when it will no longer be used
+ *
+ *******************************************************************************/
+
+static void efm32_epin_disable(FAR struct efm32_ep_s *privep)
+{
+ uint32_t regaddr;
+ uint32_t regval;
+ irqstate_t flags;
+
+ usbtrace(TRACE_EPDISABLE, privep->epphy);
+
+ /* After USB reset, the endpoint will already be deactivated by the
+ * hardware. Trying to disable again will just hang in the wait.
+ */
+
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ if ((regval & USB_DIEPCTL_USBAEP) == 0)
+ {
+ return;
+ }
+
+ /* This INEPNE wait logic is suggested by reference manual, but seems
+ * to get stuck to infinite loop.
+ */
+
+#if 0
+ /* Make sure that there is no pending IPEPNE interrupt (because we are
+ * to poll this bit below).
+ */
+
+ efm32_putreg(USB_DIEPINT_INEPNE, EFM32_USB_DIEPINT(privep->epphy));
+
+ /* Set the endpoint in NAK mode */
+
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval &= ~USB_DIEPCTL_USBAEP;
+ regval |= (USB_DIEPCTL_EPDIS | USB_DIEPCTL_SNAK);
+ efm32_putreg(regval, regaddr);
+
+ /* Wait for the INEPNE interrupt that indicates that we are now in NAK mode */
+
+ regaddr = EFM32_USB_DIEPINT(privep->epphy);
+ while ((efm32_getreg(regaddr) & USB_DIEPINT_INEPNE) == 0);
+
+ /* Clear the INEPNE interrupt indication */
+
+ efm32_putreg(USB_DIEPINT_INEPNE, regaddr);
+#endif
+
+ /* Deactivate and disable the endpoint by setting the EPDIS and SNAK bits
+ * the DIEPCTLx register.
+ */
+
+ flags = irqsave();
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval &= ~USB_DIEPCTL_USBAEP;
+ regval |= (USB_DIEPCTL_EPDIS | USB_DIEPCTL_SNAK);
+ efm32_putreg(regval, regaddr);
+
+ /* Wait for the EPDISD interrupt which indicates that the IN
+ * endpoint is completely disabled.
+ */
+
+ regaddr = EFM32_USB_DIEPINT(privep->epphy);
+ while ((efm32_getreg(regaddr) & USB_DIEPINT_EPDISD) == 0);
+
+ /* Clear the EPDISD interrupt indication */
+
+ efm32_putreg(USB_DIEPINT_EPDISD, efm32_getreg(regaddr));
+
+ /* Flush any data remaining in the TxFIFO */
+
+ efm32_txfifo_flush(USB_GRSTCTL_TXFNUM_D(privep->epphy));
+
+ /* Disable endpoint interrupts */
+
+ regval = efm32_getreg(EFM32_USB_DAINTMSK);
+ regval &= ~USB_DAINT_IEP(privep->epphy);
+ efm32_putreg(regval, EFM32_USB_DAINTMSK);
+
+ /* Cancel any queued write requests */
+
+ efm32_req_cancel(privep, -ESHUTDOWN);
+ irqrestore(flags);
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_disable
+ *
+ * Description:
+ * The endpoint will no longer be used
+ *
+ *******************************************************************************/
+
+static int efm32_ep_disable(FAR struct usbdev_ep_s *ep)
+{
+ FAR struct efm32_ep_s *privep = (FAR struct efm32_ep_s *)ep;
+
+#ifdef CONFIG_DEBUG
+ if (!ep)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+
+ usbtrace(TRACE_EPDISABLE, privep->epphy);
+
+ /* Is this an IN or an OUT endpoint */
+
+ if (privep->isin)
+ {
+ /* Disable the IN endpoint */
+
+ efm32_epin_disable(privep);
+ }
+ else
+ {
+ /* Disable the OUT endpoint */
+
+ efm32_epout_disable(privep);
+ }
+
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_allocreq
+ *
+ * Description:
+ * Allocate an I/O request
+ *
+ *******************************************************************************/
+
+static FAR struct usbdev_req_s *efm32_ep_allocreq(FAR struct usbdev_ep_s *ep)
+{
+ FAR struct efm32_req_s *privreq;
+
+#ifdef CONFIG_DEBUG
+ if (!ep)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ return NULL;
+ }
+#endif
+
+ usbtrace(TRACE_EPALLOCREQ, ((FAR struct efm32_ep_s *)ep)->epphy);
+
+ privreq = (FAR struct efm32_req_s *)kmm_malloc(sizeof(struct efm32_req_s));
+ if (!privreq)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_ALLOCFAIL), 0);
+ return NULL;
+ }
+
+ memset(privreq, 0, sizeof(struct efm32_req_s));
+ return &privreq->req;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_freereq
+ *
+ * Description:
+ * Free an I/O request
+ *
+ *******************************************************************************/
+
+static void efm32_ep_freereq(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
+{
+ FAR struct efm32_req_s *privreq = (FAR struct efm32_req_s *)req;
+
+#ifdef CONFIG_DEBUG
+ if (!ep || !req)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ return;
+ }
+#endif
+
+ usbtrace(TRACE_EPFREEREQ, ((FAR struct efm32_ep_s *)ep)->epphy);
+ kmm_free(privreq);
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_allocbuffer
+ *
+ * Description:
+ * Allocate an I/O buffer
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBDEV_DMA
+static void *efm32_ep_allocbuffer(FAR struct usbdev_ep_s *ep, unsigned bytes)
+{
+ usbtrace(TRACE_EPALLOCBUFFER, privep->epphy);
+
+#ifdef CONFIG_USBDEV_DMAMEMORY
+ return usbdev_dma_alloc(bytes);
+#else
+ return kmm_malloc(bytes);
+#endif
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_ep_freebuffer
+ *
+ * Description:
+ * Free an I/O buffer
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_USBDEV_DMA
+static void efm32_ep_freebuffer(FAR struct usbdev_ep_s *ep, FAR void *buf)
+{
+ usbtrace(TRACE_EPFREEBUFFER, privep->epphy);
+
+#ifdef CONFIG_USBDEV_DMAMEMORY
+ usbdev_dma_free(buf);
+#else
+ kmm_free(buf);
+#endif
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_ep_submit
+ *
+ * Description:
+ * Submit an I/O request to the endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_ep_submit(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
+{
+ FAR struct efm32_req_s *privreq = (FAR struct efm32_req_s *)req;
+ FAR struct efm32_ep_s *privep = (FAR struct efm32_ep_s *)ep;
+ FAR struct efm32_usbdev_s *priv;
+ irqstate_t flags;
+ int ret = OK;
+
+ /* Some sanity checking */
+
+#ifdef CONFIG_DEBUG
+ if (!req || !req->callback || !req->buf || !ep)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ ullvdbg("req=%p callback=%p buf=%p ep=%p\n", req, req->callback, req->buf, ep);
+ return -EINVAL;
+ }
+#endif
+
+ usbtrace(TRACE_EPSUBMIT, privep->epphy);
+ priv = privep->dev;
+
+#ifdef CONFIG_DEBUG
+ if (!priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_NOTCONFIGURED), priv->usbdev.speed);
+ return -ESHUTDOWN;
+ }
+#endif
+
+ /* Handle the request from the class driver */
+
+ req->result = -EINPROGRESS;
+ req->xfrd = 0;
+
+ /* Disable Interrupts */
+
+ flags = irqsave();
+
+ /* If we are stalled, then drop all requests on the floor */
+
+ if (privep->stalled)
+ {
+ ret = -EBUSY;
+ }
+ else
+ {
+ /* Add the new request to the request queue for the endpoint. */
+
+ if (efm32_req_addlast(privep, privreq) && !privep->active)
+ {
+ /* If a request was added to an IN endpoint, then attempt to send
+ * the request data buffer now.
+ */
+
+ if (privep->isin)
+ {
+ usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len);
+
+ /* If the endpoint is not busy with another write request,
+ * then process the newly received write request now.
+ */
+
+ if (!privep->active)
+ {
+ efm32_epin_request(priv, privep);
+ }
+ }
+
+ /* If the request was added to an OUT endoutput, then attempt to
+ * setup a read into the request data buffer now (this will, of
+ * course, fail if there is already a read in place).
+ */
+
+ else
+ {
+ usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len);
+ efm32_epout_request(priv, privep);
+ }
+ }
+ }
+
+ irqrestore(flags);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_cancel
+ *
+ * Description:
+ * Cancel an I/O request previously sent to an endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_ep_cancel(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
+{
+ FAR struct efm32_ep_s *privep = (FAR struct efm32_ep_s *)ep;
+ irqstate_t flags;
+
+#ifdef CONFIG_DEBUG
+ if (!ep || !req)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+
+ usbtrace(TRACE_EPCANCEL, privep->epphy);
+
+ flags = irqsave();
+
+ /* FIXME: if the request is the first, then we need to flush the EP
+ * otherwise just remove it from the list
+ *
+ * but ... all other implementations cancel all requests ...
+ */
+
+ efm32_req_cancel(privep, -ESHUTDOWN);
+ irqrestore(flags);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_epout_setstall
+ *
+ * Description:
+ * Stall an OUT endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_epout_setstall(FAR struct efm32_ep_s *privep)
+{
+#if 1
+ /* This implementation follows the requirements from the EFM32 F4 reference
+ * manual.
+ */
+
+ uint32_t regaddr;
+ uint32_t regval;
+
+ /* Put the core in the Global OUT NAK mode */
+
+ efm32_enablegonak(privep);
+
+ /* Disable and STALL the OUT endpoint by setting the EPDIS and STALL bits
+ * in the DOECPTL register.
+ */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval |= (USB_DOEPCTL_EPDIS | USB_DOEPCTL_STALL);
+ efm32_putreg(regval, regaddr);
+
+ /* Wait for the EPDISD interrupt which indicates that the OUT
+ * endpoint is completely disabled.
+ */
+
+#if 0 /* Doesn't happen */
+ regaddr = EFM32_USB_DOEPINT(privep->epphy);
+ while ((efm32_getreg(regaddr) & USB_DOEPINT_EPDISD) == 0);
+#else
+ /* REVISIT: */
+ up_udelay(10);
+#endif
+
+ /* Disable Global OUT NAK mode */
+
+ efm32_disablegonak(privep);
+
+ /* The endpoint is now stalled */
+
+ privep->stalled = true;
+ return OK;
+#else
+ /* This implementation follows the STMicro code example. */
+ /* REVISIT: */
+
+ uint32_t regaddr;
+ uint32_t regval;
+
+ /* Stall the OUT endpoint by setting the STALL bit in the DOECPTL register. */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+ regval |= USB_DOEPCTL_STALL;
+ efm32_putreg(regval, regaddr);
+
+ /* The endpoint is now stalled */
+
+ privep->stalled = true;
+ return OK;
+#endif
+}
+
+/*******************************************************************************
+ * Name: efm32_epin_setstall
+ *
+ * Description:
+ * Stall an IN endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_epin_setstall(FAR struct efm32_ep_s *privep)
+{
+ uint32_t regaddr;
+ uint32_t regval;
+
+ /* Get the IN endpoint device control register */
+
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ regval = efm32_getreg(regaddr);
+
+ /* Then stall the endpoint */
+
+ regval |= USB_DIEPCTL_STALL;
+ efm32_putreg(regval, regaddr);
+
+ /* The endpoint is now stalled */
+
+ privep->stalled = true;
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_setstall
+ *
+ * Description:
+ * Stall an endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_ep_setstall(FAR struct efm32_ep_s *privep)
+{
+ usbtrace(TRACE_EPSTALL, privep->epphy);
+
+ /* Is this an IN endpoint? */
+
+ if (privep->isin == 1)
+ {
+ return efm32_epin_setstall(privep);
+ }
+ else
+ {
+ return efm32_epout_setstall(privep);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_clrstall
+ *
+ * Description:
+ * Resume a stalled endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_ep_clrstall(FAR struct efm32_ep_s *privep)
+{
+ uint32_t regaddr;
+ uint32_t regval;
+ uint32_t stallbit;
+ uint32_t data0bit;
+
+ usbtrace(TRACE_EPRESUME, privep->epphy);
+
+ /* Is this an IN endpoint? */
+
+ if (privep->isin == 1)
+ {
+ /* Clear the stall bit in the IN endpoint device control register */
+
+ regaddr = EFM32_USB_DIEPCTL(privep->epphy);
+ stallbit = USB_DIEPCTL_STALL;
+ data0bit = USB_DIEPCTL_SD0PID;
+ }
+ else
+ {
+ /* Clear the stall bit in the IN endpoint device control register */
+
+ regaddr = EFM32_USB_DOEPCTL(privep->epphy);
+ stallbit = USB_DOEPCTL_STALL;
+ data0bit = USB_DOEPCTL_SD0PID;
+ }
+
+ /* Clear the stall bit */
+
+ regval = efm32_getreg(regaddr);
+ regval &= ~stallbit;
+
+ /* Set the DATA0 pid for interrupt and bulk endpoints */
+
+ if (privep->eptype == USB_EP_ATTR_XFER_INT ||
+ privep->eptype == USB_EP_ATTR_XFER_BULK)
+ {
+ /* Writing this bit sets the DATA0 PID */
+
+ regval |= data0bit;
+ }
+
+ efm32_putreg(regval, regaddr);
+
+ /* The endpoint is no longer stalled */
+
+ privep->stalled = false;
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_stall
+ *
+ * Description:
+ * Stall or resume an endpoint
+ *
+ *******************************************************************************/
+
+static int efm32_ep_stall(FAR struct usbdev_ep_s *ep, bool resume)
+{
+ FAR struct efm32_ep_s *privep = (FAR struct efm32_ep_s *)ep;
+ irqstate_t flags;
+ int ret;
+
+ /* Set or clear the stall condition as requested */
+
+ flags = irqsave();
+ if (resume)
+ {
+ ret = efm32_ep_clrstall(privep);
+ }
+ else
+ {
+ ret = efm32_ep_setstall(privep);
+ }
+ irqrestore(flags);
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep0_stall
+ *
+ * Description:
+ * Stall endpoint 0
+ *
+ *******************************************************************************/
+
+static void efm32_ep0_stall(FAR struct efm32_usbdev_s *priv)
+{
+ efm32_epin_setstall(&priv->epin[EP0]);
+ efm32_epout_setstall(&priv->epout[EP0]);
+ priv->stalled = true;
+ efm32_ep0out_ctrlsetup(priv);
+}
+
+/*******************************************************************************
+ * Device operations
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: efm32_ep_alloc
+ *
+ * Description:
+ * Allocate an endpoint matching the parameters.
+ *
+ * Input Parameters:
+ * eplog - 7-bit logical endpoint number (direction bit ignored). Zero means
+ * that any endpoint matching the other requirements will suffice. The
+ * assigned endpoint can be found in the eplog field.
+ * in - true: IN (device-to-host) endpoint requested
+ * eptype - Endpoint type. One of {USB_EP_ATTR_XFER_ISOC, USB_EP_ATTR_XFER_BULK,
+ * USB_EP_ATTR_XFER_INT}
+ *
+ *******************************************************************************/
+
+static FAR struct usbdev_ep_s *efm32_ep_alloc(FAR struct usbdev_s *dev,
+ uint8_t eplog, bool in,
+ uint8_t eptype)
+{
+ FAR struct efm32_usbdev_s *priv = (FAR struct efm32_usbdev_s *)dev;
+ uint8_t epavail;
+ irqstate_t flags;
+ int epphy;
+ int epno = 0;
+
+ usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog);
+
+ /* Ignore any direction bits in the logical address */
+
+ epphy = USB_EPNO(eplog);
+
+ /* Get the set of available endpoints depending on the direction */
+
+ flags = irqsave();
+ epavail = priv->epavail[in];
+
+ /* A physical address of 0 means that any endpoint will do */
+
+ if (epphy > 0)
+ {
+ /* Otherwise, we will return the endpoint structure only for the requested
+ * 'logical' endpoint. All of the other checks will still be performed.
+ *
+ * First, verify that the logical endpoint is in the range supported by
+ * by the hardware.
+ */
+
+ if (epphy >= EFM32_NENDPOINTS)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BADEPNO), (uint16_t)epphy);
+ return NULL;
+ }
+
+ /* Remove all of the candidate endpoints from the bitset except for the
+ * this physical endpoint number.
+ */
+
+ epavail &= (1 << epphy);
+ }
+
+ /* Is there an available endpoint? */
+
+ if (epavail)
+ {
+ /* Yes.. Select the lowest numbered endpoint in the set of available
+ * endpoints.
+ */
+
+ for (epno = 1; epno < EFM32_NENDPOINTS; epno++)
+ {
+ uint8_t bit = 1 << epno;
+ if ((epavail & bit) != 0)
+ {
+ /* Mark the endpoint no longer available */
+
+ priv->epavail[in] &= ~(1 << epno);
+
+ /* And return the pointer to the standard endpoint structure */
+
+ irqrestore(flags);
+ return in ? &priv->epin[epno].ep : &priv->epout[epno].ep;
+ }
+ }
+
+ /* We should not get here */
+ }
+
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_NOEP), (uint16_t)eplog);
+ irqrestore(flags);
+ return NULL;
+}
+
+/*******************************************************************************
+ * Name: efm32_ep_free
+ *
+ * Description:
+ * Free the previously allocated endpoint
+ *
+ *******************************************************************************/
+
+static void efm32_ep_free(FAR struct usbdev_s *dev, FAR struct usbdev_ep_s *ep)
+{
+ FAR struct efm32_usbdev_s *priv = (FAR struct efm32_usbdev_s *)dev;
+ FAR struct efm32_ep_s *privep = (FAR struct efm32_ep_s *)ep;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy);
+
+ if (priv && privep)
+ {
+ /* Mark the endpoint as available */
+
+ flags = irqsave();
+ priv->epavail[privep->isin] |= (1 << privep->epphy);
+ irqrestore(flags);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_getframe
+ *
+ * Description:
+ * Returns the current frame number
+ *
+ *******************************************************************************/
+
+static int efm32_getframe(struct usbdev_s *dev)
+{
+ uint32_t regval;
+
+ usbtrace(TRACE_DEVGETFRAME, 0);
+
+ /* Return the last frame number of the last SOF detected by the hardware */
+
+ regval = efm32_getreg(EFM32_USB_DSTS);
+ return (int)((regval & _USB_DSTS_SOFFN_MASK) >> _USB_DSTS_SOFFN_SHIFT);
+}
+
+/*******************************************************************************
+ * Name: efm32_wakeup
+ *
+ * Description:
+ * Exit suspend mode.
+ *
+ *******************************************************************************/
+
+static int efm32_wakeup(struct usbdev_s *dev)
+{
+ FAR struct efm32_usbdev_s *priv = (FAR struct efm32_usbdev_s *)dev;
+ uint32_t regval;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVWAKEUP, 0);
+
+ /* Is wakeup enabled? */
+
+ flags = irqsave();
+ if (priv->wakeup)
+ {
+ /* Yes... is the core suspended? */
+
+ regval = efm32_getreg(EFM32_USB_DSTS);
+ if ((regval & USB_DSTS_SUSPSTS) != 0)
+ {
+ /* Re-start the PHY clock and un-gate USB core clock (HCLK) */
+
+#ifdef CONFIG_USBDEV_LOWPOWER
+ regval = efm32_getreg(EFM32_USB_PCGCCTL);
+ regval &= ~(OTGFS_PCGCCTL_STPPCLK | OTGFS_PCGCCTL_GATEHCLK);
+ efm32_putreg(regval, EFM32_USB_PCGCCTL);
+#endif
+ /* Activate Remote wakeup signaling */
+
+ regval = efm32_getreg(EFM32_USB_DCTL);
+ regval |= USB_DCTL_RWUSIG;
+ efm32_putreg(regval, EFM32_USB_DCTL);
+ up_mdelay(5);
+ regval &= ~USB_DCTL_RWUSIG;
+ efm32_putreg(regval, EFM32_USB_DCTL);
+ }
+ }
+
+ irqrestore(flags);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_selfpowered
+ *
+ * Description:
+ * Sets/clears the device self-powered feature
+ *
+ *******************************************************************************/
+
+static int efm32_selfpowered(struct usbdev_s *dev, bool selfpowered)
+{
+ FAR struct efm32_usbdev_s *priv = (FAR struct efm32_usbdev_s *)dev;
+
+ usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered);
+
+#ifdef CONFIG_DEBUG
+ if (!dev)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ return -ENODEV;
+ }
+#endif
+
+ priv->selfpowered = selfpowered;
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_pullup
+ *
+ * Description:
+ * Software-controlled connect to/disconnect from USB host
+ *
+ *******************************************************************************/
+
+static int efm32_pullup(struct usbdev_s *dev, bool enable)
+{
+ uint32_t regval;
+
+ usbtrace(TRACE_DEVPULLUP, (uint16_t)enable);
+
+ irqstate_t flags = irqsave();
+ regval = efm32_getreg(EFM32_USB_DCTL);
+ if (enable)
+ {
+ /* Connect the device by clearing the soft disconnect bit in the DCTL
+ * register
+ */
+
+ regval &= ~USB_DCTL_SDIS;
+ }
+ else
+ {
+ /* Connect the device by setting the soft disconnect bit in the DCTL
+ * register
+ */
+
+ regval |= USB_DCTL_SDIS;
+ }
+
+ efm32_putreg(regval, EFM32_USB_DCTL);
+ irqrestore(flags);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_setaddress
+ *
+ * Description:
+ * Set the devices USB address
+ *
+ *******************************************************************************/
+
+static void efm32_setaddress(struct efm32_usbdev_s *priv, uint16_t address)
+{
+ uint32_t regval;
+
+ /* Set the device address in the DCFG register */
+
+ regval = efm32_getreg(EFM32_USB_DCFG);
+ regval &= ~_USB_DCFG_DAD_MASK;
+ regval |= ((uint32_t)address << _USB_DCFG_DAD_SHIFT);
+ efm32_putreg(regval, EFM32_USB_DCFG);
+
+ /* Are we now addressed? (i.e., do we have a non-NULL device
+ * address?)
+ */
+
+ if (address != 0)
+ {
+ priv->devstate = DEVSTATE_ADDRESSED;
+ priv->addressed = true;
+ }
+ else
+ {
+ priv->devstate = DEVSTATE_DEFAULT;
+ priv->addressed = false;
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_txfifo_flush
+ *
+ * Description:
+ * Flush the specific TX fifo.
+ *
+ *******************************************************************************/
+
+static int efm32_txfifo_flush(uint32_t txfnum)
+{
+ uint32_t regval;
+ uint32_t timeout;
+
+ /* Initiate the TX FIFO flush operation */
+
+ regval = USB_GRSTCTL_TXFFLSH | txfnum;
+ efm32_putreg(regval, EFM32_USB_GRSTCTL);
+
+ /* Wait for the FLUSH to complete */
+
+ for (timeout = 0; timeout < EFM32_FLUSH_DELAY; timeout++)
+ {
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_TXFFLSH) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Wait for 3 PHY Clocks */
+
+ up_udelay(3);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_rxfifo_flush
+ *
+ * Description:
+ * Flush the RX fifo.
+ *
+ *******************************************************************************/
+
+static int efm32_rxfifo_flush(void)
+{
+ uint32_t regval;
+ uint32_t timeout;
+
+ /* Initiate the RX FIFO flush operation */
+
+ efm32_putreg(USB_GRSTCTL_RXFFLSH, EFM32_USB_GRSTCTL);
+
+ /* Wait for the FLUSH to complete */
+
+ for (timeout = 0; timeout < EFM32_FLUSH_DELAY; timeout++)
+ {
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_RXFFLSH) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Wait for 3 PHY Clocks */
+
+ up_udelay(3);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_swinitialize
+ *
+ * Description:
+ * Initialize all driver data structures.
+ *
+ *******************************************************************************/
+
+static void efm32_swinitialize(FAR struct efm32_usbdev_s *priv)
+{
+ FAR struct efm32_ep_s *privep;
+ int i;
+
+ /* Initialize the device state structure */
+
+ memset(priv, 0, sizeof(struct efm32_usbdev_s));
+
+ priv->usbdev.ops = &g_devops;
+ priv->usbdev.ep0 = &priv->epin[EP0].ep;
+
+ priv->epavail[0] = EFM32_EP_AVAILABLE;
+ priv->epavail[1] = EFM32_EP_AVAILABLE;
+
+ priv->epin[EP0].ep.priv = priv;
+ priv->epout[EP0].ep.priv = priv;
+
+ /* Initialize the endpoint lists */
+
+ for (i = 0; i < EFM32_NENDPOINTS; i++)
+ {
+ /* Set endpoint operations, reference to driver structure (not
+ * really necessary because there is only one controller), and
+ * the physical endpoint number (which is just the index to the
+ * endpoint).
+ */
+
+ privep = &priv->epin[i];
+ privep->ep.ops = &g_epops;
+ privep->dev = priv;
+ privep->isin = 1;
+
+ /* The index, i, is the physical endpoint address; Map this
+ * to a logical endpoint address usable by the class driver.
+ */
+
+ privep->epphy = i;
+ privep->ep.eplog = EFM32_EPPHYIN2LOG(i);
+
+ /* Control until endpoint is activated */
+
+ privep->eptype = USB_EP_ATTR_XFER_CONTROL;
+ privep->ep.maxpacket = CONFIG_USBDEV_EP0_MAXSIZE;
+ }
+
+ /* Initialize the endpoint lists */
+
+ for (i = 0; i < EFM32_NENDPOINTS; i++)
+ {
+ /* Set endpoint operations, reference to driver structure (not
+ * really necessary because there is only one controller), and
+ * the physical endpoint number (which is just the index to the
+ * endpoint).
+ */
+
+ privep = &priv->epout[i];
+ privep->ep.ops = &g_epops;
+ privep->dev = priv;
+
+ /* The index, i, is the physical endpoint address; Map this
+ * to a logical endpoint address usable by the class driver.
+ */
+
+ privep->epphy = i;
+ privep->ep.eplog = EFM32_EPPHYOUT2LOG(i);
+
+ /* Control until endpoint is activated */
+
+ privep->eptype = USB_EP_ATTR_XFER_CONTROL;
+ privep->ep.maxpacket = CONFIG_USBDEV_EP0_MAXSIZE;
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_hwinitialize
+ *
+ * Description:
+ * Configure the OTG FS core for operation.
+ *
+ *******************************************************************************/
+
+static void efm32_hwinitialize(FAR struct efm32_usbdev_s *priv)
+{
+ uint32_t regval;
+ uint32_t timeout;
+ uint32_t address;
+ int i;
+
+ /* "The application must perform the following steps to initialize the core
+ * at device on, power on, or after a mode change from Host to Device.
+ * 1. Program the following fields in USB_DCFG register.
+ * - Device Speed
+ * - NonZero Length Status OUT Handshake
+ * - Periodic Frame Interval
+ * 2. Program the USB_GINTMSK register to unmask the following interrupts.
+ * - USB Reset
+ * - Enumeration Done
+ * - Early Suspend
+ * - USB Suspend
+ * 3. Wait for the USB_GINTSTS.USBRST interrupt, which indicates a reset
+ * has been detected on the USB and lasts for about 10 ms. On receiving
+ * this interrupt, the application must perform the steps listed in
+ * Initialization on USB Reset ...
+ * 4. Wait for the USB_GINTSTS.ENUMDONE interrupt. This interrupt indicates
+ * the end of reset on the USB. On receiving this interrupt, the
+ * application must read the USB_DSTS register to determine the
+ * enumeration speed and perform the steps listed in Initialization on
+ * Enumeration Completion ..."
+ *
+ * "Initialization on USB Reset
+ * 1. Set the NAK bit for all OUT endpoints
+ * - USB_DOEPx_CTL.SNAK = 1 (for all OUT endpoints)
+ * 2. Unmask the following interrupt bits:
+ * - USB_USB_DAINTMSK.INEP0 = 1 (control 0 IN endpoint)
+ * - USB_USB_DAINTMSK.OUTEP0 = 1 (control 0 OUT endpoint)
+ * - USB_DOEPMSK.SETUP = 1
+ * - USB_DOEPMSK.XFERCOMPL = 1
+ * - USB_DIEPMSK.XFERCOMPL = 1
+ * - USB_DIEPMSK.TIMEOUTMSK = 1
+ * 3. To transmit or receive data, the device must initialize more
+ * registers as specified in Device DMA/Slave Mode Initialization ...
+ * 4. Set up the Data FIFO RAM for each of the FIFOs
+ * - Program the USB_GRXFSIZ Register, to be able to receive control
+ * OUT data and setup data. At a minimum, this must be equal to 1 max
+ * packet size of control endpoint 0 + 2 DWORDs (for the status of the
+ * control OUT data packet) + 10 DWORDs (for setup packets).
+ * - Program the Device IN Endpoint Transmit FIFO size register
+ * (depending on the FIFO number chosen), to be able to transmit
+ * control IN data. At a minimum, this must be equal to 1 max packet
+ * size of control endpoint 0.
+ * 5. Program the following fields in the endpoint-specific registers for
+ * control OUT endpoint 0 to receive a SETUP packet
+ * - USB_DOEP0TSIZ.SUPCNT = 3 (to receive up to 3 back-to-back SETUP
+ * packets)
+ * - In DMA mode, USB_DOEP0DMAADDR register with a memory address to
+ * store any SETUP packets received"
+ *
+ * "Initialization on Enumeration Completion
+ * 1. On the Enumeration Done interrupt (USB_GINTSTS.ENUMDONE, read the
+ * USB_DSTS register to determine the enumeration speed.
+ * 2. Program the USB_DIEP0CTL.MPS field to set the maximum packet size.
+ * This step configures control endpoint 0. The maximum packet size
+ * for a control endpoint depends on the enumeration speed.
+ * 3. In DMA mode, program the USB_DOEP0CTL register to enable control
+ * OUT endpoint 0, to receive a SETUP packet.
+ * - USB_DOEP0CTL.EPENA = 1"
+ */
+#warning Review for missing logic
+
+ /* At start-up the core is in FS mode. */
+
+ /* Disable global interrupts by clearing the GINTMASK bit in the GAHBCFG
+ * register; Set the TXFELVL bit in the GAHBCFG register so that TxFIFO
+ * interrupts will occur when the TxFIFO is truly empty (not just half full).
+ */
+
+ efm32_putreg(USB_GAHBCFG_TXFELVL, EFM32_USB_GAHBCFG);
+
+ /* Common USB OTG core initialization */
+ /* Reset after a PHY select and set Host mode. First, wait for AHB master
+ * IDLE state.
+ */
+
+ for (timeout = 0; timeout < EFM32_READY_DELAY; timeout++)
+ {
+ up_udelay(3);
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_AHBIDL) != 0)
+ {
+ break;
+ }
+ }
+
+ /* Then perform the core soft reset. */
+
+ efm32_putreg(USB_GRSTCTL_CSRST, EFM32_USB_GRSTCTL);
+ for (timeout = 0; timeout < EFM32_READY_DELAY; timeout++)
+ {
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_CSRST) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Wait for 3 PHY Clocks */
+
+ up_udelay(3);
+
+ /* Deactivate the power down */
+
+ regval = (USB_GCCFG_PWRDWN | USB_GCCFG_VBUSASEN | USB_GCCFG_VBUSBSEN);
+#ifndef CONFIG_USBDEV_VBUSSENSING
+ regval |= USB_GCCFG_NOVBUSSENS;
+#endif
+#ifdef CONFIG_EFM32_OTGFS_SOFOUTPUT
+ regval |= USB_GCCFG_SOFOUTEN;
+#endif
+ efm32_putreg(regval, EFM32_USB_GCCFG);
+ up_mdelay(20);
+
+ /* Force Device Mode */
+
+ regval = efm32_getreg(EFM32_USB_GUSBCFG);
+ regval &= ~USB_GUSBCFG_FHMOD;
+ regval |= USB_GUSBCFG_FDMOD;
+ efm32_putreg(regval, EFM32_USB_GUSBCFG);
+ up_mdelay(50);
+
+ /* Initialize device mode */
+ /* Restart the PHY Clock */
+
+ efm32_putreg(0, EFM32_USB_PCGCCTL);
+
+ /* Device configuration register */
+
+ regval = efm32_getreg(EFM32_USB_DCFG);
+ regval &= ~_USB_DCFG_PFIVL_MASK;
+ regval |= USB_DCFG_PFIVL_80PCT;
+ efm32_putreg(regval, EFM32_USB_DCFG);
+
+ /* Set full speed PHY */
+
+ regval = efm32_getreg(EFM32_USB_DCFG);
+ regval &= ~_USB_DCFG_DSPD_MASK;
+ regval |= USB_DCFG_DSPD_FS;
+ efm32_putreg(regval, EFM32_USB_DCFG);
+
+ /* Set Rx FIFO size */
+
+ efm32_putreg(EFM32_RXFIFO_WORDS, EFM32_USB_GRXFSIZ);
+
+ /* EP0 TX */
+
+ address = EFM32_RXFIFO_WORDS;
+ regval = (address << _USB_DIEPTXF0_TX0FD_SHIFT) |
+ (EFM32_EP0_TXFIFO_WORDS << _USB_DIEPTXF0_TX0FSA_SHIFT);
+ efm32_putreg(regval, EFM32_USB_DIEPTXF0);
+
+ /* EP1 TX */
+
+ address += EFM32_EP0_TXFIFO_WORDS;
+ regval = (address << _USB_DIEPTXF_INEPTXSA_SHIFT) |
+ (EFM32_EP1_TXFIFO_WORDS << _USB_DIEPTXF_INEPTXFD_SHIFT);
+ efm32_putreg(regval, EFM32_USB_DIEPTXF1);
+
+ /* EP2 TX */
+
+ address += EFM32_EP1_TXFIFO_WORDS;
+ regval = (address << _USB_DIEPTXF_INEPTXSA_SHIFT) |
+ (EFM32_EP2_TXFIFO_WORDS << _USB_DIEPTXF_INEPTXFD_SHIFT);
+ efm32_putreg(regval, EFM32_USB_DIEPTXF2);
+
+ /* EP3 TX */
+
+ address += EFM32_EP2_TXFIFO_WORDS;
+ regval = (address << _USB_DIEPTXF_INEPTXSA_SHIFT) |
+ (EFM32_EP3_TXFIFO_WORDS << _USB_DIEPTXF_INEPTXFD_SHIFT);
+ efm32_putreg(regval, EFM32_USB_DIEPTXF3);
+
+ /* Flush the FIFOs */
+
+ efm32_txfifo_flush(USB_GRSTCTL_TXFNUM_DALL);
+ efm32_rxfifo_flush();
+
+ /* Clear all pending Device Interrupts */
+
+ efm32_putreg(0, EFM32_USB_DIEPMSK);
+ efm32_putreg(0, EFM32_USB_DOEPMSK);
+ efm32_putreg(0, EFM32_USB_DIEPEMPMSK);
+ efm32_putreg(0xffffffff, EFM32_USB_DAINT);
+ efm32_putreg(0, EFM32_USB_DAINTMSK);
+
+ /* Configure all IN endpoints */
+
+ for (i = 0; i < EFM32_NENDPOINTS; i++)
+ {
+ regval = efm32_getreg(EFM32_USB_DIEPCTL(i));
+ if ((regval & USB_DIEPCTL_EPENA) != 0)
+ {
+ /* The endpoint is already enabled */
+
+ regval = USB_DIEPCTL_EPENA | USB_DIEPCTL_SNAK;
+ }
+ else
+ {
+ regval = 0;
+ }
+
+ efm32_putreg(regval, EFM32_USB_DIEPCTL(i));
+ efm32_putreg(0, EFM32_USB_DIEPTSIZ(i));
+ efm32_putreg(0xff, EFM32_USB_DIEPINT(i));
+ }
+
+ /* Configure all OUT endpoints */
+
+ for (i = 0; i < EFM32_NENDPOINTS; i++)
+ {
+ regval = efm32_getreg(EFM32_USB_DOEPCTL(i));
+ if ((regval & USB_DOEPCTL_EPENA) != 0)
+ {
+ /* The endpoint is already enabled */
+
+ regval = USB_DOEPCTL_EPENA | USB_DOEPCTL_SNAK;
+ }
+ else
+ {
+ regval = 0;
+ }
+
+ efm32_putreg(regval, EFM32_USB_DOEPCTL(i));
+ efm32_putreg(0, EFM32_USB_DOEPTSIZ(i));
+ efm32_putreg(0xff, EFM32_USB_DOEPINT(i));
+ }
+
+ /* Disable all interrupts. */
+
+ efm32_putreg(0, EFM32_USB_GINTMSK);
+
+ /* Clear any pending USB_OTG Interrupts */
+
+ efm32_putreg(0xffffffff, EFM32_USB_GOTGINT);
+
+ /* Clear any pending interrupts */
+
+ efm32_putreg(0xbfffffff, EFM32_USB_GINTSTS);
+
+ /* Enable the interrupts in the INTMSK */
+
+ regval = (USB_GINT_RXFLVL | USB_GINT_USBSUSP | USB_GINT_ENUMDNE |
+ USB_GINT_IEP | USB_GINT_OEP | USB_GINT_USBRST);
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+ regval |= (USB_GINT_IISOIXFR | USB_GINT_IISOOXFR);
+#endif
+
+#ifdef CONFIG_USBDEV_SOFINTERRUPT
+ regval |= USB_GINT_SOF;
+#endif
+
+#ifdef CONFIG_USBDEV_VBUSSENSING
+ regval |= (USB_GINT_OTG | USB_GINT_SRQ);
+#endif
+
+#ifdef CONFIG_DEBUG_USB
+ regval |= USB_GINT_MMIS;
+#endif
+
+ efm32_putreg(regval, EFM32_USB_GINTMSK);
+
+ /* Enable the USB global interrupt by setting GINTMSK in the global OTG
+ * FS AHB configuration register; Set the TXFELVL bit in the GAHBCFG
+ * register so that TxFIFO interrupts will occur when the TxFIFO is truly
+ * empty (not just half full).
+ */
+
+ efm32_putreg(USB_GAHBCFG_GINTMSK | USB_GAHBCFG_TXFELVL,
+ EFM32_USB_GAHBCFG);
+}
+
+/*******************************************************************************
+ * Public Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: up_usbinitialize
+ *
+ * Description:
+ * Initialize USB hardware.
+ *
+ * Assumptions:
+ * - This function is called very early in the initialization sequence
+ * - PLL and GIO pin initialization is not performed here but should been in
+ * the low-level boot logic: PLL1 must be configured for operation at 48MHz
+ * and P0.23 and PO.31 in PINSEL1 must be configured for Vbus and USB connect
+ * LED.
+ *
+ *******************************************************************************/
+
+void up_usbinitialize(void)
+{
+ /* At present, there is only a single OTG FS device support. Hence it is
+ * pre-allocated as g_otgfsdev. However, in most code, the private data
+ * structure will be referenced using the 'priv' pointer (rather than the
+ * global data) in order to simplify any future support for multiple devices.
+ */
+
+ FAR struct efm32_usbdev_s *priv = &g_otgfsdev;
+ int ret;
+
+ usbtrace(TRACE_DEVINIT, 0);
+
+ /* "The USB requires the device to run from a 48 MHz crystal (2500 ppm or
+ * better). The core part of the USB will always run from HFCORECLKUSBC
+ * which is HFCLK undivided (48 MHz). The current consumption for the
+ * rest of the device can be reduced by dividing down HFCORECLK using
+ * the CMU_HFCORECLKDIV register. ..."
+ *
+ * "Follow these steps to enable the USB:
+ * 1. Enable the clock to the system part by setting USB in
+ * CMU_HFCORECLKEN0.
+ * 2. If the internal USB regulator is bypassed (by applying 3.3V on
+ * USB_VREGI and USB_VREGO externally), disable the regulator by
+ * setting VREGDIS in USB_CTRL.
+ * 3. If the PHY is powered from VBUS using the internal regulator, the
+ * VREGO sense circuit should be enabled by setting VREGOSEN in
+ * USB_CTRL.
+ * 4. Enable the USB PHY pins by setting PHYPEN in USB_ROUTE.
+ * 5. If host or OTG dual-role device, set VBUSENAP in USB_CTRL to the
+ * desired value and then enable the USB_VBUSEN pin in USB_ROUTE. Set
+ * the MODE for the pin to PUSHPULL.
+ * 6. If low-speed device, set DMPUAP in USB_CTRL to the desired value
+ * and then enable the USB_DMPU pin in USB_ROUTE. Set the MODE for the
+ * pin to PUSHPULL.
+ * 7. Make sure HFXO is ready and selected. The core part requires the
+ * undivided HFCLK to be 48 MHz when USB is active (during
+ * suspend/session-off a 32 kHz clock is used)..
+ * 8. Enable the clock to the core part by setting USBC in
+ * CMU_HFCORECLKEN0.
+ * 9. Wait for the core to come out of reset. This is easiest done by
+ * polling a core register with non-zero reset value until it reads a
+ * non-zero value. This takes approximately 20 48-MHz cycles.
+ * 10. Start initializing the USB core ...
+ */
+#warning Missing Logic
+
+ /* Uninitialize the hardware so that we know that we are starting from a
+ * known state. */
+
+ up_usbuninitialize();
+
+ /* Initialie the driver data structure */
+
+ efm32_swinitialize(priv);
+
+ /* Attach the OTG FS interrupt handler */
+
+ ret = irq_attach(EFM32_IRQ_USB, efm32_usbinterrupt);
+ if (ret < 0)
+ {
+ udbg("irq_attach failed\n", ret);
+ goto errout;
+ }
+
+ /* Initialize the USB OTG core */
+
+ efm32_hwinitialize(priv);
+
+ /* Disconnect device */
+
+ efm32_pullup(&priv->usbdev, false);
+
+ /* Reset/Re-initialize the USB hardware */
+
+ efm32_usbreset(priv);
+
+ /* Enable USB controller interrupts at the NVIC */
+
+ up_enable_irq(EFM32_IRQ_USB);
+
+#ifdef CONFIG_ARCH_IRQPRIO
+ /* Set the interrupt priority */
+
+ up_prioritize_irq(EFM32_IRQ_USB, CONFIG_OTGFS_PRI);
+#endif
+ return;
+
+errout:
+ up_usbuninitialize();
+}
+
+/*******************************************************************************
+ * Name: up_usbuninitialize
+ *******************************************************************************/
+
+void up_usbuninitialize(void)
+{
+ /* At present, there is only a single OTG FS device support. Hence it is
+ * pre-allocated as g_otgfsdev. However, in most code, the private data
+ * structure will be referenced using the 'priv' pointer (rather than the
+ * global data) in order to simplify any future support for multiple devices.
+ */
+
+ FAR struct efm32_usbdev_s *priv = &g_otgfsdev;
+ irqstate_t flags;
+ int i;
+
+ usbtrace(TRACE_DEVUNINIT, 0);
+
+ if (priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_DRIVERREGISTERED), 0);
+ usbdev_unregister(priv->driver);
+ }
+
+ /* Disconnect device */
+
+ flags = irqsave();
+ efm32_pullup(&priv->usbdev, false);
+ priv->usbdev.speed = USB_SPEED_UNKNOWN;
+
+ /* Disable and detach IRQs */
+
+ up_disable_irq(EFM32_IRQ_USB);
+ irq_detach(EFM32_IRQ_USB);
+
+ /* Disable all endpoint interrupts */
+
+ for (i = 0; i < EFM32_NENDPOINTS; i++)
+ {
+ efm32_putreg(0xff, EFM32_USB_DIEPINT(i));
+ efm32_putreg(0xff, EFM32_USB_DOEPINT(i));
+ }
+
+ efm32_putreg(0, EFM32_USB_DIEPMSK);
+ efm32_putreg(0, EFM32_USB_DOEPMSK);
+ efm32_putreg(0, EFM32_USB_DIEPEMPMSK);
+ efm32_putreg(0, EFM32_USB_DAINTMSK);
+ efm32_putreg(0xffffffff, EFM32_USB_DAINT);
+
+ /* Flush the FIFOs */
+
+ efm32_txfifo_flush(USB_GRSTCTL_TXFNUM_DALL);
+ efm32_rxfifo_flush();
+
+ /* TODO: Turn off USB power and clocking */
+
+ priv->devstate = DEVSTATE_DEFAULT;
+ irqrestore(flags);
+}
+
+/*******************************************************************************
+ * Name: usbdev_register
+ *
+ * Description:
+ * Register a USB device class driver. The class driver's bind() method will be
+ * called to bind it to a USB device driver.
+ *
+ *******************************************************************************/
+
+int usbdev_register(struct usbdevclass_driver_s *driver)
+{
+ /* At present, there is only a single OTG FS device support. Hence it is
+ * pre-allocated as g_otgfsdev. However, in most code, the private data
+ * structure will be referenced using the 'priv' pointer (rather than the
+ * global data) in order to simplify any future support for multiple devices.
+ */
+
+ FAR struct efm32_usbdev_s *priv = &g_otgfsdev;
+ int ret;
+
+ usbtrace(TRACE_DEVREGISTER, 0);
+
+#ifdef CONFIG_DEBUG
+ if (!driver || !driver->ops->bind || !driver->ops->unbind ||
+ !driver->ops->disconnect || !driver->ops->setup)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+
+ if (priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_DRIVER), 0);
+ return -EBUSY;
+ }
+#endif
+
+ /* First hook up the driver */
+
+ priv->driver = driver;
+
+ /* Then bind the class driver */
+
+ ret = CLASS_BIND(driver, &priv->usbdev);
+ if (ret)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_BINDFAILED), (uint16_t)-ret);
+ priv->driver = NULL;
+ }
+ else
+ {
+ /* Enable USB controller interrupts */
+
+ up_enable_irq(EFM32_IRQ_USB);
+
+ /* FIXME: nothing seems to call DEV_CONNECT(), but we need to set
+ * the RS bit to enable the controller. It kind of makes sense
+ * to do this after the class has bound to us...
+ * GEN: This bug is really in the class driver. It should make the
+ * soft connect when it is ready to be enumerated. I have added
+ * that logic to the class drivers but left this logic here.
+ */
+
+ efm32_pullup(&priv->usbdev, true);
+ priv->usbdev.speed = USB_SPEED_FULL;
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: usbdev_unregister
+ *
+ * Description:
+ * Un-register usbdev class driver.If the USB device is connected to a USB host,
+ * it will first disconnect(). The driver is also requested to unbind() and clean
+ * up any device state, before this procedure finally returns.
+ *
+ *******************************************************************************/
+
+int usbdev_unregister(struct usbdevclass_driver_s *driver)
+{
+ /* At present, there is only a single OTG FS device support. Hence it is
+ * pre-allocated as g_otgfsdev. However, in most code, the private data
+ * structure will be referenced using the 'priv' pointer (rather than the
+ * global data) in order to simplify any future support for multiple devices.
+ */
+
+ FAR struct efm32_usbdev_s *priv = &g_otgfsdev;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVUNREGISTER, 0);
+
+#ifdef CONFIG_DEBUG
+ if (driver != priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(EFM32_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+
+ /* Reset the hardware and cancel all requests. All requests must be
+ * canceled while the class driver is still bound.
+ */
+
+ flags = irqsave();
+ efm32_usbreset(priv);
+ irqrestore(flags);
+
+ /* Unbind the class driver */
+
+ CLASS_UNBIND(driver, &priv->usbdev);
+
+ /* Disable USB controller interrupts */
+
+ flags = irqsave();
+ up_disable_irq(EFM32_IRQ_USB);
+
+ /* Disconnect device */
+
+ efm32_pullup(&priv->usbdev, false);
+
+ /* Unhook the driver */
+
+ priv->driver = NULL;
+ irqrestore(flags);
+
+ return OK;
+}
+
+#endif /* CONFIG_USBDEV && CONFIG_EFM32_OTGFSDEV */
diff --git a/nuttx/arch/arm/src/efm32/efm32_usbhost.c b/nuttx/arch/arm/src/efm32/efm32_usbhost.c
new file mode 100644
index 000000000..ca920d2a9
--- /dev/null
+++ b/nuttx/arch/arm/src/efm32/efm32_usbhost.c
@@ -0,0 +1,4452 @@
+/*******************************************************************************
+ * arch/arm/src/efm32/efm32_otgfshost.c
+ *
+ * Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ * Authors: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Included Files
+ *******************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/clock.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+#include <nuttx/usb/usbhost_trace.h>
+
+#include <arch/irq.h>
+
+#include "chip.h" /* Includes default GPIO settings */
+#include <arch/board/board.h> /* May redefine GPIO settings */
+
+#include "up_arch.h"
+#include "up_internal.h"
+
+#include "efm32_usb.h"
+
+#if defined(CONFIG_USBHOST) && defined(CONFIG_EFM32_OTGFS)
+
+/*******************************************************************************
+ * Pre-processor Definitions
+ *******************************************************************************/
+/* Configuration ***************************************************************/
+/*
+ * EFM32 USB OTG FS Host Driver Support
+ *
+ * Pre-requisites
+ *
+ * CONFIG_USBHOST - Enable general USB host support
+ * CONFIG_EFM32_OTGFS - Enable the EFM32 USB OTG FS block
+ *
+ * Options:
+ *
+ * CONFIG_EFM32_OTGFS_RXFIFO_SIZE - Size of the RX FIFO in 32-bit words.
+ * Default 128 (512 bytes)
+ * CONFIG_EFM32_OTGFS_NPTXFIFO_SIZE - Size of the non-periodic Tx FIFO
+ * in 32-bit words. Default 96 (384 bytes)
+ * CONFIG_EFM32_OTGFS_PTXFIFO_SIZE - Size of the periodic Tx FIFO in 32-bit
+ * words. Default 96 (384 bytes)
+ * CONFIG_EFM32_OTGFS_DESCSIZE - Maximum size of a descriptor. Default: 128
+ * CONFIG_EFM32_OTGFS_SOFINTR - Enable SOF interrupts. Why would you ever
+ * want to do that?
+ * CONFIG_EFM32_USBHOST_REGDEBUG - Enable very low-level register access
+ * debug. Depends on CONFIG_DEBUG.
+ * CONFIG_EFM32_USBHOST_PKTDUMP - Dump all incoming and outgoing USB
+ * packets. Depends on CONFIG_DEBUG.
+ */
+
+/* Pre-requisites (partial) */
+
+#ifndef CONFIG_EFM32_SYSCFG
+# error "CONFIG_EFM32_SYSCFG is required"
+#endif
+
+/* Default RxFIFO size */
+
+#ifndef CONFIG_EFM32_OTGFS_RXFIFO_SIZE
+# define CONFIG_EFM32_OTGFS_RXFIFO_SIZE 128
+#endif
+
+/* Default host non-periodic Tx FIFO size */
+
+#ifndef CONFIG_EFM32_OTGFS_NPTXFIFO_SIZE
+# define CONFIG_EFM32_OTGFS_NPTXFIFO_SIZE 96
+#endif
+
+/* Default host periodic Tx fifo size register */
+
+#ifndef CONFIG_EFM32_OTGFS_PTXFIFO_SIZE
+# define CONFIG_EFM32_OTGFS_PTXFIFO_SIZE 96
+#endif
+
+/* Maximum size of a descriptor */
+
+#ifndef CONFIG_EFM32_OTGFS_DESCSIZE
+# define CONFIG_EFM32_OTGFS_DESCSIZE 128
+#endif
+
+/* Register/packet debug depends on CONFIG_DEBUG */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_EFM32_USBHOST_REGDEBUG
+# undef CONFIG_EFM32_USBHOST_PKTDUMP
+#endif
+
+/* HCD Setup *******************************************************************/
+/* Hardware capabilities */
+
+#define EFM32_NHOST_CHANNELS 8 /* Number of host channels */
+#define EFM32_MAX_PACKET_SIZE 64 /* Full speed max packet size */
+#define EFM32_EP0_DEF_PACKET_SIZE 8 /* EP0 default packet size */
+#define EFM32_EP0_MAX_PACKET_SIZE 64 /* EP0 FS max packet size */
+#define EFM32_MAX_TX_FIFOS 15 /* Max number of TX FIFOs */
+#define EFM32_MAX_PKTCOUNT 256 /* Max packet count */
+#define EFM32_RETRY_COUNT 3 /* Number of ctrl transfer retries */
+#define EFM32_DEF_DEVADDR 0 /* Default device address */
+
+/* Delays **********************************************************************/
+
+#define EFM32_READY_DELAY 200000 /* In loop counts */
+#define EFM32_FLUSH_DELAY 200000 /* In loop counts */
+#define EFM32_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */
+#define EFM32_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */
+
+/* Ever-present MIN/MAX macros */
+
+#ifndef MIN
+# define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+# define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/*******************************************************************************
+ * Private Types
+ *******************************************************************************/
+
+/* The following enumeration represents the various states of the USB host
+ * state machine (for debug purposes only)
+ */
+
+enum efm32_smstate_e
+{
+ SMSTATE_DETACHED = 0, /* Not attached to a device */
+ SMSTATE_ATTACHED, /* Attached to a device */
+ SMSTATE_ENUM, /* Attached, enumerating */
+ SMSTATE_CLASS_BOUND, /* Enumeration complete, class bound */
+};
+
+/* This enumeration provides the reason for the channel halt. */
+
+enum efm32_chreason_e
+{
+ CHREASON_IDLE = 0, /* Inactive (initial state) */
+ CHREASON_FREED, /* Channel is no longer in use */
+ CHREASON_XFRC, /* Transfer complete */
+ CHREASON_NAK, /* NAK received */
+ CHREASON_NYET, /* NotYet received */
+ CHREASON_STALL, /* Endpoint stalled */
+ CHREASON_TXERR, /* Transfer error received */
+ CHREASON_DTERR, /* Data toggle error received */
+ CHREASON_FRMOR /* Frame overrun */
+};
+
+/* This structure retains the state of one host channel. NOTE: Since there
+ * is only one channel operation active at a time, some of the fields in
+ * in the structure could be moved in struct efm32_ubhost_s to achieve
+ * some memory savings.
+ */
+
+struct efm32_chan_s
+{
+ sem_t waitsem; /* Channel wait semaphore */
+ volatile uint8_t result; /* The result of the transfer */
+ volatile uint8_t chreason; /* Channel halt reason. See enum efm32_chreason_e */
+ uint8_t epno; /* Device endpoint number (0-127) */
+ uint8_t eptype; /* See OTGFS_EPTYPE_* definitions */
+ uint8_t pid; /* Data PID */
+ uint8_t npackets; /* Number of packets (for data toggle) */
+ bool inuse; /* True: This channel is "in use" */
+ volatile bool indata1; /* IN data toggle. True: DATA01 (Bulk and INTR only) */
+ volatile bool outdata1; /* OUT data toggle. True: DATA01 */
+ bool in; /* True: IN endpoint */
+ volatile bool waiter; /* True: Thread is waiting for a channel event */
+ uint16_t maxpacket; /* Max packet size */
+ volatile uint16_t buflen; /* Buffer length (remaining) */
+ volatile uint16_t inflight; /* Number of Tx bytes "in-flight" */
+ FAR uint8_t *buffer; /* Transfer buffer pointer */
+};
+
+/* This structure retains the state of the USB host controller */
+
+struct efm32_usbhost_s
+{
+ /* Common device fields. This must be the first thing defined in the
+ * structure so that it is possible to simply cast from struct usbhost_s
+ * to structefm32_usbhost_s.
+ */
+
+ struct usbhost_driver_s drvr;
+
+ /* The bound device class driver */
+
+ struct usbhost_class_s *class;
+
+ /* Overall driver status */
+
+ volatile uint8_t smstate; /* The state of the USB host state machine */
+ uint8_t devaddr; /* Device address */
+ uint8_t ep0in; /* EP0 IN control channel index */
+ uint8_t ep0out; /* EP0 OUT control channel index */
+ uint8_t ep0size; /* EP0 max packet size */
+ uint8_t chidx; /* ID of channel waiting for space in Tx FIFO */
+ bool lowspeed; /* True: low speed device */
+ volatile bool connected; /* Connected to device */
+ volatile bool eventwait; /* True: Thread is waiting for a port event */
+ sem_t exclsem; /* Support mutually exclusive access */
+ sem_t eventsem; /* Semaphore to wait for a port event */
+
+ /* The state of each host channel */
+
+ struct efm32_chan_s chan[EFM32_MAX_TX_FIFOS];
+};
+
+/*******************************************************************************
+ * Private Function Prototypes
+ *******************************************************************************/
+
+/* Register operations ********************************************************/
+
+#ifdef CONFIG_EFM32_USBHOST_REGDEBUG
+static void efm32_printreg(uint32_t addr, uint32_t val, bool iswrite);
+static void efm32_checkreg(uint32_t addr, uint32_t val, bool iswrite);
+static uint32_t efm32_getreg(uint32_t addr);
+static void efm32_putreg(uint32_t addr, uint32_t value);
+#else
+# define efm32_getreg(addr) getreg32(addr)
+# define efm32_putreg(addr,val) putreg32(val,addr)
+#endif
+
+static inline void efm32_modifyreg(uint32_t addr, uint32_t clrbits,
+ uint32_t setbits);
+
+#ifdef CONFIG_EFM32_USBHOST_PKTDUMP
+# define efm32_pktdump(m,b,n) lib_dumpbuffer(m,b,n)
+#else
+# define efm32_pktdump(m,b,n)
+#endif
+
+/* Semaphores ******************************************************************/
+
+static void efm32_takesem(sem_t *sem);
+#define efm32_givesem(s) sem_post(s);
+
+/* Byte stream access helper functions *****************************************/
+
+static inline uint16_t efm32_getle16(const uint8_t *val);
+
+/* Channel management **********************************************************/
+
+static int efm32_chan_alloc(FAR struct efm32_usbhost_s *priv);
+static inline void efm32_chan_free(FAR struct efm32_usbhost_s *priv, int chidx);
+static inline void efm32_chan_freeall(FAR struct efm32_usbhost_s *priv);
+static void efm32_chan_configure(FAR struct efm32_usbhost_s *priv, int chidx);
+static void efm32_chan_halt(FAR struct efm32_usbhost_s *priv, int chidx,
+ enum efm32_chreason_e chreason);
+static int efm32_chan_waitsetup(FAR struct efm32_usbhost_s *priv,
+ FAR struct efm32_chan_s *chan);
+static int efm32_chan_wait(FAR struct efm32_usbhost_s *priv,
+ FAR struct efm32_chan_s *chan);
+static void efm32_chan_wakeup(FAR struct efm32_usbhost_s *priv,
+ FAR struct efm32_chan_s *chan);
+
+/* Control/data transfer logic *************************************************/
+
+static void efm32_transfer_start(FAR struct efm32_usbhost_s *priv, int chidx);
+#if 0 /* Not used */
+static inline uint16_t efm32_getframe(void);
+#endif
+static int efm32_ctrl_sendsetup(FAR struct efm32_usbhost_s *priv,
+ FAR const struct usb_ctrlreq_s *req);
+static int efm32_ctrl_senddata(FAR struct efm32_usbhost_s *priv,
+ FAR uint8_t *buffer, unsigned int buflen);
+static int efm32_ctrl_recvdata(FAR struct efm32_usbhost_s *priv,
+ FAR uint8_t *buffer, unsigned int buflen);
+static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx,
+ FAR uint8_t *buffer, size_t buflen);
+static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx,
+ FAR uint8_t *buffer, size_t buflen);
+
+/* Interrupt handling **********************************************************/
+/* Lower level interrupt handlers */
+
+static void efm32_gint_wrpacket(FAR struct efm32_usbhost_s *priv,
+ FAR uint8_t *buffer, int chidx, int buflen);
+static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv,
+ int chidx);
+static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv,
+ int chidx);
+static void efm32_gint_connected(FAR struct efm32_usbhost_s *priv);
+static void efm32_gint_disconnected(FAR struct efm32_usbhost_s *priv);
+
+/* Second level interrupt handlers */
+
+#ifdef CONFIG_EFM32_OTGFS_SOFINTR
+static inline void efm32_gint_sofisr(FAR struct efm32_usbhost_s *priv);
+#endif
+static inline void efm32_gint_rxflvlisr(FAR struct efm32_usbhost_s *priv);
+static inline void efm32_gint_nptxfeisr(FAR struct efm32_usbhost_s *priv);
+static inline void efm32_gint_ptxfeisr(FAR struct efm32_usbhost_s *priv);
+static inline void efm32_gint_hcisr(FAR struct efm32_usbhost_s *priv);
+static inline void efm32_gint_hprtisr(FAR struct efm32_usbhost_s *priv);
+static inline void efm32_gint_discisr(FAR struct efm32_usbhost_s *priv);
+static inline void efm32_gint_ipxfrisr(FAR struct efm32_usbhost_s *priv);
+
+/* First level, global interrupt handler */
+
+static int efm32_gint_isr(int irq, FAR void *context);
+
+/* Interrupt controls */
+
+static void efm32_gint_enable(void);
+static void efm32_gint_disable(void);
+static inline void efm32_hostinit_enable(void);
+static void efm32_txfe_enable(FAR struct efm32_usbhost_s *priv, int chidx);
+
+/* USB host controller operations **********************************************/
+
+static int efm32_wait(FAR struct usbhost_connection_s *conn,
+ FAR const bool *connected);
+static int efm32_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx);
+
+static int efm32_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
+ uint16_t maxpacketsize);
+static int efm32_getdevinfo(FAR struct usbhost_driver_s *drvr,
+ FAR struct usbhost_devinfo_s *devinfo);
+static int efm32_epalloc(FAR struct usbhost_driver_s *drvr,
+ FAR const FAR struct usbhost_epdesc_s *epdesc,
+ FAR usbhost_ep_t *ep);
+static int efm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep);
+static int efm32_alloc(FAR struct usbhost_driver_s *drvr,
+ FAR uint8_t **buffer, FAR size_t *maxlen);
+static int efm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
+static int efm32_ioalloc(FAR struct usbhost_driver_s *drvr,
+ FAR uint8_t **buffer, size_t buflen);
+static int efm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
+static int efm32_ctrlin(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR uint8_t *buffer);
+static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR const uint8_t *buffer);
+static int efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
+ FAR uint8_t *buffer, size_t buflen);
+static void efm32_disconnect(FAR struct usbhost_driver_s *drvr);
+
+/* Initialization **************************************************************/
+
+static void efm32_portreset(FAR struct efm32_usbhost_s *priv);
+static void efm32_flush_txfifos(uint32_t txfnum);
+static void efm32_flush_rxfifo(void);
+static void efm32_vbusdrive(FAR struct efm32_usbhost_s *priv, bool state);
+static void efm32_host_initialize(FAR struct efm32_usbhost_s *priv);
+
+static inline void efm32_sw_initialize(FAR struct efm32_usbhost_s *priv);
+static inline int efm32_hw_initialize(FAR struct efm32_usbhost_s *priv);
+
+/*******************************************************************************
+ * Private Data
+ *******************************************************************************/
+
+/* In this driver implementation, support is provided for only a single a single
+ * USB device. All status information can be simply retained in a single global
+ * instance.
+ */
+
+static struct efm32_usbhost_s g_usbhost =
+{
+ .drvr =
+ {
+ .ep0configure = efm32_ep0configure,
+ .getdevinfo = efm32_getdevinfo,
+ .epalloc = efm32_epalloc,
+ .epfree = efm32_epfree,
+ .alloc = efm32_alloc,
+ .free = efm32_free,
+ .ioalloc = efm32_ioalloc,
+ .iofree = efm32_iofree,
+ .ctrlin = efm32_ctrlin,
+ .ctrlout = efm32_ctrlout,
+ .transfer = efm32_transfer,
+ .disconnect = efm32_disconnect,
+ },
+ .class = NULL,
+};
+
+/* This is the connection/enumeration interface */
+
+static struct usbhost_connection_s g_usbconn =
+{
+ .wait = efm32_wait,
+ .enumerate = efm32_enumerate,
+};
+
+/*******************************************************************************
+ * Public Data
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Private Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: efm32_printreg
+ *
+ * Description:
+ * Print the contents of an EFM32xx register operation
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_EFM32_USBHOST_REGDEBUG
+static void efm32_printreg(uint32_t addr, uint32_t val, bool iswrite)
+{
+ lldbg("%08x%s%08x\n", addr, iswrite ? "<-" : "->", val);
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_checkreg
+ *
+ * Description:
+ * Get the contents of an EFM32 register
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_EFM32_USBHOST_REGDEBUG
+static void efm32_checkreg(uint32_t addr, uint32_t val, bool iswrite)
+{
+ static uint32_t prevaddr = 0;
+ static uint32_t preval = 0;
+ static uint32_t count = 0;
+ static bool prevwrite = false;
+
+ /* Is this the same value that we read from/wrote to the same register last time?
+ * Are we polling the register? If so, suppress the output.
+ */
+
+ if (addr == prevaddr && val == preval && prevwrite == iswrite)
+ {
+ /* Yes.. Just increment the count */
+
+ count++;
+ }
+ else
+ {
+ /* No this is a new address or value or operation. Were there any
+ * duplicate accesses before this one?
+ */
+
+ if (count > 0)
+ {
+ /* Yes.. Just one? */
+
+ if (count == 1)
+ {
+ /* Yes.. Just one */
+
+ efm32_printreg(prevaddr, preval, prevwrite);
+ }
+ else
+ {
+ /* No.. More than one. */
+
+ lldbg("[repeats %d more times]\n", count);
+ }
+ }
+
+ /* Save the new address, value, count, and operation for next time */
+
+ prevaddr = addr;
+ preval = val;
+ count = 0;
+ prevwrite = iswrite;
+
+ /* Show the new regisgter access */
+
+ efm32_printreg(addr, val, iswrite);
+ }
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_getreg
+ *
+ * Description:
+ * Get the contents of an EFM32 register
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_EFM32_USBHOST_REGDEBUG
+static uint32_t efm32_getreg(uint32_t addr)
+{
+ /* Read the value from the register */
+
+ uint32_t val = getreg32(addr);
+
+ /* Check if we need to print this value */
+
+ efm32_checkreg(addr, val, false);
+ return val;
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_putreg
+ *
+ * Description:
+ * Set the contents of an EFM32 register to a value
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_EFM32_USBHOST_REGDEBUG
+static void efm32_putreg(uint32_t addr, uint32_t val)
+{
+ /* Check if we need to print this value */
+
+ efm32_checkreg(addr, val, true);
+
+ /* Write the value */
+
+ putreg32(val, addr);
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_modifyreg
+ *
+ * Description:
+ * Modify selected bits of an EFM32 register.
+ *
+ *******************************************************************************/
+
+static inline void efm32_modifyreg(uint32_t addr, uint32_t clrbits, uint32_t setbits)
+{
+ efm32_putreg(addr, (((efm32_getreg(addr)) & ~clrbits) | setbits));
+}
+
+/****************************************************************************
+ * Name: efm32_takesem
+ *
+ * Description:
+ * This is just a wrapper to handle the annoying behavior of semaphore
+ * waits that return due to the receipt of a signal.
+ *
+ *******************************************************************************/
+
+static void efm32_takesem(sem_t *sem)
+{
+ /* Take the semaphore (perhaps waiting) */
+
+ while (sem_wait(sem) != 0)
+ {
+ /* The only case that an error should occr here is if the wait was
+ * awakened by a signal.
+ */
+
+ ASSERT(errno == EINTR);
+ }
+}
+
+/****************************************************************************
+ * Name: efm32_getle16
+ *
+ * Description:
+ * Get a (possibly unaligned) 16-bit little endian value.
+ *
+ *******************************************************************************/
+
+static inline uint16_t efm32_getle16(const uint8_t *val)
+{
+ return (uint16_t)val[1] << 8 | (uint16_t)val[0];
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_alloc
+ *
+ * Description:
+ * Allocate a channel.
+ *
+ *******************************************************************************/
+
+static int efm32_chan_alloc(FAR struct efm32_usbhost_s *priv)
+{
+ int chidx;
+
+ /* Search the table of channels */
+
+ for (chidx = 0; chidx < EFM32_NHOST_CHANNELS; chidx++)
+ {
+ /* Is this channel available? */
+
+ if (!priv->chan[chidx].inuse)
+ {
+ /* Yes... make it "in use" and return the index */
+
+ priv->chan[chidx].inuse = true;
+ return chidx;
+ }
+ }
+
+ /* All of the channels are "in-use" */
+
+ return -EBUSY;
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_free
+ *
+ * Description:
+ * Free a previoiusly allocated channel.
+ *
+ *******************************************************************************/
+
+static void efm32_chan_free(FAR struct efm32_usbhost_s *priv, int chidx)
+{
+ DEBUGASSERT((unsigned)chidx < EFM32_NHOST_CHANNELS);
+
+ /* Halt the channel */
+
+ efm32_chan_halt(priv, chidx, CHREASON_FREED);
+
+ /* Mark the channel available */
+
+ priv->chan[chidx].inuse = false;
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_freeall
+ *
+ * Description:
+ * Free all channels.
+ *
+ *******************************************************************************/
+
+static inline void efm32_chan_freeall(FAR struct efm32_usbhost_s *priv)
+{
+ uint8_t chidx;
+
+ /* Free all host channels */
+
+ for (chidx = 2; chidx < EFM32_NHOST_CHANNELS; chidx ++)
+ {
+ efm32_chan_free(priv, chidx);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_configure
+ *
+ * Description:
+ * Configure or re-configure a host channel. Host channels are configured
+ * when endpoint is allocated and EP0 (only) is re-configured with the
+ * max packet size or device address changes.
+ *
+ *******************************************************************************/
+
+static void efm32_chan_configure(FAR struct efm32_usbhost_s *priv, int chidx)
+{
+ uint32_t regval;
+
+ /* Clear any old pending interrupts for this host channel. */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), 0xffffffff);
+
+ /* Enable channel interrupts required for transfers on this channel. */
+
+ regval = 0;
+
+ switch (priv->chan[chidx].eptype)
+ {
+ case OTGFS_EPTYPE_CTRL:
+ case OTGFS_EPTYPE_BULK:
+ {
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+ uint16_t intrace;
+ uint16_t outtrace;
+
+ /* Determine the definitive trace ID to use below */
+
+ if (priv->chan[chidx].eptype == OTGFS_EPTYPE_CTRL)
+ {
+ intrace = OTGFS_VTRACE2_CHANCONF_CTRL_IN;
+ outtrace = OTGFS_VTRACE2_CHANCONF_CTRL_OUT;
+ }
+ else
+ {
+ intrace = OTGFS_VTRACE2_CHANCONF_BULK_IN;
+ outtrace = OTGFS_VTRACE2_CHANCONF_BULK_OUT;
+ }
+#endif
+
+ /* Interrupts required for CTRL and BULK endpoints */
+
+ regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | OTGFS_HCINT_NAK |
+ OTGFS_HCINT_TXERR | OTGFS_HCINT_DTERR);
+
+ /* Additional setting for IN/OUT endpoints */
+
+ if (priv->chan[chidx].in)
+ {
+ usbhost_vtrace2(intrace, chidx, priv->chan[chidx].epno);
+ regval |= OTGFS_HCINT_BBERR;
+ }
+ else
+ {
+ usbhost_vtrace2(outtrace, chidx, priv->chan[chidx].epno);
+ regval |= OTGFS_HCINT_NYET;
+ }
+ }
+ break;
+
+ case OTGFS_EPTYPE_INTR:
+ {
+ /* Interrupts required for INTR endpoints */
+
+ regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | OTGFS_HCINT_NAK |
+ OTGFS_HCINT_TXERR | OTGFS_HCINT_FRMOR | OTGFS_HCINT_DTERR);
+
+ /* Additional setting for IN endpoints */
+
+ if (priv->chan[chidx].in)
+ {
+ usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_INTR_IN, chidx,
+ priv->chan[chidx].epno);
+ regval |= OTGFS_HCINT_BBERR;
+ }
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+ else
+ {
+ usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_INTR_OUT, chidx,
+ priv->chan[chidx].epno);
+ }
+#endif
+ }
+ break;
+
+ case OTGFS_EPTYPE_ISOC:
+ {
+ /* Interrupts required for ISOC endpoints */
+
+ regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_ACK | OTGFS_HCINT_FRMOR);
+
+ /* Additional setting for IN endpoints */
+
+ if (priv->chan[chidx].in)
+ {
+ usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_ISOC_IN, chidx,
+ priv->chan[chidx].epno);
+ regval |= (OTGFS_HCINT_TXERR | OTGFS_HCINT_BBERR);
+ }
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+ else
+ {
+ usbhost_vtrace2(OTGFS_VTRACE2_CHANCONF_ISOC_OUT, chidx,
+ priv->chan[chidx].epno);
+ }
+#endif
+ }
+ break;
+ }
+
+ efm32_putreg(EFM32_USB_HCINTMSK(chidx), regval);
+
+ /* Enable the top level host channel interrupt. */
+
+ efm32_modifyreg(EFM32_USB_HAINTMSK, 0, OTGFS_HAINT(chidx));
+
+ /* Make sure host channel interrupts are enabled. */
+
+ efm32_modifyreg(EFM32_USB_GINTMSK, 0, USB_GINT_HC);
+
+ /* Program the HCCHAR register */
+
+ regval = ((uint32_t)priv->chan[chidx].maxpacket << _OTGFS_HCCHAR_MPSIZ_SHIFT) |
+ ((uint32_t)priv->chan[chidx].epno << _OTGFS_HCCHAR_EPNUM_SHIFT) |
+ ((uint32_t)priv->chan[chidx].eptype << _OTGFS_HCCHAR_EPTYP_SHIFT) |
+ ((uint32_t)priv->devaddr << _OTGFS_HCCHAR_DAD_SHIFT);
+
+ /* Special case settings for low speed devices */
+
+ if (priv->lowspeed)
+ {
+ regval |= OTGFS_HCCHAR_LSDEV;
+ }
+
+ /* Special case settings for IN endpoints */
+
+ if (priv->chan[chidx].in)
+ {
+ regval |= OTGFS_HCCHAR_EPDIR_IN;
+ }
+
+ /* Special case settings for INTR endpoints */
+
+ if (priv->chan[chidx].eptype == OTGFS_EPTYPE_INTR)
+ {
+ regval |= OTGFS_HCCHAR_ODDFRM;
+ }
+
+ /* Write the channel configuration */
+
+ efm32_putreg(EFM32_USB_HCCHAR(chidx), regval);
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_halt
+ *
+ * Description:
+ * Halt the channel associated with 'chidx' by setting the CHannel DISable
+ * (CHDIS) bit in in the HCCHAR register.
+ *
+ *******************************************************************************/
+
+static void efm32_chan_halt(FAR struct efm32_usbhost_s *priv, int chidx,
+ enum efm32_chreason_e chreason)
+{
+ uint32_t hcchar;
+ uint32_t intmsk;
+ uint32_t eptype;
+ unsigned int avail;
+
+ /* Save the reason for the halt. We need this in the channel halt interrrupt
+ * handling logic to know what to do next.
+ */
+
+ usbhost_vtrace2(OTGFS_VTRACE2_CHANHALT, chidx, chreason);
+
+ priv->chan[chidx].chreason = (uint8_t)chreason;
+
+ /* "The application can disable any channel by programming the OTG_FS_HCCHARx
+ * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS
+ * host to flush the posted requests (if any) and generates a channel halted
+ * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx
+ * before reallocating the channel for other transactions. The OTG_FS host
+ * does not interrupt the transaction that has already been started on the
+ * USB."
+ */
+
+ hcchar = efm32_getreg(EFM32_USB_HCCHAR(chidx));
+ hcchar |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA);
+
+ /* Get the endpoint type from the HCCHAR register */
+
+ eptype = hcchar & _OTGFS_HCCHAR_EPTYP_MASK;
+
+ /* Check for space in the Tx FIFO to issue the halt.
+ *
+ * "Before disabling a channel, the application must ensure that there is at
+ * least one free space available in the non-periodic request queue (when
+ * disabling a non-periodic channel) or the periodic request queue (when
+ * disabling a periodic channel). The application can simply flush the
+ * posted requests when the Request queue is full (before disabling the
+ * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit
+ * set to 1, and the CHENA bit cleared to 0.
+ */
+
+ if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || eptype == OTGFS_HCCHAR_EPTYP_BULK)
+ {
+ /* Get the number of words available in the non-periodic Tx FIFO. */
+
+ avail = efm32_getreg(EFM32_USB_HNPTXSTS) & _OTGFS_HNPTXSTS_NPTXFSAV_MASK;
+ }
+ else /* if (eptype == OTGFS_HCCHAR_EPTYP_ISOC || eptype == OTGFS_HCCHAR_EPTYP_INTR) */
+ {
+ /* Get the number of words available in the non-periodic Tx FIFO. */
+
+ avail = efm32_getreg(EFM32_USB_HPTXSTS) & _OTGFS_HPTXSTS_PTXFSAVL_MASK;
+ }
+
+ /* Check if there is any space available in the Tx FIFO. */
+
+ if (avail == 0)
+ {
+ /* The Tx FIFO is full... disable the channel to flush the requests */
+
+ hcchar &= ~OTGFS_HCCHAR_CHENA;
+ }
+
+ /* Unmask the CHannel Halted (CHH) interrupt */
+
+ intmsk = efm32_getreg(EFM32_USB_HCINTMSK(chidx));
+ intmsk |= OTGFS_HCINT_CHH;
+ efm32_putreg(EFM32_USB_HCINTMSK(chidx), intmsk);
+
+ /* Halt the channel by setting CHDIS (and maybe CHENA) in the HCCHAR */
+
+ efm32_putreg(EFM32_USB_HCCHAR(chidx), hcchar);
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_waitsetup
+ *
+ * Description:
+ * Set the request for the transfer complete event well BEFORE enabling the
+ * transfer (as soon as we are absolutely committed to the to avoid transfer).
+ * We do this to minimize race conditions. This logic would have to be expanded
+ * if we want to have more than one packet in flight at a time!
+ *
+ * Assumptions:
+ * Called from a normal thread context BEFORE the transfer has been started.
+ *
+ *******************************************************************************/
+
+static int efm32_chan_waitsetup(FAR struct efm32_usbhost_s *priv,
+ FAR struct efm32_chan_s *chan)
+{
+ irqstate_t flags = irqsave();
+ int ret = -ENODEV;
+
+ /* Is the device still connected? */
+
+ if (priv->connected)
+ {
+ /* Yes.. then set waiter to indicate that we expect to be informed when
+ * either (1) the device is disconnected, or (2) the transfer completed.
+ */
+
+ chan->waiter = true;
+ ret = OK;
+ }
+
+ irqrestore(flags);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_wait
+ *
+ * Description:
+ * Wait for a transfer on a channel to complete.
+ *
+ * Assumptions:
+ * Called from a normal thread context
+ *
+ *******************************************************************************/
+
+static int efm32_chan_wait(FAR struct efm32_usbhost_s *priv,
+ FAR struct efm32_chan_s *chan)
+{
+ irqstate_t flags;
+ int ret;
+
+ /* Disable interrupts so that the following operations will be atomic. On
+ * the OTG FS global interrupt needs to be disabled. However, here we disable
+ * all interrupts to exploit that fact that interrupts will be re-enabled
+ * while we wait.
+ */
+
+ flags = irqsave();
+
+ /* Loop, testing for an end of transfer conditino. The channel 'result'
+ * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter'
+ * will be set to false and 'result' will be set appropriately when the
+ * tranfer is completed.
+ */
+
+ do
+ {
+ /* Wait for the transfer to complete. NOTE the transfer may already
+ * completed before we get here or the transfer may complete while we
+ * wait here.
+ */
+
+ ret = sem_wait(&chan->waitsem);
+
+ /* sem_wait should succeeed. But it is possible that we could be
+ * awakened by a signal too.
+ */
+
+ DEBUGASSERT(ret == OK || get_errno() == EINTR);
+ }
+ while (chan->waiter);
+
+ /* The transfer is complete re-enable interrupts and return the result */
+
+ ret = -(int)chan->result;
+ irqrestore(flags);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_chan_wakeup
+ *
+ * Description:
+ * A channel transfer has completed... wakeup any threads waiting for the
+ * transfer to complete.
+ *
+ * Assumptions:
+ * This function is called from the transfer complete interrupt handler for
+ * the channel. Interrupts are disabled.
+ *
+ *******************************************************************************/
+
+static void efm32_chan_wakeup(FAR struct efm32_usbhost_s *priv,
+ FAR struct efm32_chan_s *chan)
+{
+ /* Is the transfer complete? Is there a thread waiting for this transfer
+ * to complete?
+ */
+
+ if (chan->result != EBUSY && chan->waiter)
+ {
+ usbhost_vtrace2(chan->in ? OTGFS_VTRACE2_CHANWAKEUP_IN :
+ OTGFS_VTRACE2_CHANWAKEUP_OUT,
+ chan->epno, chan->result);
+
+ efm32_givesem(&chan->waitsem);
+ chan->waiter = false;
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_transfer_start
+ *
+ * Description:
+ * Start at transfer on the select IN or OUT channel.
+ *
+ *******************************************************************************/
+
+static void efm32_transfer_start(FAR struct efm32_usbhost_s *priv, int chidx)
+{
+ FAR struct efm32_chan_s *chan;
+ uint32_t regval;
+ unsigned int npackets;
+ unsigned int maxpacket;
+ unsigned int avail;
+ unsigned int wrsize;
+ unsigned int minsize;
+
+ /* Set up the initial state of the transfer */
+
+ chan = &priv->chan[chidx];
+
+ usbhost_vtrace2(OTGFS_VTRACE2_STARTTRANSFER, chidx, chan->buflen);
+
+ chan->result = EBUSY;
+ chan->inflight = 0;
+ priv->chidx = chidx;
+
+ /* Compute the expected number of packets associated to the transfer.
+ * If the transfer length is zero (or less than the size of one maximum
+ * size packet), then one packet is expected.
+ */
+
+ /* If the transfer size is greater than one packet, then calculate the
+ * number of packets that will be received/sent, including any partial
+ * final packet.
+ */
+
+ maxpacket = chan->maxpacket;
+
+ if (chan->buflen > maxpacket)
+ {
+ npackets = (chan->buflen + maxpacket - 1) / maxpacket;
+
+ /* Clip if the buffer length if it exceeds the maximum number of
+ * packets that can be transferred (this should not happen).
+ */
+
+ if (npackets > EFM32_MAX_PKTCOUNT)
+ {
+ npackets = EFM32_MAX_PKTCOUNT;
+ chan->buflen = EFM32_MAX_PKTCOUNT * maxpacket;
+ usbhost_trace2(OTGFS_TRACE2_CLIP, chidx, chan->buflen);
+ }
+ }
+ else
+ {
+ /* One packet will be sent/received (might be a zero length packet) */
+
+ npackets = 1;
+ }
+
+ /* If it is an IN transfer, then adjust the size of the buffer UP to
+ * a full number of packets. Hmmm... couldn't this cause an overrun
+ * into unallocated memory?
+ */
+
+#if 0 /* Think about this */
+ if (chan->in)
+ {
+ /* Force the buffer length to an even multiple of maxpacket */
+
+ chan->buflen = npackets * maxpacket;
+ }
+#endif
+
+ /* Save the number of packets in the transfer. We will need this in
+ * order to set the next data toggle correctly when the transfer
+ * completes.
+ */
+
+ chan->npackets = (uint8_t)npackets;
+
+ /* Setup the HCTSIZn register */
+
+ regval = ((uint32_t)chan->buflen << _OTGFS_HCTSIZ_XFRSIZ_SHIFT) |
+ ((uint32_t)npackets << _OTGFS_HCTSIZ_PKTCNT_SHIFT) |
+ ((uint32_t)chan->pid << _OTGFS_HCTSIZ_DPID_SHIFT);
+ efm32_putreg(EFM32_USB_HCTSIZ(chidx), regval);
+
+ /* Setup the HCCHAR register: Frame oddness and host channel enable */
+
+ regval = efm32_getreg(EFM32_USB_HCCHAR(chidx));
+
+ /* Set/clear the Odd Frame bit. Check for an even frame; if so set Odd
+ * Frame. This field is applicable for only periodic (isochronous and
+ * interrupt) channels.
+ */
+
+ if ((efm32_getreg(EFM32_USB_HFNUM) & 1) == 0)
+ {
+ regval |= OTGFS_HCCHAR_ODDFRM;
+ }
+ else
+ {
+ regval &= ~OTGFS_HCCHAR_ODDFRM;
+ }
+
+ regval &= ~OTGFS_HCCHAR_CHDIS;
+ regval |= OTGFS_HCCHAR_CHENA;
+ efm32_putreg(EFM32_USB_HCCHAR(chidx), regval);
+
+ /* If this is an out transfer, then we need to do more.. we need to copy
+ * the outgoing data into the correct TxFIFO.
+ */
+
+ if (!chan->in && chan->buflen > 0)
+ {
+ /* Handle non-periodic (CTRL and BULK) OUT transfers differently than
+ * periodic (INTR and ISOC) OUT transfers.
+ */
+
+ minsize = MIN(chan->buflen, chan->maxpacket);
+
+ switch (chan->eptype)
+ {
+ case OTGFS_EPTYPE_CTRL: /* Non periodic transfer */
+ case OTGFS_EPTYPE_BULK:
+ {
+ /* Read the Non-periodic Tx FIFO status register */
+
+ regval = efm32_getreg(EFM32_USB_HNPTXSTS);
+ avail = ((regval & _OTGFS_HNPTXSTS_NPTXFSAV_MASK) >> _OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) << 2;
+ }
+ break;
+
+ /* Periodic transfer */
+
+ case OTGFS_EPTYPE_INTR:
+ case OTGFS_EPTYPE_ISOC:
+ {
+ /* Read the Non-periodic Tx FIFO status register */
+
+ regval = efm32_getreg(EFM32_USB_HPTXSTS);
+ avail = ((regval & _OTGFS_HPTXSTS_PTXFSAVL_MASK) >> _OTGFS_HPTXSTS_PTXFSAVL_SHIFT) << 2;
+ }
+ break;
+
+ default:
+ DEBUGASSERT(false);
+ return;
+ }
+
+ /* Is there space in the TxFIFO to hold the minimum size packet? */
+
+ if (minsize <= avail)
+ {
+ /* Yes.. Get the size of the biggest thing that we can put in the Tx FIFO now */
+
+ wrsize = chan->buflen;
+ if (wrsize > avail)
+ {
+ /* Clip the write size to the number of full, max sized packets
+ * that will fit in the Tx FIFO.
+ */
+
+ unsigned int wrpackets = avail / chan->maxpacket;
+ wrsize = wrpackets * chan->maxpacket;
+ }
+
+ /* Write packet into the Tx FIFO. */
+
+ efm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize);
+ }
+
+ /* Did we put the entire buffer into the Tx FIFO? */
+
+ if (chan->buflen > avail)
+ {
+ /* No, there was insufficient space to hold the entire transfer ...
+ * Enable the Tx FIFO interrupt to handle the transfer when the Tx
+ * FIFO becomes empty.
+ */
+
+ efm32_txfe_enable(priv, chidx);
+ }
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_getframe
+ *
+ * Description:
+ * Get the current frame number. The frame number (FRNUM) field increments
+ * when a new SOF is transmitted on the USB, and is cleared to 0 when it
+ * reaches 0x3fff.
+ *
+ *******************************************************************************/
+
+#if 0 /* Not used */
+static inline uint16_t efm32_getframe(void)
+{
+ return (uint16_t)(efm32_getreg(EFM32_USB_HFNUM) & _OTGFS_HFNUM_FRNUM_MASK);
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_ctrl_sendsetup
+ *
+ * Description:
+ * Send an IN/OUT SETUP packet.
+ *
+ *******************************************************************************/
+
+static int efm32_ctrl_sendsetup(FAR struct efm32_usbhost_s *priv,
+ FAR const struct usb_ctrlreq_s *req)
+{
+ FAR struct efm32_chan_s *chan;
+ uint32_t start;
+ uint32_t elapsed;
+ int ret;
+
+ /* Loop while the device reports NAK (and a timeout is not exceeded */
+
+ chan = &priv->chan[priv->ep0out];
+ start = clock_systimer();
+
+ do
+ {
+ /* Send the SETUP packet */
+
+ chan->pid = OTGFS_PID_SETUP;
+ chan->buffer = (FAR uint8_t *)req;
+ chan->buflen = USB_SIZEOF_CTRLREQ;
+
+ /* Set up for the wait BEFORE starting the transfer */
+
+ ret = efm32_chan_waitsetup(priv, chan);
+ if (ret != OK)
+ {
+ usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0);
+ return ret;
+ }
+
+ /* Start the transfer */
+
+ efm32_transfer_start(priv, priv->ep0out);
+
+ /* Wait for the transfer to complete */
+
+ ret = efm32_chan_wait(priv, chan);
+
+ /* Return on success and for all failures other than EAGAIN. EAGAIN
+ * means that the device NAKed the SETUP command and that we should
+ * try a few more times.
+ */
+
+ if (ret != -EAGAIN)
+ {
+ /* Output some debug information if the transfer failed */
+
+ if (ret < 0)
+ {
+ usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED, ret);
+ }
+
+ /* Return the result in any event */
+
+ return ret;
+ }
+
+ /* Get the elapsed time (in frames) */
+
+ elapsed = clock_systimer() - start;
+ }
+ while (elapsed < EFM32_SETUP_DELAY);
+
+ return -ETIMEDOUT;
+}
+
+/*******************************************************************************
+ * Name: efm32_ctrl_senddata
+ *
+ * Description:
+ * Send data in the data phase of an OUT control transfer. Or send status
+ * in the status phase of an IN control transfer
+ *
+ *******************************************************************************/
+
+static int efm32_ctrl_senddata(FAR struct efm32_usbhost_s *priv,
+ FAR uint8_t *buffer, unsigned int buflen)
+{
+ FAR struct efm32_chan_s *chan = &priv->chan[priv->ep0out];
+ int ret;
+
+ /* Save buffer information */
+
+ chan->buffer = buffer;
+ chan->buflen = buflen;
+
+ /* Set the DATA PID */
+
+ if (buflen == 0)
+ {
+ /* For status OUT stage with buflen == 0, set PID DATA1 */
+
+ chan->outdata1 = true;
+ }
+
+ /* Set the Data PID as per the outdata1 boolean */
+
+ chan->pid = chan->outdata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0;
+
+ /* Set up for the wait BEFORE starting the transfer */
+
+ ret = efm32_chan_waitsetup(priv, chan);
+ if (ret != OK)
+ {
+ usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0);
+ return ret;
+ }
+
+ /* Start the transfer */
+
+ efm32_transfer_start(priv, priv->ep0out);
+
+ /* Wait for the transfer to complete and return the result */
+
+ return efm32_chan_wait(priv, chan);
+}
+
+/*******************************************************************************
+ * Name: efm32_ctrl_recvdata
+ *
+ * Description:
+ * Receive data in the data phase of an IN control transfer. Or receive status
+ * in the status phase of an OUT control transfer
+ *
+ *******************************************************************************/
+
+static int efm32_ctrl_recvdata(FAR struct efm32_usbhost_s *priv,
+ FAR uint8_t *buffer, unsigned int buflen)
+{
+ FAR struct efm32_chan_s *chan = &priv->chan[priv->ep0in];
+ int ret;
+
+ /* Save buffer information */
+
+ chan->pid = OTGFS_PID_DATA1;
+ chan->buffer = buffer;
+ chan->buflen = buflen;
+
+ /* Set up for the wait BEFORE starting the transfer */
+
+ ret = efm32_chan_waitsetup(priv, chan);
+ if (ret != OK)
+ {
+ usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0);
+ return ret;
+ }
+
+ /* Start the transfer */
+
+ efm32_transfer_start(priv, priv->ep0in);
+
+ /* Wait for the transfer to complete and return the result */
+
+ return efm32_chan_wait(priv, chan);
+}
+
+/*******************************************************************************
+ * Name: efm32_in_transfer
+ *
+ * Description:
+ * Transfer 'buflen' bytes into 'buffer' from an IN channel.
+ *
+ *******************************************************************************/
+
+static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx,
+ FAR uint8_t *buffer, size_t buflen)
+{
+ FAR struct efm32_chan_s *chan;
+ uint32_t start;
+ uint32_t elapsed;
+ int ret = OK;
+
+ /* Loop until the transfer completes (i.e., buflen is decremented to zero)
+ * or a fatal error occurs (any error other than a simple NAK)
+ */
+
+ chan = &priv->chan[chidx];
+ chan->buffer = buffer;
+ chan->buflen = buflen;
+
+ start = clock_systimer();
+ while (chan->buflen > 0)
+ {
+ /* Set up for the wait BEFORE starting the transfer */
+
+ ret = efm32_chan_waitsetup(priv, chan);
+ if (ret != OK)
+ {
+ usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0);
+ return ret;
+ }
+
+ /* Set up for the transfer based on the direction and the endpoint type */
+
+ switch (chan->eptype)
+ {
+ default:
+ case OTGFS_EPTYPE_CTRL: /* Control */
+ {
+ /* This kind of transfer on control endpoints other than EP0 are not
+ * currently supported
+ */
+
+ return -ENOSYS;
+ }
+
+ case OTGFS_EPTYPE_ISOC: /* Isochronous */
+ {
+ /* Set up the IN data PID */
+
+ usbhost_vtrace2(OTGFS_VTRACE2_ISOCIN, chidx, buflen);
+ chan->pid = OTGFS_PID_DATA0;
+ }
+ break;
+
+ case OTGFS_EPTYPE_BULK: /* Bulk */
+ {
+ /* Setup the IN data PID */
+
+ usbhost_vtrace2(OTGFS_VTRACE2_BULKIN, chidx, buflen);
+ chan->pid = chan->indata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0;
+ }
+ break;
+
+ case OTGFS_EPTYPE_INTR: /* Interrupt */
+ {
+ /* Setup the IN data PID */
+
+ usbhost_vtrace2(OTGFS_VTRACE2_INTRIN, chidx, buflen);
+ chan->pid = chan->indata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0;
+ }
+ break;
+ }
+
+ /* Start the transfer */
+
+ efm32_transfer_start(priv, chidx);
+
+ /* Wait for the transfer to complete and get the result */
+
+ ret = efm32_chan_wait(priv, chan);
+
+ /* EAGAIN indicates that the device NAKed the transfer and we need
+ * do try again. Anything else (success or other errors) will
+ * cause use to return
+ */
+
+ if (ret != OK)
+ {
+ usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED,ret);
+
+ /* Check for a special case: If (1) the transfer was NAKed and (2)
+ * no Tx FIFO empty or Rx FIFO not-empty event occurred, then we
+ * should be able to just flush the Rx and Tx FIFOs and try again.
+ * We can detect this latter case becasue the then the transfer
+ * buffer pointer and buffer size will be unaltered.
+ */
+
+ elapsed = clock_systimer() - start;
+ if (ret != -EAGAIN || /* Not a NAK condition OR */
+ elapsed >= EFM32_DATANAK_DELAY || /* Timeout has elapsed OR */
+ chan->buflen != buflen) /* Data has been partially transferred */
+ {
+ /* Break out and return the error */
+
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_out_transfer
+ *
+ * Description:
+ * Transfer the 'buflen' bytes in 'buffer' through an OUT channel.
+ *
+ *******************************************************************************/
+
+static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx,
+ FAR uint8_t *buffer, size_t buflen)
+{
+ FAR struct efm32_chan_s *chan;
+ uint32_t start;
+ uint32_t elapsed;
+ size_t xfrlen;
+ int ret = OK;
+
+ /* Loop until the transfer completes (i.e., buflen is decremented to zero)
+ * or a fatal error occurs (any error other than a simple NAK)
+ */
+
+ chan = &priv->chan[chidx];
+ start = clock_systimer();
+
+ while (buflen > 0)
+ {
+ /* Transfer one packet at a time. The hardware is capable of queueing
+ * multiple OUT packets, but I just haven't figured out how to handle
+ * the case where a single OUT packet in the group is NAKed.
+ */
+
+ xfrlen = MIN(chan->maxpacket, buflen);
+ chan->buffer = buffer;
+ chan->buflen = xfrlen;
+
+ /* Set up for the wait BEFORE starting the transfer */
+
+ ret = efm32_chan_waitsetup(priv, chan);
+ if (ret != OK)
+ {
+ usbhost_trace1(OTGFS_TRACE1_DEVDISCONN,0);
+ return ret;
+ }
+
+ /* Set up for the transfer based on the direction and the endpoint type */
+
+ switch (chan->eptype)
+ {
+ default:
+ case OTGFS_EPTYPE_CTRL: /* Control */
+ {
+ /* This kind of transfer on control endpoints other than EP0 are not
+ * currently supported
+ */
+
+ return -ENOSYS;
+ }
+
+ case OTGFS_EPTYPE_ISOC: /* Isochronous */
+ {
+ /* Set up the OUT data PID */
+
+ usbhost_vtrace2(OTGFS_VTRACE2_ISOCOUT, chidx, buflen);
+ chan->pid = OTGFS_PID_DATA0;
+ }
+ break;
+
+ case OTGFS_EPTYPE_BULK: /* Bulk */
+ {
+ /* Setup the OUT data PID */
+
+ usbhost_vtrace2(OTGFS_VTRACE2_BULKOUT, chidx, buflen);
+ chan->pid = chan->outdata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0;
+ }
+ break;
+
+ case OTGFS_EPTYPE_INTR: /* Interrupt */
+ {
+ /* Setup the OUT data PID */
+
+ usbhost_vtrace2(OTGFS_VTRACE2_INTROUT, chidx, buflen);
+ chan->pid = chan->outdata1 ? OTGFS_PID_DATA1 : OTGFS_PID_DATA0;
+
+ /* Toggle the OUT data PID for the next transfer */
+
+ chan->outdata1 ^= true;
+ }
+ break;
+ }
+
+ /* Start the transfer */
+
+ efm32_transfer_start(priv, chidx);
+
+ /* Wait for the transfer to complete and get the result */
+
+ ret = efm32_chan_wait(priv, chan);
+
+ /* Handle transfer failures */
+
+ if (ret != OK)
+ {
+ usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED,ret);
+
+ /* Check for a special case: If (1) the transfer was NAKed and (2)
+ * no Tx FIFO empty or Rx FIFO not-empty event occurred, then we
+ * should be able to just flush the Rx and Tx FIFOs and try again.
+ * We can detect this latter case becasue the then the transfer
+ * buffer pointer and buffer size will be unaltered.
+ */
+
+ elapsed = clock_systimer() - start;
+ if (ret != -EAGAIN || /* Not a NAK condition OR */
+ elapsed >= EFM32_DATANAK_DELAY || /* Timeout has elapsed OR */
+ chan->buflen != xfrlen) /* Data has been partially transferred */
+ {
+ /* Break out and return the error */
+
+ break;
+ }
+
+ /* Is this flush really necessary? What does the hardware do with the
+ * data in the FIFO when the NAK occurs? Does it discard it?
+ */
+
+ efm32_flush_txfifos(USB_GRSTCTL_TXFNUM_HALL);
+
+ /* Get the device a little time to catch up. Then retry the transfer
+ * using the same buffer pointer and length.
+ */
+
+ usleep(20*1000);
+ }
+ else
+ {
+ /* Successfully transferred. Update the buffer pointer and length */
+
+ buffer += xfrlen;
+ buflen -= xfrlen;
+ }
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_wrpacket
+ *
+ * Description:
+ * Transfer the 'buflen' bytes in 'buffer' to the Tx FIFO associated with
+ * 'chidx' (non-DMA).
+ *
+ *******************************************************************************/
+
+static void efm32_gint_wrpacket(FAR struct efm32_usbhost_s *priv,
+ FAR uint8_t *buffer, int chidx, int buflen)
+{
+ FAR uint32_t *src;
+ uint32_t fifo;
+ int buflen32;
+
+ efm32_pktdump("Sending", buffer, buflen);
+
+ /* Get the number of 32-byte words associated with this byte size */
+
+ buflen32 = (buflen + 3) >> 2;
+
+ /* Get the address of the Tx FIFO associated with this channel */
+
+ fifo = EFM32_USB_DFIFO_HCH(chidx);
+
+ /* Transfer all of the data into the Tx FIFO */
+
+ src = (FAR uint32_t *)buffer;
+ for (; buflen32 > 0; buflen32--)
+ {
+ uint32_t data = *src++;
+ efm32_putreg(fifo, data);
+ }
+
+ /* Increment the count of bytes "in-flight" in the Tx FIFO */
+
+ priv->chan[chidx].inflight += buflen;
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_hcinisr
+ *
+ * Description:
+ * USB OTG FS host IN channels interrupt handler
+ *
+ * One the completion of the transfer, the channel result byte may be set as
+ * follows:
+ *
+ * OK - Transfer completed successfully
+ * EAGAIN - If devices NAKs the transfer or NYET occurs
+ * EPERM - If the endpoint stalls
+ * EIO - On a TX or data toggle error
+ * EPIPE - Frame overrun
+ *
+ * EBUSY in the result field indicates that the transfer has not completed.
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv,
+ int chidx)
+{
+ FAR struct efm32_chan_s *chan = &priv->chan[chidx];
+ uint32_t regval;
+ uint32_t pending;
+
+ /* Read the HCINT register to get the pending HC interrupts. Read the
+ * HCINTMSK register to get the set of enabled HC interrupts.
+ */
+
+ pending = efm32_getreg(EFM32_USB_HCINT(chidx));
+ regval = efm32_getreg(EFM32_USB_HCINTMSK(chidx));
+
+ /* AND the two to get the set of enabled, pending HC interrupts */
+
+ pending &= regval;
+ ullvdbg("HCINTMSK%d: %08x pending: %08x\n", chidx, regval, pending);
+
+ /* Check for a pending ACK response received/transmitted (ACK) interrupt */
+
+ if ((pending & OTGFS_HCINT_ACK) != 0)
+ {
+ /* Clear the pending the ACK response received/transmitted (ACK) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_ACK);
+ }
+
+ /* Check for a pending STALL response receive (STALL) interrupt */
+
+ else if ((pending & OTGFS_HCINT_STALL) != 0)
+ {
+ /* Clear the NAK and STALL Conditions. */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_STALL));
+
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
+
+ efm32_chan_halt(priv, chidx, CHREASON_STALL);
+
+ /* When there is a STALL, clear any pending NAK so that it is not
+ * processed below.
+ */
+
+ pending &= ~OTGFS_HCINT_NAK;
+ }
+
+ /* Check for a pending Data Toggle ERRor (DTERR) interrupt */
+
+ else if ((pending & OTGFS_HCINT_DTERR) != 0)
+ {
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
+
+ efm32_chan_halt(priv, chidx, CHREASON_DTERR);
+
+ /* Clear the NAK and data toggle error conditions */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR));
+ }
+
+ /* Check for a pending FRaMe OverRun (FRMOR) interrupt */
+
+ if ((pending & OTGFS_HCINT_FRMOR) != 0)
+ {
+ /* Halt the channel -- the CHH interrrupt is expected next */
+
+ efm32_chan_halt(priv, chidx, CHREASON_FRMOR);
+
+ /* Clear the FRaMe OverRun (FRMOR) condition */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_FRMOR);
+ }
+
+ /* Check for a pending TransFeR Completed (XFRC) interrupt */
+
+ else if ((pending & OTGFS_HCINT_XFRC) != 0)
+ {
+ /* Clear the TransFeR Completed (XFRC) condition */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_XFRC);
+
+ /* Then handle the transfer completion event based on the endpoint type */
+
+ if (chan->eptype == OTGFS_EPTYPE_CTRL || chan->eptype == OTGFS_EPTYPE_BULK)
+ {
+ /* Halt the channel -- the CHH interrrupt is expected next */
+
+ efm32_chan_halt(priv, chidx, CHREASON_XFRC);
+
+ /* Clear any pending NAK condition. The 'indata1' data toggle
+ * should have been appropriately updated by the RxFIFO
+ * logic as each packet was received.
+ */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_NAK);
+ }
+ else if (chan->eptype == OTGFS_EPTYPE_INTR)
+ {
+ /* Force the next transfer on an ODD frame */
+
+ regval = efm32_getreg(EFM32_USB_HCCHAR(chidx));
+ regval |= OTGFS_HCCHAR_ODDFRM;
+ efm32_putreg(EFM32_USB_HCCHAR(chidx), regval);
+
+ /* Set the request done state */
+
+ chan->result = OK;
+ }
+ }
+
+ /* Check for a pending CHannel Halted (CHH) interrupt */
+
+ else if ((pending & OTGFS_HCINT_CHH) != 0)
+ {
+ /* Mask the CHannel Halted (CHH) interrupt */
+
+ regval = efm32_getreg(EFM32_USB_HCINTMSK(chidx));
+ regval &= ~OTGFS_HCINT_CHH;
+ efm32_putreg(EFM32_USB_HCINTMSK(chidx), regval);
+
+ /* Update the request state based on the host state machine state */
+
+ if (chan->chreason == CHREASON_XFRC)
+ {
+ /* Set the request done reult */
+
+ chan->result = OK;
+ }
+ else if (chan->chreason == CHREASON_STALL)
+ {
+ /* Set the request stall result */
+
+ chan->result = EPERM;
+ }
+ else if ((chan->chreason == CHREASON_TXERR) ||
+ (chan->chreason == CHREASON_DTERR))
+ {
+ /* Set the request I/O error result */
+
+ chan->result = EIO;
+ }
+ else if (chan->chreason == CHREASON_NAK)
+ {
+ /* Halt on NAK only happens on an INTR channel. Fetch the HCCHAR register
+ * and check for an interrupt endpoint.
+ */
+
+ regval = efm32_getreg(EFM32_USB_HCCHAR(chidx));
+ if ((regval & _OTGFS_HCCHAR_EPTYP_MASK) == OTGFS_HCCHAR_EPTYP_INTR)
+ {
+ /* Toggle the IN data toggle (Used by Bulk and INTR only) */
+
+ chan->indata1 ^= true;
+ }
+
+ /* Set the NAK error result */
+
+ chan->result = EAGAIN;
+ }
+ else /* if (chan->chreason == CHREASON_FRMOR) */
+ {
+ /* Set the frame overrun error result */
+
+ chan->result = EPIPE;
+ }
+
+ /* Clear the CHannel Halted (CHH) condition */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_CHH);
+ }
+
+ /* Check for a pending Transaction ERror (TXERR) interrupt */
+
+ else if ((pending & OTGFS_HCINT_TXERR) != 0)
+ {
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
+
+ efm32_chan_halt(priv, chidx, CHREASON_TXERR);
+
+ /* Clear the Transaction ERror (TXERR) condition */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_TXERR);
+ }
+
+ /* Check for a pending NAK response received (NAK) interrupt */
+
+ else if ((pending & OTGFS_HCINT_NAK) != 0)
+ {
+ /* For a BULK transfer, the hardware is capable of retrying
+ * automatically on a NAK. However, this is not always
+ * what we need to do. So we always halt the transfer and
+ * return control to high level logic in the even of a NAK.
+ */
+
+#if 1
+ /* Halt the interrupt channel */
+
+ if (chan->eptype == OTGFS_EPTYPE_INTR)
+ {
+ /* Halt the channel -- the CHH interrupt is expected next */
+
+ efm32_chan_halt(priv, chidx, CHREASON_NAK);
+ }
+
+ /* Re-activate CTRL and BULK channels */
+
+ else if (chan->eptype == OTGFS_EPTYPE_CTRL ||
+ chan->eptype == OTGFS_EPTYPE_BULK)
+ {
+ /* Re-activate the channel by clearing CHDIS and assuring that
+ * CHENA is set
+ */
+
+ regval = efm32_getreg(EFM32_USB_HCCHAR(chidx));
+ regval |= OTGFS_HCCHAR_CHENA;
+ regval &= ~OTGFS_HCCHAR_CHDIS;
+ efm32_putreg(EFM32_USB_HCCHAR(chidx), regval);
+ }
+#else
+ /* Halt all transfers on the NAK -- the CHH interrupt is expected next */
+
+ efm32_chan_halt(priv, chidx, CHREASON_NAK);
+#endif
+
+ /* Clear the NAK condition */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_NAK);
+ }
+
+ /* Check for a transfer complete event */
+
+ efm32_chan_wakeup(priv, chan);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_hcoutisr
+ *
+ * Description:
+ * USB OTG FS host OUT channels interrupt handler
+ *
+ * One the completion of the transfer, the channel result byte may be set as
+ * follows:
+ *
+ * OK - Transfer completed successfully
+ * EAGAIN - If devices NAKs the transfer or NYET occurs
+ * EPERM - If the endpoint stalls
+ * EIO - On a TX or data toggle error
+ * EPIPE - Frame overrun
+ *
+ * EBUSY in the result field indicates that the transfer has not completed.
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv,
+ int chidx)
+{
+ FAR struct efm32_chan_s *chan = &priv->chan[chidx];
+ uint32_t regval;
+ uint32_t pending;
+
+ /* Read the HCINT register to get the pending HC interrupts. Read the
+ * HCINTMSK register to get the set of enabled HC interrupts.
+ */
+
+ pending = efm32_getreg(EFM32_USB_HCINT(chidx));
+ regval = efm32_getreg(EFM32_USB_HCINTMSK(chidx));
+
+ /* AND the two to get the set of enabled, pending HC interrupts */
+
+ pending &= regval;
+ ullvdbg("HCINTMSK%d: %08x pending: %08x\n", chidx, regval, pending);
+
+ /* Check for a pending ACK response received/transmitted (ACK) interrupt */
+
+ if ((pending & OTGFS_HCINT_ACK) != 0)
+ {
+ /* Clear the pending the ACK response received/transmitted (ACK) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_ACK);
+ }
+
+ /* Check for a pending FRaMe OverRun (FRMOR) interrupt */
+
+ else if ((pending & OTGFS_HCINT_FRMOR) != 0)
+ {
+ /* Halt the channel (probably not necessary for FRMOR) */
+
+ efm32_chan_halt(priv, chidx, CHREASON_FRMOR);
+
+ /* Clear the pending the FRaMe OverRun (FRMOR) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_FRMOR);
+ }
+
+ /* Check for a pending TransFeR Completed (XFRC) interrupt */
+
+ else if ((pending & OTGFS_HCINT_XFRC) != 0)
+ {
+ /* Decrement the number of bytes remaining by the number of
+ * bytes that were "in-flight".
+ */
+
+ priv->chan[chidx].buffer += priv->chan[chidx].inflight;
+ priv->chan[chidx].buflen -= priv->chan[chidx].inflight;
+ priv->chan[chidx].inflight = 0;
+
+ /* Halt the channel -- the CHH interrrupt is expected next */
+
+ efm32_chan_halt(priv, chidx, CHREASON_XFRC);
+
+ /* Clear the pending the TransFeR Completed (XFRC) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_XFRC);
+ }
+
+ /* Check for a pending STALL response receive (STALL) interrupt */
+
+ else if ((pending & OTGFS_HCINT_STALL) != 0)
+ {
+ /* Clear the pending the STALL response receiv (STALL) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_STALL);
+
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
+
+ efm32_chan_halt(priv, chidx, CHREASON_STALL);
+ }
+
+ /* Check for a pending NAK response received (NAK) interrupt */
+
+ else if ((pending & OTGFS_HCINT_NAK) != 0)
+ {
+ /* Halt the channel -- the CHH interrrupt is expected next */
+
+ efm32_chan_halt(priv, chidx, CHREASON_NAK);
+
+ /* Clear the pending the NAK response received (NAK) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_NAK);
+ }
+
+ /* Check for a pending Transaction ERror (TXERR) interrupt */
+
+ else if ((pending & OTGFS_HCINT_TXERR) != 0)
+ {
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
+
+ efm32_chan_halt(priv, chidx, CHREASON_TXERR);
+
+ /* Clear the pending the Transaction ERror (TXERR) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_TXERR);
+ }
+
+ /* Check for a NYET interrupt */
+
+#if 0 /* NYET is a reserved bit in the HCINT register */
+ else if ((pending & OTGFS_HCINT_NYET) != 0)
+ {
+ /* Halt the channel */
+
+ efm32_chan_halt(priv, chidx, CHREASON_NYET);
+
+ /* Clear the pending the NYET interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_NYET);
+ }
+#endif
+
+ /* Check for a pending Data Toggle ERRor (DTERR) interrupt */
+
+ else if (pending & OTGFS_HCINT_DTERR)
+ {
+ /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is
+ * received on the channel.
+ */
+
+ efm32_chan_halt(priv, chidx, CHREASON_DTERR);
+
+ /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), (OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK));
+ }
+
+ /* Check for a pending CHannel Halted (CHH) interrupt */
+
+ else if ((pending & OTGFS_HCINT_CHH) != 0)
+ {
+ /* Mask the CHannel Halted (CHH) interrupt */
+
+ regval = efm32_getreg(EFM32_USB_HCINTMSK(chidx));
+ regval &= ~OTGFS_HCINT_CHH;
+ efm32_putreg(EFM32_USB_HCINTMSK(chidx), regval);
+
+ if (chan->chreason == CHREASON_XFRC)
+ {
+ /* Set the request done result */
+
+ chan->result = OK;
+
+ /* Read the HCCHAR register to get the HCCHAR register to get
+ * the endpoint type.
+ */
+
+ regval = efm32_getreg(EFM32_USB_HCCHAR(chidx));
+
+ /* Is it a bulk endpoint? Were an odd number of packets
+ * transferred?
+ */
+
+ if ((regval & _OTGFS_HCCHAR_EPTYP_MASK) == OTGFS_HCCHAR_EPTYP_BULK &&
+ (chan->npackets & 1) != 0)
+ {
+ /* Yes to both... toggle the data out PID */
+
+ chan->outdata1 ^= true;
+ }
+ }
+ else if (chan->chreason == CHREASON_NAK ||
+ chan->chreason == CHREASON_NYET)
+ {
+ /* Set the try again later result */
+
+ chan->result = EAGAIN;
+ }
+ else if (chan->chreason == CHREASON_STALL)
+ {
+ /* Set the request stall result */
+
+ chan->result = EPERM;
+ }
+ else if ((chan->chreason == CHREASON_TXERR) ||
+ (chan->chreason == CHREASON_DTERR))
+ {
+ /* Set the I/O failure result */
+
+ chan->result = EIO;
+ }
+ else /* if (chan->chreason == CHREASON_FRMOR) */
+ {
+ /* Set the frame error result */
+
+ chan->result = EPIPE;
+ }
+
+ /* Clear the pending the CHannel Halted (CHH) interrupt */
+
+ efm32_putreg(EFM32_USB_HCINT(chidx), OTGFS_HCINT_CHH);
+ }
+
+ /* Check for a transfer complete event */
+
+ efm32_chan_wakeup(priv, chan);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_connected
+ *
+ * Description:
+ * Handle a connection event.
+ *
+ *******************************************************************************/
+
+static void efm32_gint_connected(FAR struct efm32_usbhost_s *priv)
+{
+ /* We we previously disconnected? */
+
+ if (!priv->connected)
+ {
+ /* Yes.. then now we are connected */
+
+ usbhost_vtrace1(OTGFS_VTRACE1_CONNECTED,0);
+ priv->connected = true;
+ DEBUGASSERT(priv->smstate == SMSTATE_DETACHED);
+
+ /* Notify any waiters */
+
+ priv->smstate = SMSTATE_ATTACHED;
+ if (priv->eventwait)
+ {
+ efm32_givesem(&priv->eventsem);
+ priv->eventwait = false;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_disconnected
+ *
+ * Description:
+ * Handle a disconnection event.
+ *
+ *******************************************************************************/
+
+static void efm32_gint_disconnected(FAR struct efm32_usbhost_s *priv)
+{
+ /* Were we previously connected? */
+
+ if (priv->connected)
+ {
+ /* Yes.. then we no longer connected */
+
+ usbhost_vtrace1(OTGFS_VTRACE1_DISCONNECTED,0);
+
+ /* Are we bound to a class driver? */
+
+ if (priv->class)
+ {
+ /* Yes.. Disconnect the class driver */
+
+ CLASS_DISCONNECTED(priv->class);
+ priv->class = NULL;
+ }
+
+ /* Re-Initilaize Host for new Enumeration */
+
+ priv->smstate = SMSTATE_DETACHED;
+ priv->ep0size = EFM32_EP0_MAX_PACKET_SIZE;
+ priv->devaddr = EFM32_DEF_DEVADDR;
+ priv->connected = false;
+ priv->lowspeed = false;
+ efm32_chan_freeall(priv);
+
+ /* Notify any waiters that there is a change in the connection state */
+
+ if (priv->eventwait)
+ {
+ efm32_givesem(&priv->eventsem);
+ priv->eventwait = false;
+ }
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_sofisr
+ *
+ * Description:
+ * USB OTG FS start-of-frame interrupt handler
+ *
+ *******************************************************************************/
+
+#ifdef CONFIG_EFM32_OTGFS_SOFINTR
+static inline void efm32_gint_sofisr(FAR struct efm32_usbhost_s *priv)
+{
+ /* Handle SOF interrupt */
+#warning "Do what?"
+
+ /* Clear pending SOF interrupt */
+
+ efm32_putreg(EFM32_USB_GINTSTS, USB_GINT_SOF);
+}
+#endif
+
+/*******************************************************************************
+ * Name: efm32_gint_rxflvlisr
+ *
+ * Description:
+ * USB OTG FS RxFIFO non-empty interrupt handler
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_rxflvlisr(FAR struct efm32_usbhost_s *priv)
+{
+ FAR uint32_t *dest;
+ uint32_t grxsts;
+ uint32_t intmsk;
+ uint32_t hcchar;
+ uint32_t hctsiz;
+ uint32_t fifo;
+ int bcnt;
+ int bcnt32;
+ int chidx;
+ int i;
+
+ /* Disable the RxFIFO non-empty interrupt */
+
+ intmsk = efm32_getreg(EFM32_USB_GINTMSK);
+ intmsk &= ~USB_GINT_RXFLVL;
+ efm32_putreg(EFM32_USB_GINTMSK, intmsk);
+
+ /* Read and pop the next status from the Rx FIFO */
+
+ grxsts = efm32_getreg(EFM32_USB_GRXSTSP);
+ ullvdbg("GRXSTS: %08x\n", grxsts);
+
+ /* Isolate the channel number/index in the status word */
+
+ chidx = (grxsts & _OTGFS_GRXSTSH_CHNUM_MASK) >> _OTGFS_GRXSTSH_CHNUM_SHIFT;
+
+ /* Get the host channel characteristics register (HCCHAR) for this channel */
+
+ hcchar = efm32_getreg(EFM32_USB_HCCHAR(chidx));
+
+ /* Then process the interrupt according to the packet status */
+
+ switch (grxsts & _OTGFS_GRXSTSH_PKTSTS_MASK)
+ {
+ case OTGFS_GRXSTSH_PKTSTS_INRECVD: /* IN data packet received */
+ {
+ /* Read the data into the host buffer. */
+
+ bcnt = (grxsts & _OTGFS_GRXSTSH_BCNT_MASK) >> _OTGFS_GRXSTSH_BCNT_SHIFT;
+ if (bcnt > 0 && priv->chan[chidx].buffer != NULL)
+ {
+ /* Transfer the packet from the Rx FIFO into the user buffer */
+
+ dest = (FAR uint32_t *)priv->chan[chidx].buffer;
+ fifo = EFM32_USB_DFIFO_HCH(0);
+ bcnt32 = (bcnt + 3) >> 2;
+
+ for (i = 0; i < bcnt32; i++)
+ {
+ *dest++ = efm32_getreg(fifo);
+ }
+
+ efm32_pktdump("Received", priv->chan[chidx].buffer, bcnt);
+
+ /* Toggle the IN data pid (Used by Bulk and INTR only) */
+
+ priv->chan[chidx].indata1 ^= true;
+
+ /* Manage multiple packet transfers */
+
+ priv->chan[chidx].buffer += bcnt;
+ priv->chan[chidx].buflen -= bcnt;
+
+ /* Check if more packets are expected */
+
+ hctsiz = efm32_getreg(EFM32_USB_HCTSIZ(chidx));
+ if ((hctsiz & _OTGFS_HCTSIZ_PKTCNT_MASK) != 0)
+ {
+ /* Re-activate the channel when more packets are expected */
+
+ hcchar |= OTGFS_HCCHAR_CHENA;
+ hcchar &= ~OTGFS_HCCHAR_CHDIS;
+ efm32_putreg(EFM32_USB_HCCHAR(chidx), hcchar);
+ }
+ }
+ }
+ break;
+
+ case OTGFS_GRXSTSH_PKTSTS_INDONE: /* IN transfer completed */
+ case OTGFS_GRXSTSH_PKTSTS_DTOGERR: /* Data toggle error */
+ case OTGFS_GRXSTSH_PKTSTS_HALTED: /* Channel halted */
+ default:
+ break;
+ }
+
+ /* Re-enable the RxFIFO non-empty interrupt */
+
+ intmsk |= USB_GINT_RXFLVL;
+ efm32_putreg(EFM32_USB_GINTMSK, intmsk);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_nptxfeisr
+ *
+ * Description:
+ * USB OTG FS non-periodic TxFIFO empty interrupt handler
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_nptxfeisr(FAR struct efm32_usbhost_s *priv)
+{
+ FAR struct efm32_chan_s *chan;
+ uint32_t regval;
+ unsigned int wrsize;
+ unsigned int avail;
+ unsigned int chidx;
+
+ /* Recover the index of the channel that is waiting for space in the Tx
+ * FIFO.
+ */
+
+ chidx = priv->chidx;
+ chan = &priv->chan[chidx];
+
+ /* Reduce the buffer size by the number of bytes that were previously placed
+ * in the Tx FIFO.
+ */
+
+ chan->buffer += chan->inflight;
+ chan->buflen -= chan->inflight;
+ chan->inflight = 0;
+
+ /* If we have now transfered the entire buffer, then this transfer is
+ * complete (this case really should never happen because we disable
+ * the NPTXFE interrupt on the final packet).
+ */
+
+ if (chan->buflen <= 0)
+ {
+ /* Disable further Tx FIFO empty interrupts and bail. */
+
+ efm32_modifyreg(EFM32_USB_GINTMSK, USB_GINT_NPTXFE, 0);
+ return;
+ }
+
+ /* Read the status from the top of the non-periodic TxFIFO */
+
+ regval = efm32_getreg(EFM32_USB_HNPTXSTS);
+
+ /* Extract the number of bytes available in the non-periodic Tx FIFO. */
+
+ avail = ((regval & _OTGFS_HNPTXSTS_NPTXFSAV_MASK) >> _OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) << 2;
+
+ /* Get minimal size packet that can be sent. Something is seriously
+ * configured wrong if one packet will not fit into the empty Tx FIFO.
+ */
+
+ DEBUGASSERT(chan->buflen > 0 &&
+ avail >= MIN(chan->buflen, chan->maxpacket));
+
+ /* Get the size to put in the Tx FIFO now */
+
+ wrsize = chan->buflen;
+ if (wrsize > avail)
+ {
+ /* Clip the write size to the number of full, max sized packets
+ * that will fit in the Tx FIFO.
+ */
+
+ unsigned int wrpackets = avail / chan->maxpacket;
+ wrsize = wrpackets * chan->maxpacket;
+ }
+
+ /* Otherwise, this will be the last packet to be sent in this transaction.
+ * We now need to disable further NPTXFE interrupts.
+ */
+
+ else
+ {
+ efm32_modifyreg(EFM32_USB_GINTMSK, USB_GINT_NPTXFE, 0);
+ }
+
+ /* Write the next group of packets into the Tx FIFO */
+
+ ullvdbg("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n",
+ regval, chidx, avail, chan->buflen, wrsize);
+
+ efm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_ptxfeisr
+ *
+ * Description:
+ * USB OTG FS periodic TxFIFO empty interrupt handler
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_ptxfeisr(FAR struct efm32_usbhost_s *priv)
+{
+ FAR struct efm32_chan_s *chan;
+ uint32_t regval;
+ unsigned int wrsize;
+ unsigned int avail;
+ unsigned int chidx;
+
+ /* Recover the index of the channel that is waiting for space in the Tx
+ * FIFO.
+ */
+
+ chidx = priv->chidx;
+ chan = &priv->chan[chidx];
+
+ /* Reduce the buffer size by the number of bytes that were previously placed
+ * in the Tx FIFO.
+ */
+
+ chan->buffer += chan->inflight;
+ chan->buflen -= chan->inflight;
+ chan->inflight = 0;
+
+ /* If we have now transfered the entire buffer, then this transfer is
+ * complete (this case really should never happen because we disable
+ * the PTXFE interrupt on the final packet).
+ */
+
+ if (chan->buflen <= 0)
+ {
+ /* Disable further Tx FIFO empty interrupts and bail. */
+
+ efm32_modifyreg(EFM32_USB_GINTMSK, USB_GINT_PTXFE, 0);
+ return;
+ }
+
+ /* Read the status from the top of the periodic TxFIFO */
+
+ regval = efm32_getreg(EFM32_USB_HPTXSTS);
+
+ /* Extract the number of bytes available in the periodic Tx FIFO. */
+
+ avail = ((regval & _OTGFS_HPTXSTS_PTXFSAVL_MASK) >> _OTGFS_HPTXSTS_PTXFSAVL_SHIFT) << 2;
+
+ /* Get minimal size packet that can be sent. Something is seriously
+ * configured wrong if one packet will not fit into the empty Tx FIFO.
+ */
+
+ DEBUGASSERT(chan->buflen > 0 &&
+ avail >= MIN(chan->buflen, chan->maxpacket));
+
+ /* Get the size to put in the Tx FIFO now */
+
+ wrsize = chan->buflen;
+ if (wrsize > avail)
+ {
+ /* Clip the write size to the number of full, max sized packets
+ * that will fit in the Tx FIFO.
+ */
+
+ unsigned int wrpackets = avail / chan->maxpacket;
+ wrsize = wrpackets * chan->maxpacket;
+ }
+
+ /* Otherwise, this will be the last packet to be sent in this transaction.
+ * We now need to disable further PTXFE interrupts.
+ */
+
+ else
+ {
+ efm32_modifyreg(EFM32_USB_GINTMSK, USB_GINT_PTXFE, 0);
+ }
+
+ /* Write the next group of packets into the Tx FIFO */
+
+ ullvdbg("HPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n",
+ regval, chidx, avail, chan->buflen, wrsize);
+
+ efm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_hcisr
+ *
+ * Description:
+ * USB OTG FS host channels interrupt handler
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_hcisr(FAR struct efm32_usbhost_s *priv)
+{
+ uint32_t haint;
+ uint32_t hcchar;
+ int i = 0;
+
+ /* Read the Host all channels interrupt register and test each bit in the
+ * register. Each bit i, i=0...(EFM32_NHOST_CHANNELS-1), corresponds to
+ * a pending interrupt on channel i.
+ */
+
+ haint = efm32_getreg(EFM32_USB_HAINT);
+ for (i = 0; i < EFM32_NHOST_CHANNELS; i++)
+ {
+ /* Is an interrupt pending on this channel? */
+
+ if ((haint & OTGFS_HAINT(i)) != 0)
+ {
+ /* Yes... read the HCCHAR register to get the direction bit */
+
+ hcchar = efm32_getreg(EFM32_USB_HCCHAR(i));
+
+ /* Was this an interrupt on an IN or an OUT channel? */
+
+ if ((hcchar & OTGFS_HCCHAR_EPDIR) != 0)
+ {
+ /* Handle the HC IN channel interrupt */
+
+ efm32_gint_hcinisr(priv, i);
+ }
+ else
+ {
+ /* Handle the HC OUT channel interrupt */
+
+ efm32_gint_hcoutisr(priv, i);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_hprtisr
+ *
+ * Description:
+ * USB OTG FS host port interrupt handler
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_hprtisr(FAR struct efm32_usbhost_s *priv)
+{
+ uint32_t hprt;
+ uint32_t newhprt;
+ uint32_t hcfg;
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT, 0);
+ /* Read the port status and control register (HPRT) */
+
+ hprt = efm32_getreg(EFM32_USB_HPRT);
+
+ /* Setup to clear the interrupt bits in GINTSTS by setting the corresponding
+ * bits in the HPRT. The HCINT interrupt bit is cleared when the appropriate
+ * status bits in the HPRT register are cleared.
+ */
+
+ newhprt = hprt & ~(OTGFS_HPRT_PENA | OTGFS_HPRT_PCDET |
+ OTGFS_HPRT_PENCHNG | OTGFS_HPRT_POCCHNG);
+
+ /* Check for Port Overcurrent CHaNGe (POCCHNG) */
+
+ if ((hprt & OTGFS_HPRT_POCCHNG) != 0)
+ {
+ /* Set up to clear the POCCHNG status in the new HPRT contents. */
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_POCCHNG, 0);
+ newhprt |= OTGFS_HPRT_POCCHNG;
+ }
+
+ /* Check for Port Connect DETected (PCDET). The core sets this bit when a
+ * device connection is detected.
+ */
+
+ if ((hprt & OTGFS_HPRT_PCDET) != 0)
+ {
+ /* Set up to clear the PCDET status in the new HPRT contents. Then
+ * process the new connection event.
+ */
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_PCDET, 0);
+ newhprt |= OTGFS_HPRT_PCDET;
+ efm32_portreset(priv);
+ efm32_gint_connected(priv);
+ }
+
+ /* Check for Port Enable CHaNGed (PENCHNG) */
+
+ if ((hprt & OTGFS_HPRT_PENCHNG) != 0)
+ {
+ /* Set up to clear the PENCHNG status in the new HPRT contents. */
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_PENCHNG, 0);
+ newhprt |= OTGFS_HPRT_PENCHNG;
+
+ /* Was the port enabled? */
+
+ if ((hprt & OTGFS_HPRT_PENA) != 0)
+ {
+ /* Yes.. handle the new connection event */
+
+ efm32_gint_connected(priv);
+
+ /* Check the Host ConFiGuration register (HCFG) */
+
+ hcfg = efm32_getreg(EFM32_USB_HCFG);
+
+ /* Is this a low speed or full speed connection (OTG FS does not
+ * support high speed)
+ */
+
+ if ((hprt & _OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_LS)
+ {
+ /* Set the Host Frame Interval Register for the 6KHz speed */
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_LSDEV, 0);
+ efm32_putreg(EFM32_USB_HFIR, 6000);
+
+ /* Are we switching from FS to LS? */
+
+ if ((hcfg & _OTGFS_HCFG_FSLSPCS_MASK) != OTGFS_HCFG_FSLSPCS_LS6MHz)
+ {
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_FSLSSW, 0);
+ /* Yes... configure for LS */
+
+ hcfg &= ~_OTGFS_HCFG_FSLSPCS_MASK;
+ hcfg |= OTGFS_HCFG_FSLSPCS_LS6MHz;
+ efm32_putreg(EFM32_USB_HCFG, hcfg);
+
+ /* And reset the port */
+
+ efm32_portreset(priv);
+ }
+ }
+ else /* if ((hprt & _OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_FS) */
+ {
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_FSDEV, 0);
+ efm32_putreg(EFM32_USB_HFIR, 48000);
+
+ /* Are we switching from LS to FS? */
+
+ if ((hcfg & _OTGFS_HCFG_FSLSPCS_MASK) != OTGFS_HCFG_FSLSPCS_FS48MHz)
+ {
+
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_LSFSSW, 0);
+ /* Yes... configure for FS */
+
+ hcfg &= ~_OTGFS_HCFG_FSLSPCS_MASK;
+ hcfg |= OTGFS_HCFG_FSLSPCS_FS48MHz;
+ efm32_putreg(EFM32_USB_HCFG, hcfg);
+
+ /* And reset the port */
+
+ efm32_portreset(priv);
+ }
+ }
+ }
+ }
+
+ /* Clear port interrupts by setting bits in the HPRT */
+
+ efm32_putreg(EFM32_USB_HPRT, newhprt);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_discisr
+ *
+ * Description:
+ * USB OTG FS disconnect detected interrupt handler
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_discisr(FAR struct efm32_usbhost_s *priv)
+{
+ /* Handle the disconnection event */
+
+ efm32_gint_disconnected(priv);
+
+ /* Clear the dicsonnect interrupt */
+
+ efm32_putreg(EFM32_USB_GINTSTS, USB_GINT_DISC);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_ipxfrisr
+ *
+ * Description:
+ * USB OTG FS incomplete periodic interrupt handler
+ *
+ *******************************************************************************/
+
+static inline void efm32_gint_ipxfrisr(FAR struct efm32_usbhost_s *priv)
+{
+ uint32_t regval;
+
+ /* CHENA : Set to enable the channel
+ * CHDIS : Set to stop transmitting/receiving data on a channel
+ */
+
+ regval = efm32_getreg(EFM32_USB_HCCHAR(0));
+ regval |= (OTGFS_HCCHAR_CHDIS | OTGFS_HCCHAR_CHENA);
+ efm32_putreg(EFM32_USB_HCCHAR(0), regval);
+
+ /* Clear the incomplete isochronous OUT interrupt */
+
+ efm32_putreg(EFM32_USB_GINTSTS, USB_GINT_IPXFR);
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_isr
+ *
+ * Description:
+ * USB OTG FS global interrupt handler
+ *
+ *******************************************************************************/
+
+static int efm32_gint_isr(int irq, FAR void *context)
+{
+ /* At present, there is only support for a single OTG FS host. Hence it is
+ * pre-allocated as g_usbhost. However, in most code, the private data
+ * structure will be referenced using the 'priv' pointer (rather than the
+ * global data) in order to simplify any future support for multiple devices.
+ */
+
+ FAR struct efm32_usbhost_s *priv = &g_usbhost;
+ uint32_t pending;
+
+ /* If OTG were supported, we would need to check if we are in host or
+ * device mode when the global interrupt occurs. Here we support only
+ * host mode
+ */
+
+ /* Loop while there are pending interrupts to process. This loop may save a
+ * little interrupt handling overhead.
+ */
+
+ for (;;)
+ {
+ /* Get the unmasked bits in the GINT status */
+
+ pending = efm32_getreg(EFM32_USB_GINTSTS);
+ pending &= efm32_getreg(EFM32_USB_GINTMSK);
+
+ /* Return from the interrupt when there are no furhter pending
+ * interrupts.
+ */
+
+ if (pending == 0)
+ {
+ return OK;
+ }
+
+ /* Otherwise, process each pending, unmasked GINT interrupts */
+
+
+ /* Handle the start of frame interrupt */
+
+#ifdef CONFIG_EFM32_OTGFS_SOFINTR
+ if ((pending & USB_GINT_SOF) != 0)
+ {
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_SOF, 0);
+ efm32_gint_sofisr(priv);
+ }
+#endif
+
+ /* Handle the RxFIFO non-empty interrupt */
+
+ if ((pending & USB_GINT_RXFLVL) != 0)
+ {
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_RXFLVL, 0);
+ efm32_gint_rxflvlisr(priv);
+ }
+
+ /* Handle the non-periodic TxFIFO empty interrupt */
+
+ if ((pending & USB_GINT_NPTXFE) != 0)
+ {
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_NPTXFE, 0);
+ efm32_gint_nptxfeisr(priv);
+ }
+
+ /* Handle the periodic TxFIFO empty interrupt */
+
+ if ((pending & USB_GINT_PTXFE) != 0)
+ {
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_PTXFE, 0);
+ efm32_gint_ptxfeisr(priv);
+ }
+
+ /* Handle the host channels interrupt */
+
+ if ((pending & USB_GINT_HC) != 0)
+ {
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_HC, 0);
+ efm32_gint_hcisr(priv);
+ }
+
+ /* Handle the host port interrupt */
+
+ if ((pending & USB_GINT_HPRT) != 0)
+ {
+ efm32_gint_hprtisr(priv);
+ }
+
+ /* Handle the disconnect detected interrupt */
+
+ if ((pending & USB_GINT_DISC) != 0)
+ {
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_DISC, 0);
+ efm32_gint_discisr(priv);
+ }
+
+ /* Handle the incomplete periodic transfer */
+
+ if ((pending & USB_GINT_IPXFR) != 0)
+ {
+ usbhost_vtrace1(OTGFS_VTRACE1_GINT_IPXFR, 0);
+ efm32_gint_ipxfrisr(priv);
+ }
+ }
+
+ /* We won't get here */
+
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_gint_enable and efm32_gint_disable
+ *
+ * Description:
+ * Respectively enable or disable the global OTG FS interrupt.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ *******************************************************************************/
+
+static void efm32_gint_enable(void)
+{
+ uint32_t regval;
+
+ /* Set the GINTMSK bit to unmask the interrupt */
+
+ regval = efm32_getreg(EFM32_USB_GAHBCFG);
+ regval |= USB_GAHBCFG_GINTMSK;
+ efm32_putreg(EFM32_USB_GAHBCFG, regval);
+}
+
+static void efm32_gint_disable(void)
+{
+ uint32_t regval;
+
+ /* Clear the GINTMSK bit to mask the interrupt */
+
+ regval = efm32_getreg(EFM32_USB_GAHBCFG);
+ regval &= ~USB_GAHBCFG_GINTMSK;
+ efm32_putreg(EFM32_USB_GAHBCFG, regval);
+}
+
+/*******************************************************************************
+ * Name: efm32_hostinit_enable
+ *
+ * Description:
+ * Enable host interrupts.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ *******************************************************************************/
+
+static inline void efm32_hostinit_enable(void)
+{
+ uint32_t regval;
+
+ /* Disable all interrupts. */
+
+ efm32_putreg(EFM32_USB_GINTMSK, 0);
+
+ /* Clear any pending interrupts. */
+
+ efm32_putreg(EFM32_USB_GINTSTS, 0xffffffff);
+
+ /* Clear any pending USB OTG Interrupts (should be done elsewhere if OTG is supported) */
+
+ efm32_putreg(EFM32_USB_GOTGINT, 0xffffffff);
+
+ /* Clear any pending USB OTG interrupts */
+
+ efm32_putreg(EFM32_USB_GINTSTS, 0xbfffffff);
+
+ /* Enable the host interrupts */
+ /* Common interrupts:
+ *
+ * USB_GINT_WKUP : Resume/remote wakeup detected interrupt
+ * USB_GINT_USBSUSP : USB suspend
+ */
+
+ regval = (USB_GINT_WKUP | USB_GINT_USBSUSP);
+
+ /* If OTG were supported, we would need to enable the following as well:
+ *
+ * USB_GINT_OTG : OTG interrupt
+ * USB_GINT_SRQ : Session request/new session detected interrupt
+ * USB_GINT_CIDSCHG : Connector ID status change
+ */
+
+ /* Host-specific interrupts
+ *
+ * USB_GINT_SOF : Start of frame
+ * USB_GINT_RXFLVL : RxFIFO non-empty
+ * USB_GINT_IISOOXFR : Incomplete isochronous OUT transfer
+ * USB_GINT_HPRT : Host port interrupt
+ * USB_GINT_HC : Host channels interrupt
+ * USB_GINT_DISC : Disconnect detected interrupt
+ */
+
+#ifdef CONFIG_EFM32_OTGFS_SOFINTR
+ regval |= (USB_GINT_SOF | USB_GINT_RXFLVL | USB_GINT_IISOOXFR |
+ USB_GINT_HPRT | USB_GINT_HC | USB_GINT_DISC);
+#else
+ regval |= (USB_GINT_RXFLVL | USB_GINT_IPXFR | USB_GINT_HPRT |
+ USB_GINT_HC | USB_GINT_DISC);
+#endif
+ efm32_putreg(EFM32_USB_GINTMSK, regval);
+}
+
+/*******************************************************************************
+ * Name: efm32_txfe_enable
+ *
+ * Description:
+ * Enable Tx FIFO empty interrupts. This is necessary when the entire
+ * transfer will not fit into Tx FIFO. The transfer will then be completed
+ * when the Tx FIFO is empty. NOTE: The Tx FIFO interrupt is disabled
+ * the fifo empty interrupt handler when the transfer is complete.
+ *
+ * Input Parameters:
+ * priv - Driver state structure reference
+ * chidx - The channel that requires the Tx FIFO empty interrupt
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called from user task context. Interrupts must be disabled to assure
+ * exclusive access to the GINTMSK register.
+ *
+ *******************************************************************************/
+
+static void efm32_txfe_enable(FAR struct efm32_usbhost_s *priv, int chidx)
+{
+ FAR struct efm32_chan_s *chan = &priv->chan[chidx];
+ irqstate_t flags;
+ uint32_t regval;
+
+ /* Disable all interrupts so that we have exclusive access to the GINTMSK
+ * (it would be sufficent just to disable the GINT interrupt).
+ */
+
+ flags = irqsave();
+
+ /* Should we enable the periodic or non-peridic Tx FIFO empty interrupts */
+
+ regval = efm32_getreg(EFM32_USB_GINTMSK);
+ switch (chan->eptype)
+ {
+ default:
+ case OTGFS_EPTYPE_CTRL: /* Non periodic transfer */
+ case OTGFS_EPTYPE_BULK:
+ regval |= USB_GINT_NPTXFE;
+ break;
+
+ case OTGFS_EPTYPE_INTR: /* Periodic transfer */
+ case OTGFS_EPTYPE_ISOC:
+ regval |= USB_GINT_PTXFE;
+ break;
+ }
+
+ /* Enable interrupts */
+
+ efm32_putreg(EFM32_USB_GINTMSK, regval);
+ irqrestore(flags);
+}
+
+/*******************************************************************************
+ * USB Host Controller Operations
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: efm32_wait
+ *
+ * Description:
+ * Wait for a device to be connected or disconneced.
+ *
+ * Input Parameters:
+ * conn - The USB host connection instance obtained as a parameter from the call to
+ * the USB driver initialization logic.
+ * connected - A pointer to a boolean value. TRUE: Wait for device to be
+ * connected; FALSE: wait for device to be disconnected
+ *
+ * Returned Values:
+ * Zero (OK) is returned when a device in connected. This function will not
+ * return until either (1) a device is connected or (2) some failure occurs.
+ * On a failure, a negated errno value is returned indicating the nature of
+ * the failure
+ *
+ * Assumptions:
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int efm32_wait(FAR struct usbhost_connection_s *conn,
+ FAR const bool *connected)
+{
+ FAR struct efm32_usbhost_s *priv = &g_usbhost;
+ irqstate_t flags;
+
+ /* Are we already connected? */
+
+ flags = irqsave();
+ while (priv->connected == *connected)
+ {
+ /* No... wait for the connection/disconnection */
+
+ priv->eventwait = true;
+ efm32_takesem(&priv->eventsem);
+ }
+
+ irqrestore(flags);
+
+ udbg("Connected:%s\n", priv->connected ? "YES" : "NO");
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_enumerate
+ *
+ * Description:
+ * Enumerate the connected device. As part of this enumeration process,
+ * the driver will (1) get the device's configuration descriptor, (2)
+ * extract the class ID info from the configuration descriptor, (3) call
+ * usbhost_findclass() to find the class that supports this device, (4)
+ * call the create() method on the struct usbhost_registry_s interface
+ * to get a class instance, and finally (5) call the configdesc() method
+ * of the struct usbhost_class_s interface. After that, the class is in
+ * charge of the sequence of operations.
+ *
+ * Input Parameters:
+ * conn - The USB host connection instance obtained as a parameter from the call to
+ * the USB driver initialization logic.
+ * rphndx - Root hub port index. 0-(n-1) corresponds to root hub port 1-n.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int efm32_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
+{
+ FAR struct efm32_usbhost_s *priv = &g_usbhost;
+ uint32_t regval;
+ int chidx;
+ int ret;
+
+ DEBUGASSERT(priv && rhpndx == 0);
+
+ /* Are we connected to a device? The caller should have called the wait()
+ * method first to be assured that a device is connected.
+ */
+
+ while (!priv->connected)
+ {
+ /* No, return an error */
+
+ usbhost_trace1(OTGFS_TRACE1_DEVDISCONN,0);
+ return -ENODEV;
+ }
+
+ DEBUGASSERT(priv->smstate == SMSTATE_ATTACHED);
+
+ /* Allocate and initialize the control OUT channel */
+
+ chidx = efm32_chan_alloc(priv);
+ DEBUGASSERT(chidx >= 0);
+
+ priv->ep0out = chidx;
+ priv->chan[chidx].epno = 0;
+ priv->chan[chidx].in = false;
+ priv->chan[chidx].eptype = OTGFS_EPTYPE_CTRL;
+ priv->chan[chidx].maxpacket = EFM32_EP0_DEF_PACKET_SIZE;
+ priv->chan[chidx].indata1 = false;
+ priv->chan[chidx].outdata1 = false;
+
+ /* Allocate and initialize the control IN channel */
+
+ chidx = efm32_chan_alloc(priv);
+ DEBUGASSERT(chidx >= 0);
+
+ priv->ep0in = chidx;
+ priv->chan[chidx].epno = 0;
+ priv->chan[chidx].in = true;
+ priv->chan[chidx].eptype = OTGFS_EPTYPE_CTRL;
+ priv->chan[chidx].maxpacket = EFM32_EP0_DEF_PACKET_SIZE;
+ priv->chan[chidx].indata1 = false;
+ priv->chan[chidx].outdata1 = false;
+
+ /* USB 2.0 spec says at least 50ms delay before port reset. We wait 100ms. */
+
+ usleep(100*1000);
+
+ /* Reset the host port */
+
+ efm32_portreset(priv);
+
+ /* Get the current device speed */
+
+ regval = efm32_getreg(EFM32_USB_HPRT);
+ priv->lowspeed = ((regval & _OTGFS_HPRT_PSPD_MASK) == OTGFS_HPRT_PSPD_LS);
+
+ /* Configure control channels */
+
+ efm32_chan_configure(priv, priv->ep0out);
+ efm32_chan_configure(priv, priv->ep0in);
+
+ /* Let the common usbhost_enumerate do all of the real work. Note that the
+ * FunctionAddress (USB address) is hardcoded to one.
+ */
+
+ uvdbg("Enumerate the device\n");
+ priv->smstate = SMSTATE_ENUM;
+ ret = usbhost_enumerate(&g_usbhost.drvr, 1, &priv->class);
+
+ /* The enumeration may fail either because of some HCD interfaces failure
+ * or because the device class is not supported. In either case, we just
+ * need to perform the disconnection operation and make ready for a new
+ * enumeration.
+ */
+
+ if (ret < 0)
+ {
+ /* Return to the disconnected state */
+
+ efm32_gint_disconnected(priv);
+ }
+
+ return ret;
+}
+
+/************************************************************************************
+ * Name: efm32_ep0configure
+ *
+ * Description:
+ * Configure endpoint 0. This method is normally used internally by the
+ * enumerate() method but is made available at the interface to support an
+ * external implementation of the enumeration logic.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * funcaddr - The USB address of the function containing the endpoint that EP0
+ * controls
+ * maxpacketsize - The maximum number of bytes that can be sent to or
+ * received from the endpoint in a single data packet
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int efm32_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
+ uint16_t maxpacketsize)
+{
+ FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr;
+
+ DEBUGASSERT(drvr && funcaddr < 128 && maxpacketsize < 2048);
+
+ /* We must have exclusive access to the USB host hardware and state structures */
+
+ efm32_takesem(&priv->exclsem);
+
+ /* Save the device address and EP0 max packet size */
+
+ priv->devaddr = funcaddr;
+ priv->ep0size = maxpacketsize;
+
+ /* Configure the EP0 OUT channel */
+
+ priv->chan[priv->ep0out].maxpacket = maxpacketsize;
+ efm32_chan_configure(priv, priv->ep0out);
+
+ /* Configure the EP0 IN channel */
+
+ priv->chan[priv->ep0in].maxpacket = maxpacketsize;
+ efm32_chan_configure(priv, priv->ep0in);
+
+ efm32_givesem(&priv->exclsem);
+ return OK;
+}
+
+/************************************************************************************
+ * Name: efm32_getdevinfo
+ *
+ * Description:
+ * Get information about the connected device.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * devinfo - A pointer to memory provided by the caller in which to return the
+ * device information.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int efm32_getdevinfo(FAR struct usbhost_driver_s *drvr,
+ FAR struct usbhost_devinfo_s *devinfo)
+{
+ FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr;
+
+ DEBUGASSERT(drvr && devinfo);
+ devinfo->speed = priv->lowspeed ? DEVINFO_SPEED_LOW : DEVINFO_SPEED_FULL;
+ return OK;
+}
+
+/************************************************************************************
+ * Name: efm32_epalloc
+ *
+ * Description:
+ * Allocate and configure one endpoint.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * epdesc - Describes the endpoint to be allocated.
+ * ep - A memory location provided by the caller in which to receive the
+ * allocated endpoint descriptor.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int efm32_epalloc(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usbhost_epdesc_s *epdesc,
+ FAR usbhost_ep_t *ep)
+{
+ FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr;
+ FAR struct efm32_chan_s *chan;
+ int chidx;
+ int ret;
+
+ /* Sanity check. NOTE that this method should only be called if a device is
+ * connected (because we need a valid low speed indication).
+ */
+
+ DEBUGASSERT(priv && epdesc && ep && priv->connected);
+
+ /* We must have exclusive access to the USB host hardware and state structures */
+
+ efm32_takesem(&priv->exclsem);
+
+ /* Allocate a host channel for the endpoint */
+
+ chidx = efm32_chan_alloc(priv);
+ if (chidx < 0)
+ {
+ udbg("Failed to allocate a host channel\n");
+ ret = -ENOMEM;
+ goto errout;
+ }
+
+ /* Decode the endpoint descriptor to initialize the channel data structures.
+ * Note: Here we depend on the fact that the endpoint point type is
+ * encoded in the same way in the endpoint descriptor as it is in the OTG
+ * FS hardware.
+ */
+
+ chan = &priv->chan[chidx];
+ chan->epno = epdesc->addr & USB_EPNO_MASK;
+ chan->in = epdesc->in;
+ chan->eptype = epdesc->xfrtype;
+ chan->maxpacket = epdesc->mxpacketsize;
+ chan->indata1 = false;
+ chan->outdata1 = false;
+
+ /* Then configure the endpoint */
+
+ efm32_chan_configure(priv, chidx);
+
+ /* Return the index to the allocated channel as the endpoint "handle" */
+
+ *ep = (usbhost_ep_t)chidx;
+ ret = OK;
+
+errout:
+ efm32_givesem(&priv->exclsem);
+ return ret;
+}
+
+/************************************************************************************
+ * Name: efm32_epfree
+ *
+ * Description:
+ * Free and endpoint previously allocated by DRVR_EPALLOC.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * ep - The endpoint to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int efm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
+{
+ struct efm32_usbhost_s *priv = (struct efm32_usbhost_s *)drvr;
+ int chidx = (int)ep;
+
+ DEBUGASSERT(priv && chidx < EFM32_MAX_TX_FIFOS);
+
+ /* We must have exclusive access to the USB host hardware and state structures */
+
+ efm32_takesem(&priv->exclsem);
+
+ /* Halt the channel and mark the channel avaiable */
+
+ efm32_chan_free(priv, chidx);
+
+ efm32_givesem(&priv->exclsem);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_alloc
+ *
+ * Description:
+ * Some hardware supports special memory in which request and descriptor data can
+ * be accessed more efficiently. This method provides a mechanism to allocate
+ * the request/descriptor memory. If the underlying hardware does not support
+ * such "special" memory, this functions may simply map to kmm_malloc.
+ *
+ * This interface was optimized under a particular assumption. It was assumed
+ * that the driver maintains a pool of small, pre-allocated buffers for descriptor
+ * traffic. NOTE that size is not an input, but an output: The size of the
+ * pre-allocated buffer is returned.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * buffer - The address of a memory location provided by the caller in which to
+ * return the allocated buffer memory address.
+ * maxlen - The address of a memory location provided by the caller in which to
+ * return the maximum size of the allocated buffer memory.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int efm32_alloc(FAR struct usbhost_driver_s *drvr,
+ FAR uint8_t **buffer, FAR size_t *maxlen)
+{
+ FAR uint8_t *alloc;
+
+ DEBUGASSERT(drvr && buffer && maxlen);
+
+ /* There is no special memory requirement for the EFM32. */
+
+ alloc = (FAR uint8_t *)kmm_malloc(CONFIG_EFM32_OTGFS_DESCSIZE);
+ if (!alloc)
+ {
+ return -ENOMEM;
+ }
+
+ /* Return the allocated address and size of the descriptor buffer */
+
+ *buffer = alloc;
+ *maxlen = CONFIG_EFM32_OTGFS_DESCSIZE;
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_free
+ *
+ * Description:
+ * Some hardware supports special memory in which request and descriptor data can
+ * be accessed more efficiently. This method provides a mechanism to free that
+ * request/descriptor memory. If the underlying hardware does not support
+ * such "special" memory, this functions may simply map to kmm_free().
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * buffer - The address of the allocated buffer memory to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int efm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
+{
+ /* There is no special memory requirement */
+
+ DEBUGASSERT(drvr && buffer);
+ kmm_free(buffer);
+ return OK;
+}
+
+/************************************************************************************
+ * Name: efm32_ioalloc
+ *
+ * Description:
+ * Some hardware supports special memory in which larger IO buffers can
+ * be accessed more efficiently. This method provides a mechanism to allocate
+ * the request/descriptor memory. If the underlying hardware does not support
+ * such "special" memory, this functions may simply map to kmm_malloc.
+ *
+ * This interface differs from DRVR_ALLOC in that the buffers are variable-sized.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * buffer - The address of a memory location provided by the caller in which to
+ * return the allocated buffer memory address.
+ * buflen - The size of the buffer required.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int efm32_ioalloc(FAR struct usbhost_driver_s *drvr,
+ FAR uint8_t **buffer, size_t buflen)
+{
+ FAR uint8_t *alloc;
+
+ DEBUGASSERT(drvr && buffer && buflen > 0);
+
+ /* There is no special memory requirement */
+
+ alloc = (FAR uint8_t *)kmm_malloc(buflen);
+ if (!alloc)
+ {
+ return -ENOMEM;
+ }
+
+ /* Return the allocated buffer */
+
+ *buffer = alloc;
+ return OK;
+}
+
+/************************************************************************************
+ * Name: efm32_iofree
+ *
+ * Description:
+ * Some hardware supports special memory in which IO data can be accessed more
+ * efficiently. This method provides a mechanism to free that IO buffer
+ * memory. If the underlying hardware does not support such "special" memory,
+ * this functions may simply map to kmm_free().
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * buffer - The address of the allocated buffer memory to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int efm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
+{
+ /* There is no special memory requirement */
+
+ DEBUGASSERT(drvr && buffer);
+ kmm_free(buffer);
+ return OK;
+}
+
+/*******************************************************************************
+ * Name: efm32_ctrlin and efm32_ctrlout
+ *
+ * Description:
+ * Process a IN or OUT request on the control endpoint. These methods
+ * will enqueue the request and wait for it to complete. Only one transfer may be
+ * queued; Neither these methods nor the transfer() method can be called again
+ * until the control transfer functions returns.
+ *
+ * These are blocking methods; these functions will not return until the
+ * control transfer has completed.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * req - Describes the request to be sent. This request must lie in memory
+ * created by DRVR_ALLOC.
+ * buffer - A buffer used for sending the request and for returning any
+ * responses. This buffer must be large enough to hold the length value
+ * in the request description. buffer must have been allocated using DRVR_ALLOC
+ *
+ * NOTE: On an IN transaction, req and buffer may refer to the same allocated
+ * memory.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int efm32_ctrlin(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR uint8_t *buffer)
+{
+ struct efm32_usbhost_s *priv = (struct efm32_usbhost_s *)drvr;
+ uint16_t buflen;
+ uint32_t start;
+ uint32_t elapsed;
+ int retries;
+ int ret;
+
+ DEBUGASSERT(drvr && req);
+ usbhost_vtrace2(OTGFS_VTRACE2_CTRLIN, req->type, req->req);
+ uvdbg("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n",
+ req->type, req->req, req->value[1], req->value[0],
+ req->index[1], req->index[0], req->len[1], req->len[0]);
+
+ /* Extract values from the request */
+
+ buflen = efm32_getle16(req->len);
+
+ /* We must have exclusive access to the USB host hardware and state structures */
+
+ efm32_takesem(&priv->exclsem);
+
+ /* Loop, retrying until the retry time expires */
+
+ for (retries = 0; retries < EFM32_RETRY_COUNT; retries++)
+ {
+ /* Send the SETUP request */
+
+ ret = efm32_ctrl_sendsetup(priv, req);
+ if (ret < 0)
+ {
+ usbhost_trace1(OTGFS_TRACE1_SENDSETUP, -ret);
+ continue;
+ }
+
+ /* Get the start time. Loop again until the timeout expires */
+
+ start = clock_systimer();
+ do
+ {
+ /* Handle the IN data phase (if any) */
+
+ if (buflen > 0)
+ {
+ ret = efm32_ctrl_recvdata(priv, buffer, buflen);
+ if (ret < 0)
+ {
+ usbhost_trace1(OTGFS_TRACE1_RECVDATA, -ret);
+ }
+ }
+
+ /* Handle the status OUT phase */
+
+ if (ret == OK)
+ {
+ priv->chan[priv->ep0out].outdata1 ^= true;
+ ret = efm32_ctrl_senddata(priv, NULL, 0);
+ if (ret == OK)
+ {
+ /* All success transactions exit here */
+
+ efm32_givesem(&priv->exclsem);
+ return OK;
+ }
+
+ usbhost_trace1(OTGFS_TRACE1_SENDDATA, ret < 0 ? -ret : ret);
+ }
+
+ /* Get the elapsed time (in frames) */
+
+ elapsed = clock_systimer() - start;
+ }
+ while (elapsed < EFM32_DATANAK_DELAY);
+ }
+
+ /* All failures exit here after all retries and timeouts have been exhausted */
+
+ efm32_givesem(&priv->exclsem);
+ return -ETIMEDOUT;
+}
+
+static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr,
+ FAR const struct usb_ctrlreq_s *req,
+ FAR const uint8_t *buffer)
+{
+ struct efm32_usbhost_s *priv = (struct efm32_usbhost_s *)drvr;
+ uint16_t buflen;
+ uint32_t start;
+ uint32_t elapsed;
+ int retries;
+ int ret;
+
+ DEBUGASSERT(drvr && req);
+ usbhost_vtrace2(OTGFS_VTRACE2_CTRLOUT, req->type, req->req);
+ uvdbg("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n",
+ req->type, req->req, req->value[1], req->value[0],
+ req->index[1], req->index[0], req->len[1], req->len[0]);
+
+ /* Extract values from the request */
+
+ buflen = efm32_getle16(req->len);
+
+ /* We must have exclusive access to the USB host hardware and state structures */
+
+ efm32_takesem(&priv->exclsem);
+
+ /* Loop, retrying until the retry time expires */
+
+ for (retries = 0; retries < EFM32_RETRY_COUNT; retries++)
+ {
+ /* Send the SETUP request */
+
+ /* Send the SETUP request */
+
+ ret = efm32_ctrl_sendsetup(priv, req);
+ if (ret < 0)
+ {
+ usbhost_trace1(OTGFS_TRACE1_SENDSETUP, -ret);
+ continue;
+ }
+
+ /* Get the start time. Loop again until the timeout expires */
+
+ start = clock_systimer();
+ do
+ {
+ /* Handle the data OUT phase (if any) */
+
+ if (buflen > 0)
+ {
+ /* Start DATA out transfer (only one DATA packet) */
+
+ priv->chan[priv->ep0out].outdata1 = true;
+ ret = efm32_ctrl_senddata(priv, NULL, 0);
+ if (ret < 0)
+ {
+ usbhost_trace1(OTGFS_TRACE1_SENDDATA, -ret);
+ }
+ }
+
+ /* Handle the status IN phase */
+
+ if (ret == OK)
+ {
+ ret = efm32_ctrl_recvdata(priv, NULL, 0);
+ if (ret == OK)
+ {
+ /* All success transactins exit here */
+
+ efm32_givesem(&priv->exclsem);
+ return OK;
+ }
+
+ usbhost_trace1(OTGFS_TRACE1_RECVDATA, ret < 0 ? -ret : ret);
+ }
+
+ /* Get the elapsed time (in frames) */
+
+ elapsed = clock_systimer() - start;
+ }
+ while (elapsed < EFM32_DATANAK_DELAY);
+ }
+
+ /* All failures exit here after all retries and timeouts have been exhausted */
+
+ efm32_givesem(&priv->exclsem);
+ return -ETIMEDOUT;
+}
+
+/*******************************************************************************
+ * Name: efm32_transfer
+ *
+ * Description:
+ * Process a request to handle a transfer descriptor. This method will
+ * enqueue the transfer request and return immediately. Only one transfer may be
+ * queued; Neither this method nor the ctrlin or ctrlout methods can be called
+ * again until this function returns.
+ *
+ * This is a blocking method; this functions will not return until the
+ * transfer has completed.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * ep - The IN or OUT endpoint descriptor for the device endpoint on which to
+ * perform the transfer.
+ * buffer - A buffer containing the data to be sent (OUT endpoint) or received
+ * (IN endpoint). buffer must have been allocated using DRVR_ALLOC
+ * buflen - The length of the data to be sent or received.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure:
+ *
+ * EAGAIN - If devices NAKs the transfer (or NYET or other error where
+ * it may be appropriate to restart the entire transaction).
+ * EPERM - If the endpoint stalls
+ * EIO - On a TX or data toggle error
+ * EPIPE - Overrun errors
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Called from a single thread so no mutual exclusion is required.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static int efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
+ FAR uint8_t *buffer, size_t buflen)
+{
+ FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr;
+ unsigned int chidx = (unsigned int)ep;
+ int ret;
+
+ uvdbg("chidx: %d buflen: %d\n", (unsigned int)ep, buflen);
+
+ DEBUGASSERT(priv && buffer && chidx < EFM32_MAX_TX_FIFOS && buflen > 0);
+
+ /* We must have exclusive access to the USB host hardware and state structures */
+
+ efm32_takesem(&priv->exclsem);
+
+ /* Handle IN and OUT transfer slightly differently */
+
+ if (priv->chan[chidx].in)
+ {
+ ret = efm32_in_transfer(priv, chidx, buffer, buflen);
+ }
+ else
+ {
+ ret = efm32_out_transfer(priv, chidx, buffer, buflen);
+ }
+
+ efm32_givesem(&priv->exclsem);
+ return ret;
+}
+
+/*******************************************************************************
+ * Name: efm32_disconnect
+ *
+ * Description:
+ * Called by the class when an error occurs and driver has been disconnected.
+ * The USB host driver should discard the handle to the class instance (it is
+ * stale) and not attempt any further interaction with the class driver instance
+ * (until a new instance is received from the create() method). The driver
+ * should not called the class' disconnected() method.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ *
+ * Returned Values:
+ * None
+ *
+ * Assumptions:
+ * - Only a single class bound to a single device is supported.
+ * - Never called from an interrupt handler.
+ *
+ *******************************************************************************/
+
+static void efm32_disconnect(FAR struct usbhost_driver_s *drvr)
+{
+ struct efm32_usbhost_s *priv = (struct efm32_usbhost_s *)drvr;
+ DEBUGASSERT(priv);
+
+ priv->class = NULL;
+}
+
+/*******************************************************************************
+ * Initialization
+ *******************************************************************************/
+/*******************************************************************************
+ * Name: efm32_portreset
+ *
+ * Description:
+ * Reset the USB host port.
+ *
+ * NOTE: "Before starting to drive a USB reset, the application waits for the
+ * OTG interrupt triggered by the debounce done bit (DBCDNE bit in
+ * OTG_FS_GOTGINT), which indicates that the bus is stable again after the
+ * electrical debounce caused by the attachment of a pull-up resistor on DP
+ * (FS) or DM (LS).
+ *
+ * Input Parameters:
+ * priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ * None
+ *
+ *******************************************************************************/
+
+static void efm32_portreset(FAR struct efm32_usbhost_s *priv)
+{
+ uint32_t regval;
+
+ regval = efm32_getreg(EFM32_USB_HPRT);
+ regval &= ~(OTGFS_HPRT_PENA|OTGFS_HPRT_PCDET|OTGFS_HPRT_PENCHNG|OTGFS_HPRT_POCCHNG);
+ regval |= OTGFS_HPRT_PRST;
+ efm32_putreg(EFM32_USB_HPRT, regval);
+
+ up_mdelay(20);
+
+ regval &= ~OTGFS_HPRT_PRST;
+ efm32_putreg(EFM32_USB_HPRT, regval);
+
+ up_mdelay(20);
+}
+
+/*******************************************************************************
+ * Name: efm32_flush_txfifos
+ *
+ * Description:
+ * Flush the selected Tx FIFO.
+ *
+ * Input Parameters:
+ * txfnum -- USB host driver private data structure.
+ *
+ * Returned Value:
+ * None.
+ *
+ *******************************************************************************/
+
+static void efm32_flush_txfifos(uint32_t txfnum)
+{
+ uint32_t regval;
+ uint32_t timeout;
+
+ /* Initiate the TX FIFO flush operation */
+
+ regval = USB_GRSTCTL_TXFFLSH | txfnum;
+ efm32_putreg(regval, EFM32_USB_GRSTCTL);
+
+ /* Wait for the FLUSH to complete */
+
+ for (timeout = 0; timeout < EFM32_FLUSH_DELAY; timeout++)
+ {
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_TXFFLSH) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Wait for 3 PHY Clocks */
+
+ up_udelay(3);
+}
+
+/*******************************************************************************
+ * Name: efm32_flush_rxfifo
+ *
+ * Description:
+ * Flush the Rx FIFO.
+ *
+ * Input Parameters:
+ * priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ * None.
+ *
+ *******************************************************************************/
+
+static void efm32_flush_rxfifo(void)
+{
+ uint32_t regval;
+ uint32_t timeout;
+
+ /* Initiate the RX FIFO flush operation */
+
+ efm32_putreg(USB_GRSTCTL_RXFFLSH, EFM32_USB_GRSTCTL);
+
+ /* Wait for the FLUSH to complete */
+
+ for (timeout = 0; timeout < EFM32_FLUSH_DELAY; timeout++)
+ {
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_RXFFLSH) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Wait for 3 PHY Clocks */
+
+ up_udelay(3);
+}
+
+/*******************************************************************************
+ * Name: efm32_vbusdrive
+ *
+ * Description:
+ * Drive the Vbus +5V.
+ *
+ * Input Parameters:
+ * priv - USB host driver private data structure.
+ * state - True: Drive, False: Don't drive
+ *
+ * Returned Value:
+ * None.
+ *
+ *******************************************************************************/
+
+static void efm32_vbusdrive(FAR struct efm32_usbhost_s *priv, bool state)
+{
+ uint32_t regval;
+
+ /* Enable/disable the external charge pump */
+
+ efm32_usbhost_vbusdrive(0, state);
+
+ /* Turn on the Host port power. */
+
+ regval = efm32_getreg(EFM32_USB_HPRT);
+ regval &= ~(OTGFS_HPRT_PENA|OTGFS_HPRT_PCDET|OTGFS_HPRT_PENCHNG|OTGFS_HPRT_POCCHNG);
+
+ if (((regval & OTGFS_HPRT_PPWR) == 0) && state)
+ {
+ regval |= OTGFS_HPRT_PPWR;
+ efm32_putreg(EFM32_USB_HPRT, regval);
+ }
+
+ if (((regval & OTGFS_HPRT_PPWR) != 0) && !state)
+ {
+ regval &= ~OTGFS_HPRT_PPWR;
+ efm32_putreg(EFM32_USB_HPRT, regval);
+ }
+
+ up_mdelay(200);
+}
+
+/*******************************************************************************
+ * Name: efm32_host_initialize
+ *
+ * Description:
+ * Initialize/re-initialize hardware for host mode operation. At present,
+ * this function is called only from efm32_hw_initialize(). But if OTG mode
+ * were supported, this function would also be called to swtich between
+ * host and device modes on a connector ID change interrupt.
+ *
+ * Input Parameters:
+ * priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ * None.
+ *
+ *******************************************************************************/
+
+static void efm32_host_initialize(FAR struct efm32_usbhost_s *priv)
+{
+ uint32_t regval;
+ uint32_t offset;
+ int i;
+
+ /* Restart the PHY Clock */
+
+ efm32_putreg(EFM32_USB_PCGCCTL, 0);
+
+ /* Initialize Host Configuration (HCFG) register */
+
+ regval = efm32_getreg(EFM32_USB_HCFG);
+ regval &= ~_OTGFS_HCFG_FSLSPCS_MASK;
+ regval |= OTGFS_HCFG_FSLSPCS_FS48MHz;
+ efm32_putreg(EFM32_USB_HCFG, regval);
+
+ /* Reset the host port */
+
+ efm32_portreset(priv);
+
+ /* Clear the FS-/LS-only support bit in the HCFG register */
+
+ regval = efm32_getreg(EFM32_USB_HCFG);
+ regval &= ~OTGFS_HCFG_FSLSS;
+ efm32_putreg(EFM32_USB_HCFG, regval);
+
+ /* Carve up FIFO memory for the Rx FIFO and the periodic and non-periodic Tx FIFOs */
+ /* Configure Rx FIFO size (GRXFSIZ) */
+
+ efm32_putreg(EFM32_USB_GRXFSIZ, CONFIG_EFM32_OTGFS_RXFIFO_SIZE);
+ offset = CONFIG_EFM32_OTGFS_RXFIFO_SIZE;
+
+ /* Setup the host non-periodic Tx FIFO size (HNPTXFSIZ) */
+
+ regval = (offset | (CONFIG_EFM32_OTGFS_NPTXFIFO_SIZE << _OTGFS_HNPTXFSIZ_NPTXFD_SHIFT));
+ efm32_putreg(EFM32_USB_HNPTXFSIZ, regval);
+ offset += CONFIG_EFM32_OTGFS_NPTXFIFO_SIZE;
+
+ /* Set up the host periodic Tx fifo size register (HPTXFSIZ) */
+
+ regval = (offset | (CONFIG_EFM32_OTGFS_PTXFIFO_SIZE << _OTGFS_HPTXFSIZ_PTXFD_SHIFT));
+ efm32_putreg(EFM32_USB_HPTXFSIZ, regval);
+
+ /* If OTG were supported, we sould need to clear HNP enable bit in the
+ * USB_OTG control register about here.
+ */
+
+ /* Flush all FIFOs */
+
+ efm32_flush_txfifos(USB_GRSTCTL_TXFNUM_HALL);
+ efm32_flush_rxfifo();
+
+ /* Clear all pending HC Interrupts */
+
+ for (i = 0; i < EFM32_NHOST_CHANNELS; i++)
+ {
+ efm32_putreg(EFM32_USB_HCINT(i), 0xffffffff);
+ efm32_putreg(EFM32_USB_HCINTMSK(i), 0);
+ }
+
+ /* Driver Vbus +5V (the smoke test). Should be done elsewhere in OTG
+ * mode.
+ */
+
+ efm32_vbusdrive(priv, true);
+
+ /* Enable host interrupts */
+
+ efm32_hostinit_enable();
+}
+
+/*******************************************************************************
+ * Name: efm32_sw_initialize
+ *
+ * Description:
+ * One-time setup of the host driver state structure.
+ *
+ * Input Parameters:
+ * priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ * None.
+ *
+ *******************************************************************************/
+
+static inline void efm32_sw_initialize(FAR struct efm32_usbhost_s *priv)
+{
+ int i;
+
+ /* Initialize the state data structure */
+
+ sem_init(&priv->eventsem, 0, 0);
+ sem_init(&priv->exclsem, 0, 1);
+
+ priv->smstate = SMSTATE_DETACHED;
+ priv->ep0size = EFM32_EP0_MAX_PACKET_SIZE;
+ priv->devaddr = EFM32_DEF_DEVADDR;
+ priv->connected = false;
+ priv->lowspeed = false;
+
+ /* Put all of the channels back in their initial, allocated state */
+
+ memset(priv->chan, 0, EFM32_MAX_TX_FIFOS * sizeof(struct efm32_chan_s));
+
+ /* Initialize each channel */
+
+ for (i = 0; i < EFM32_MAX_TX_FIFOS; i++)
+ {
+ FAR struct efm32_chan_s *chan = &priv->chan[i];
+ sem_init(&chan->waitsem, 0, 0);
+ }
+}
+
+/*******************************************************************************
+ * Name: efm32_hw_initialize
+ *
+ * Description:
+ * One-time setup of the host controller harware for normal operations.
+ *
+ * Input Parameters:
+ * priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure.
+ *
+ *******************************************************************************/
+
+static inline int efm32_hw_initialize(FAR struct efm32_usbhost_s *priv)
+{
+ uint32_t regval;
+ unsigned long timeout;
+
+ /* "To initialize the core as host, the application must perform the
+ * following steps.
+ * 1. Program USB_GINTMSK.PRTINT to unmask.
+ * 2. Program the USB_HCFG register to select full-speed host.
+ * 3. Program the USB_HPRT.PRTPWR bit to 1. This drives VBUS on the USB.
+ * 4. Wait for the USB_HPRT.PRTCONNDET interrupt. This indicates that a
+ * device is connect to the port.
+ * 5. Program the USB_HPRT.PRTRST bit to 1. This starts the reset process.
+ * 6. Wait at least 10 ms for the reset process to complete.
+ * 7. Program the USB_HPRT.PRTRST bit to 0.
+ * 8. Wait for the USB_HPRT.PRTENCHNG interrupt.
+ * 9. Read the USB_HPRT.PRTSPD field to get the enumerated speed.
+ * 10. Program the USB_HFIR register with a value corresponding to the
+ * selected PHY clock. At this point, the host is up and running and
+ * the port register begins to report device disconnects, etc. The
+ * port is active with SOFs occurring down the enabled port.
+ * 11. Program the RXFSIZE register to select the size of the receive FIFO.
+ * 12. Program the NPTXFSIZE register to select the size and the start
+ * address of the Non-periodic Transmit FIFO for non-periodic
+ * transactions.
+ * 13. Program the USB_HPTXFSIZ register to select the size and start
+ * address of the Periodic Transmit FIFO for periodic transactions."
+ */
+#warning Review for missing logic
+
+ /* Set the PHYSEL bit in the GUSBCFG register to select the OTG FS serial
+ * transceiver: "This bit is always 1 with write-only access"
+ */
+
+ regval = efm32_getreg(EFM32_USB_GUSBCFG);;
+ regval |= USB_GUSBCFG_PHYSEL;
+ efm32_putreg(EFM32_USB_GUSBCFG, regval);
+
+ /* Reset after a PHY select and set Host mode. First, wait for AHB master
+ * IDLE state.
+ */
+
+ for (timeout = 0; timeout < EFM32_READY_DELAY; timeout++)
+ {
+ up_udelay(3);
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_AHBIDL) != 0)
+ {
+ break;
+ }
+ }
+
+ /* Then perform the core soft reset. */
+
+ efm32_putreg(EFM32_USB_GRSTCTL, USB_GRSTCTL_CSRST);
+ for (timeout = 0; timeout < EFM32_READY_DELAY; timeout++)
+ {
+ regval = efm32_getreg(EFM32_USB_GRSTCTL);
+ if ((regval & USB_GRSTCTL_CSRST) == 0)
+ {
+ break;
+ }
+ }
+
+ /* Wait for 3 PHY Clocks */
+
+ up_udelay(3);
+
+ /* Deactivate the power down */
+
+ regval = (USB_GCCFG_PWRDWN | USB_GCCFG_VBUSASEN | USB_GCCFG_VBUSBSEN);
+#ifndef CONFIG_USBDEV_VBUSSENSING
+ regval |= USB_GCCFG_NOVBUSSENS;
+#endif
+#ifdef CONFIG_EFM32_OTGFS_SOFOUTPUT
+ regval |= USB_GCCFG_SOFOUTEN;
+#endif
+ efm32_putreg(EFM32_USB_GCCFG, regval);
+ up_mdelay(20);
+
+ /* Initialize OTG features: In order to support OTP, the HNPCAP and SRPCAP
+ * bits would need to be set in the GUSBCFG register about here.
+ */
+
+ /* Force Host Mode */
+
+ regval = efm32_getreg(EFM32_USB_GUSBCFG);
+ regval &= ~USB_GUSBCFG_FDMOD;
+ regval |= USB_GUSBCFG_FHMOD;
+ efm32_putreg(EFM32_USB_GUSBCFG, regval);
+ up_mdelay(50);
+
+ /* Initialize host mode and return success */
+
+ efm32_host_initialize(priv);
+ return OK;
+}
+
+/*******************************************************************************
+ * Public Functions
+ *******************************************************************************/
+
+/*******************************************************************************
+ * Name: efm32_otgfshost_initialize
+ *
+ * Description:
+ * Initialize USB host device controller hardware.
+ *
+ * Input Parameters:
+ * controller -- If the device supports more than USB host controller, then
+ * this identifies which controller is being initialized. Normally, this
+ * is just zero.
+ *
+ * Returned Value:
+ * And instance of the USB host interface. The controlling task should
+ * use this interface to (1) call the wait() method to wait for a device
+ * to be connected, and (2) call the enumerate() method to bind the device
+ * to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ * to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ * Otherwise, there is a race condition if the device is already connected.
+ *
+ *******************************************************************************/
+
+FAR struct usbhost_connection_s *efm32_otgfshost_initialize(int controller)
+{
+ /* At present, there is only support for a single OTG FS host. Hence it is
+ * pre-allocated as g_usbhost. However, in most code, the private data
+ * structure will be referenced using the 'priv' pointer (rather than the
+ * global data) in order to simplify any future support for multiple devices.
+ */
+
+ FAR struct efm32_usbhost_s *priv = &g_usbhost;
+
+ /* Sanity checks */
+
+ DEBUGASSERT(controller == 0);
+
+ /* "The USB requires the device to run from a 48 MHz crystal (2500 ppm or
+ * better). The core part of the USB will always run from HFCORECLKUSBC
+ * which is HFCLK undivided (48 MHz). The current consumption for the
+ * rest of the device can be reduced by dividing down HFCORECLK using
+ * the CMU_HFCORECLKDIV register. ..."
+ *
+ * "Follow these steps to enable the USB:
+ * 1. Enable the clock to the system part by setting USB in
+ * CMU_HFCORECLKEN0.
+ * 2. If the internal USB regulator is bypassed (by applying 3.3V on
+ * USB_VREGI and USB_VREGO externally), disable the regulator by
+ * setting VREGDIS in USB_CTRL.
+ * 3. If the PHY is powered from VBUS using the internal regulator, the
+ * VREGO sense circuit should be enabled by setting VREGOSEN in
+ * USB_CTRL.
+ * 4. Enable the USB PHY pins by setting PHYPEN in USB_ROUTE.
+ * 5. If host or OTG dual-role device, set VBUSENAP in USB_CTRL to the
+ * desired value and then enable the USB_VBUSEN pin in USB_ROUTE. Set
+ * the MODE for the pin to PUSHPULL.
+ * 6. If low-speed device, set DMPUAP in USB_CTRL to the desired value
+ * and then enable the USB_DMPU pin in USB_ROUTE. Set the MODE for the
+ * pin to PUSHPULL.
+ * 7. Make sure HFXO is ready and selected. The core part requires the
+ * undivided HFCLK to be 48 MHz when USB is active (during
+ * suspend/session-off a 32 kHz clock is used)..
+ * 8. Enable the clock to the core part by setting USBC in
+ * CMU_HFCORECLKEN0.
+ * 9. Wait for the core to come out of reset. This is easiest done by
+ * polling a core register with non-zero reset value until it reads a
+ * non-zero value. This takes approximately 20 48-MHz cycles.
+ * 10. Start initializing the USB core ..."
+ */
+#warning Missing Logic
+
+ /* Make sure that interrupts from the OTG FS core are disabled */
+
+ efm32_gint_disable();
+
+ /* Reset the state of the host driver */
+
+ efm32_sw_initialize(priv);
+
+ /* Initialize the USB OTG FS core */
+
+ efm32_hw_initialize(priv);
+
+ /* Attach USB host controller interrupt handler */
+
+ if (irq_attach(EFM32_IRQ_USB, efm32_gint_isr) != 0)
+ {
+ usbhost_trace1(OTGFS_TRACE1_IRQATTACH, 0);
+ return NULL;
+ }
+
+ /* Enable USB OTG FS global interrupts */
+
+ efm32_gint_enable();
+
+ /* Enable interrupts at the interrupt controller */
+
+ up_enable_irq(EFM32_IRQ_USB);
+ return &g_usbconn;
+}
+
+#endif /* CONFIG_USBHOST && CONFIG_EFM32_OTGFS */