You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/05/24 01:55:01 UTC
[nuttx] 01/04: arch/nrf53: add USBD support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 0117260d8cedb2e259f8fbe24d8209a886173d93
Author: raiden00pl <ra...@railab.me>
AuthorDate: Sun May 21 12:47:42 2023 +0200
arch/nrf53: add USBD support
USB device role is now supported for NRF53
---
arch/arm/src/nrf53/Kconfig | 10 +-
arch/arm/src/nrf53/Make.defs | 4 +
.../src/nrf53/hardware/nrf53_memorymap_cpuapp.h | 2 +-
arch/arm/src/nrf53/hardware/nrf53_usbd.h | 394 +++
arch/arm/src/nrf53/hardware/nrf53_usbreg.h | 62 +
arch/arm/src/nrf53/nrf53_usbd.c | 3195 ++++++++++++++++++++
arch/arm/src/nrf53/nrf53_usbd.h | 62 +
7 files changed, 3726 insertions(+), 3 deletions(-)
diff --git a/arch/arm/src/nrf53/Kconfig b/arch/arm/src/nrf53/Kconfig
index 8b13d2e0e6..3c9976c62d 100644
--- a/arch/arm/src/nrf53/Kconfig
+++ b/arch/arm/src/nrf53/Kconfig
@@ -23,7 +23,7 @@ config NRF53_APPCORE
select ARM_HAVE_DSP
select ARCH_HAVE_FPU
select NRF53_HAVE_PWM
- select NRF52_HAVE_GPIOTE1
+ select NRF53_HAVE_GPIOTE1
select NRF53_HAVE_SAADC
select NRF53_HAVE_UART1
select NRF53_HAVE_I2C123
@@ -252,6 +252,12 @@ config NRF53_RTC1
select NRF53_RTC
default n
+config NRF53_USBDEV
+ bool "USB Device"
+ default n
+ depends on NRF53_HFCLK_XTAL
+ select USBDEV
+
endmenu # NRF53 Peripheral Selection
menu "Clock Configuration"
@@ -613,7 +619,7 @@ config NRF53_SDC_PERIPHERAL_COUNT
CENTRAL_ROLES = CONFIG_BLUETOOTH_MAX_CONN - NRF53_SDC_PERIPHERAL_COUNT
or
- CENTRAL_ROLES = NRF52_SDC_MAX_COUNT - NRF52_SDC_PERIPHERAL_COUNT
+ CENTRAL_ROLES = NRF53_SDC_MAX_COUNT - NRF53_SDC_PERIPHERAL_COUNT
So by choosing these two variables you can control both capabilities.
diff --git a/arch/arm/src/nrf53/Make.defs b/arch/arm/src/nrf53/Make.defs
index 0227178801..b56975db25 100644
--- a/arch/arm/src/nrf53/Make.defs
+++ b/arch/arm/src/nrf53/Make.defs
@@ -91,6 +91,10 @@ ifeq ($(CONFIG_NRF53_I2C_MASTER),y)
CHIP_CSRCS += nrf53_i2c.c
endif
+ifeq ($(CONFIG_USBDEV),y)
+CHIP_CSRCS += nrf53_usbd.c
+endif
+
ifeq ($(CONFIG_NRF53_SOFTDEVICE_CONTROLLER),y)
NRFXLIB_UNPACK := sdk-nrfxlib
diff --git a/arch/arm/src/nrf53/hardware/nrf53_memorymap_cpuapp.h b/arch/arm/src/nrf53/hardware/nrf53_memorymap_cpuapp.h
index 5ffa4f94a5..85c0a97324 100644
--- a/arch/arm/src/nrf53/hardware/nrf53_memorymap_cpuapp.h
+++ b/arch/arm/src/nrf53/hardware/nrf53_memorymap_cpuapp.h
@@ -101,7 +101,7 @@
#define NRF53_MUTEX_BASE 0x50030000
#define NRF53_QDEC_BASE 0x50033000
#define NRF53_USBD_BASE 0x50036000
-#define NRF53_USBREGULATOR_BASE 0x50037000
+#define NRF53_USBREG_BASE 0x50037000
#define NRF53_KMU_BASE 0x50039000
#define NRF53_NVMC_BASE 0x50039000
#define NRF53_GPIO_P0_BASE 0x50842500
diff --git a/arch/arm/src/nrf53/hardware/nrf53_usbd.h b/arch/arm/src/nrf53/hardware/nrf53_usbd.h
new file mode 100644
index 0000000000..f0af98a154
--- /dev/null
+++ b/arch/arm/src/nrf53/hardware/nrf53_usbd.h
@@ -0,0 +1,394 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/hardware/nrf53_usbd.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_USBD_H
+#define __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_USBD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+#include "hardware/nrf53_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NRF53_USBD_INOUT_NENDPOINTS (7)
+
+/* Register offsets *********************************************************/
+
+#define NRF53_USBD_TASKS_STARTEPIN_OFFSET(n) (0x0004 + (0x04 * n))
+#define NRF53_USBD_TASKS_STARTISOIN_OFFSET (0x0024)
+#define NRF53_USBD_TASKS_STARTEPOUT_OFFSET(n) (0x0028 + (0x04 * n))
+#define NRF53_USBD_TASKS_STARTISOOUT_OFFSET (0x0048)
+#define NRF53_USBD_TASKS_EP0RCVOUT_OFFSET (0x004c)
+#define NRF53_USBD_TASKS_EP0STATUS_OFFSET (0x0050)
+#define NRF53_USBD_TASKS_EP0STALL_OFFSET (0x0054)
+#define NRF53_USBD_TASKS_DPDMDRIVE_OFFSET (0x0058)
+#define NRF53_USBD_TASKS_PDPMNODRIVE_OFFSET (0x005c)
+#define NRF53_USBD_EVENTS_USBRESET_OFFSET (0x0100)
+#define NRF53_USBD_EVENTS_ENDEPIN_OFFSET(n) (0x0108 + (0x04 * n))
+#define NRF53_USBD_EVENTS_EP0DATADONE_OFFSET (0x0128)
+#define NRF53_USBD_EVENTS_ENDISOIN_OFFSET (0x012c)
+#define NRF53_USBD_EVENTS_ENDEPOUT_OFFSET(n) (0x0130 + (0x04 * n))
+#define NRF53_USBD_EVENTS_ENDISOOUT_OFFSET (0x0150)
+#define NRF53_USBD_EVENTS_SOF_OFFSET (0x0154)
+#define NRF53_USBD_EVENTS_USBEVENT_OFFSET (0x0158)
+#define NRF53_USBD_EVENTS_EP0SETUP_OFFSET (0x015c)
+#define NRF53_USBD_EVENTS_EPDATA_OFFSET (0x0160)
+#define NRF53_USBD_SHORTS_OFFSET (0x0200)
+#define NRF53_USBD_INTEN_OFFSET (0x0300)
+#define NRF53_USBD_INTENSET_OFFSET (0x0304)
+#define NRF53_USBD_INTENCLR_OFFSET (0x0308)
+#define NRF53_USBD_EVENTCAUSE_OFFSET (0x0400)
+#define NRF53_USBD_HALTED_EPIN_OFFSET(n) (0x0420 + (0x04 * n))
+#define NRF53_USBD_HALTED_EPOUT_OFFSET(n) (0x0444 + (0x04 * n))
+#define NRF53_USBD_EPSTATUS_OFFSET (0x0468)
+#define NRF53_USBD_EPDATASTATUS_OFFSET (0x046c)
+#define NRF53_USBD_USBADDR_OFFSET (0x0470)
+#define NRF53_USBD_BMREQUESTTYPE_OFFSET (0x0480)
+#define NRF53_USBD_BREQUEST_OFFSET (0x0484)
+#define NRF53_USBD_WVALUEL_OFFSET (0x0488)
+#define NRF53_USBD_WVALUEH_OFFSET (0x048c)
+#define NRF53_USBD_WINDEXL_OFFSET (0x0490)
+#define NRF53_USBD_WINDEXH_OFFSET (0x0494)
+#define NRF53_USBD_WLENGTHL_OFFSET (0x0498)
+#define NRF53_USBD_WLENGTHH_OFFSET (0x049c)
+#define NRF53_USBD_SIZE_EPOUT_OFFSET(n) (0x04A0 + (0x04 * n))
+#define NRF53_USBD_SIZE_ISOOUT_OFFSET (0x04c0)
+#define NRF53_USBD_ENABLE_OFFSET (0x0500)
+#define NRF53_USBD_USBPULLUP_OFFSET (0x0504)
+#define NRF53_USBD_DPDMVALUE_OFFSET (0x0508)
+#define NRF53_USBD_DTOGGLE_OFFSET (0x050C)
+#define NRF53_USBD_EPINEN_OFFSET (0x0510)
+#define NRF53_USBD_EPOUTEN_OFFSET (0x0514)
+#define NRF53_USBD_EPSTALL_OFFSET (0x0518)
+#define NRF53_USBD_ISOSPLIT_OFFSET (0x051c)
+#define NRF53_USBD_FRAMECNTR_OFFSET (0x0520)
+#define NRF53_USBD_LOWPOWER_OFFSET (0x052c)
+#define NRF53_USBD_ISOINCONFIG_OFFSET (0x0530)
+#define NRF53_USBD_EPIN_PTR_OFFSET(n) (0x0600 + (0x14 * n))
+#define NRF53_USBD_EPIN_MAXCNT_OFFSET(n) (0x0604 + (0x14 * n))
+#define NRF53_USBD_EPIN_AMOUNT_OFFSET(n) (0x0608 + (0x14 * n))
+#define NRF53_USBD_ISOIN_PTR_OFFSET (0x06a0)
+#define NRF53_USBD_ISOIN_MAXCNT_OFFSET (0x06a4)
+#define NRF53_USBD_ISOIN_AMOUNT_OFFSET (0x06a8)
+#define NRF53_USBD_EPOUT_PTR_OFFSET(n) (0x0700 + (0x14 * n))
+#define NRF53_USBD_EPOUT_MAXCNT_OFFSET(n) (0x0704 + (0x14 * n))
+#define NRF53_USBD_EPOUT_AMOUNT_OFFSET(n) (0x0708 + (0x14 * n))
+#define NRF53_USBD_ISOOUT_PTR_OFFSET (0x07a0)
+#define NRF53_USBD_ISOOUT_MAXCNT_OFFSET (0x07a4)
+#define NRF53_USBD_ISOOUT_AMOUNT_OFFSET (0x07a8)
+
+/* Register addresses *******************************************************/
+
+#define NRF53_USBD_TASKS_STARTEPIN(n) (NRF53_USBD_BASE + NRF53_USBD_TASKS_STARTEPIN_OFFSET(n))
+#define NRF53_USBD_TASKS_STARTISOIN (NRF53_USBD_BASE + NRF53_USBD_TASKS_STARTISOIN_OFFSET)
+#define NRF53_USBD_TASKS_STARTEPOUT(n) (NRF53_USBD_BASE + NRF53_USBD_TASKS_STARTEPOUT_OFFSET(n))
+#define NRF53_USBD_TASKS_STARTISOOUT (NRF53_USBD_BASE + NRF53_USBD_TASKS_STARTISOOUT_OFFSET)
+#define NRF53_USBD_TASKS_EP0RCVOUT (NRF53_USBD_BASE + NRF53_USBD_TASKS_EP0RCVOUT_OFFSET)
+#define NRF53_USBD_TASKS_EP0STATUS (NRF53_USBD_BASE + NRF53_USBD_TASKS_EP0STATUS_OFFSET)
+#define NRF53_USBD_TASKS_EP0STALL (NRF53_USBD_BASE + NRF53_USBD_TASKS_EP0STALL_OFFSET)
+#define NRF53_USBD_TASKS_DPDMDRIVE (NRF53_USBD_BASE + NRF53_USBD_TASKS_DPDMDRIVE_OFFSET)
+#define NRF53_USBD_TASKS_PDPMNODRIVE (NRF53_USBD_BASE + NRF53_USBD_TASKS_PDPMNODRIVE_OFFSET)
+#define NRF53_USBD_EVENTS_USBRESET (NRF53_USBD_BASE + NRF53_USBD_EVENTS_USBRESET_OFFSET)
+#define NRF53_USBD_EVENTS_ENDEPIN(n) (NRF53_USBD_BASE + NRF53_USBD_EVENTS_ENDEPIN_OFFSET(n))
+#define NRF53_USBD_EVENTS_EP0DATADONE (NRF53_USBD_BASE + NRF53_USBD_EVENTS_EP0DATADONE_OFFSET)
+#define NRF53_USBD_EVENTS_ENDISOIN (NRF53_USBD_BASE + NRF53_USBD_EVENTS_ENDISOIN_OFFSEN)
+#define NRF53_USBD_EVENTS_ENDEPOUT(n) (NRF53_USBD_BASE + NRF53_USBD_EVENTS_ENDEPOUT_OFFSET(n))
+#define NRF53_USBD_EVENTS_ENDISOOUT (NRF53_USBD_BASE + NRF53_USBD_EVENTS_ENDISOOUT_OFFSET)
+#define NRF53_USBD_EVENTS_SOF (NRF53_USBD_BASE + NRF53_USBD_EVENTS_SOF_OFFSET)
+#define NRF53_USBD_EVENTS_USBEVENT (NRF53_USBD_BASE + NRF53_USBD_EVENTS_USBEVENT_OFFSET)
+#define NRF53_USBD_EVENTS_EP0SETUP (NRF53_USBD_BASE + NRF53_USBD_EVENTS_EP0SETUP_OFFSET)
+#define NRF53_USBD_EVENTS_EPDATA (NRF53_USBD_BASE + NRF53_USBD_EVENTS_EPDATA_OFFSET)
+#define NRF53_USBD_SHORTS (NRF53_USBD_BASE + NRF53_USBD_SHORTS_OFFSET)
+#define NRF53_USBD_INTEN (NRF53_USBD_BASE + NRF53_USBD_INTEN_OFFSET)
+#define NRF53_USBD_INTENSET (NRF53_USBD_BASE + NRF53_USBD_INTENSET_OFFSET)
+#define NRF53_USBD_INTENCLR (NRF53_USBD_BASE + NRF53_USBD_INTENCLR_OFFSET)
+#define NRF53_USBD_EVENTCAUSE (NRF53_USBD_BASE + NRF53_USBD_EVENTCAUSE_OFFSET)
+#define NRF53_USBD_HALTED_EPIN(n) (NRF53_USBD_BASE + NRF53_USBD_HALTED_EPIN_OFFSET(n))
+#define NRF53_USBD_HALTED_EPOUT(n) (NRF53_USBD_BASE + NRF53_USBD_HALTED_EPOUT_OFFSET(n))
+#define NRF53_USBD_EPSTATUS (NRF53_USBD_BASE + NRF53_USBD_EPSTATUS_OFFSET)
+#define NRF53_USBD_EPDATASTATUS (NRF53_USBD_BASE + NRF53_USBD_EPDATASTATUS_OFFSET)
+#define NRF53_USBD_USBADDR (NRF53_USBD_BASE + NRF53_USBD_USBADDR_OFFSET)
+#define NRF53_USBD_BMREQUESTTYPE (NRF53_USBD_BASE + NRF53_USBD_BMREQUESTTYPE_OFFSET)
+#define NRF53_USBD_BREQUEST (NRF53_USBD_BASE + NRF53_USBD_BREQUEST_OFFSET)
+#define NRF53_USBD_WVALUEL (NRF53_USBD_BASE + NRF53_USBD_WVALUEL_OFFSET)
+#define NRF53_USBD_WVALUEH (NRF53_USBD_BASE + NRF53_USBD_WVALUEH_OFFSET)
+#define NRF53_USBD_WINDEXL (NRF53_USBD_BASE + NRF53_USBD_WINDEXL_OFFSET)
+#define NRF53_USBD_WINDEXH (NRF53_USBD_BASE + NRF53_USBD_WINDEXH_OFFSET)
+#define NRF53_USBD_WLENGTHL (NRF53_USBD_BASE + NRF53_USBD_WLENGTHL_OFFSET)
+#define NRF53_USBD_WLENGTHH (NRF53_USBD_BASE + NRF53_USBD_WLENGTHH_OFFSET)
+#define NRF53_USBD_SIZE_EPOUT(n) (NRF53_USBD_BASE + NRF53_USBD_SIZE_EPOUT_OFFSET(n))
+#define NRF53_USBD_SIZE_ISOOUT (NRF53_USBD_BASE + NRF53_USBD_SIZE_ISOOUT_OFFSET)
+#define NRF53_USBD_ENABLE (NRF53_USBD_BASE + NRF53_USBD_ENABLE_OFFSET)
+#define NRF53_USBD_USBPULLUP (NRF53_USBD_BASE + NRF53_USBD_USBPULLUP_OFFSET)
+#define NRF53_USBD_DPDMVALUE (NRF53_USBD_BASE + NRF53_USBD_DPDMVALUE_OFFSET)
+#define NRF53_USBD_DTOGGLE (NRF53_USBD_BASE + NRF53_USBD_DTOGGLE_OFFSET)
+#define NRF53_USBD_EPINEN (NRF53_USBD_BASE + NRF53_USBD_EPINEN_OFFSET)
+#define NRF53_USBD_EPOUTEN (NRF53_USBD_BASE + NRF53_USBD_EPOUTEN_OFFSET)
+#define NRF53_USBD_EPSTALL (NRF53_USBD_BASE + NRF53_USBD_EPSTALL_OFFSET)
+#define NRF53_USBD_ISOSPLIT (NRF53_USBD_BASE + NRF53_USBD_ISOSPLIT_OFFSET)
+#define NRF53_USBD_FRAMECNTR (NRF53_USBD_BASE + NRF53_USBD_FRAMECNTR_OFFSET)
+#define NRF53_USBD_LOWPOWER (NRF53_USBD_BASE + NRF53_USBD_LOWPOWER_OFFSET)
+#define NRF53_USBD_ISOINCONFIG (NRF53_USBD_BASE + NRF53_USBD_ISOINCONFIG_OFFSET)
+#define NRF53_USBD_EPIN_PTR(n) (NRF53_USBD_BASE + NRF53_USBD_EPIN_PTR_OFFSET(n))
+#define NRF53_USBD_EPIN_MAXCNT(n) (NRF53_USBD_BASE + NRF53_USBD_EPIN_MAXCNT_OFFSET(n))
+#define NRF53_USBD_EPIN_AMOUNT(n) (NRF53_USBD_BASE + NRF53_USBD_EPIN_AMOUNT_OFFSET(n))
+#define NRF53_USBD_ISOIN_PTR (NRF53_USBD_BASE + NRF53_USBD_ISOIN_PTR_OFFSET)
+#define NRF53_USBD_ISOIN_MAXCNT (NRF53_USBD_BASE + NRF53_USBD_ISOIN_MAXCNT_OFFSET)
+#define NRF53_USBD_ISOIN_AMOUNT (NRF53_USBD_BASE + NRF53_USBD_ISOIN_AMOUNT_OFFSET)
+#define NRF53_USBD_EPOUT_PTR(n) (NRF53_USBD_BASE + NRF53_USBD_EPOUT_PTR_OFFSET(n))
+#define NRF53_USBD_EPOUT_MAXCNT(n) (NRF53_USBD_BASE + NRF53_USBD_EPOUT_MAXCNT_OFFSET(n))
+#define NRF53_USBD_EPOUT_AMOUNT(n) (NRF53_USBD_BASE + NRF53_USBD_EPOUT_AMOUNT_OFFSET(n))
+#define NRF53_USBD_ISOOUT_PTR (NRF53_USBD_BASE + NRF53_USBD_ISOOUT_PTR_OFFSET)
+#define NRF53_USBD_ISOOUT_MAXCNT (NRF53_USBD_BASE + NRF53_USBD_ISOOUT_MAXCNT_OFFSET)
+#define NRF53_USBD_ISOOUT_AMOUNT (NRF53_USBD_BASE + NRF53_USBD_ISOOUT_AMOUNT_OFFSET)
+
+/* Register bit definitions *************************************************/
+
+/* USBD tasks */
+
+#define USBD_TASKS_TRIGGER (1)
+
+/* USBD events */
+
+#define USBD_EVENT_GENERATED (1)
+
+/* USBD shorts */
+
+#define USBD_SHORTS_EP0DATADONE_STARTEPIN0 (1 << 0) /* Shortcut EP0DATADONE->TARTEPIN[0] */
+#define USBD_SHORTS_EP0DATADONE_STARTEPOUT0 (1 << 1) /* Shortcut EP0DATADONE->STARTEPOUT[0] */
+#define USBD_SHORTS_EP0DATADONE_EP0STATUS (1 << 3) /* Shortcut EP0DATADONE->EP0STATUS */
+#define USBD_SHORTS_ENDEPOUT0_EP0STATUS (1 << 4) /* Shortcut ENDEPOUT0->EP0STATUS */
+#define USBD_SHORTS_ENDEPOUT0_EP0RCVOUT (1 << 5) /* Shortcut ENDEPOUT[0]->EP0RCVOUT */
+
+/* USBD interrupts */
+
+#define USBD_INT_USBRESET (1 << 0) /* Enable/disable interrupt USBRESET */
+#define USBD_INT_STARTED (1 << 1) /* Enable/disable interrupt STARTED */
+#define USBD_INT_ENDEPIN(n) (1 << (2 + n)) /* Enable/disable interrupt ENDEPIN[i] */
+#define USBD_INT_EP0DATADONE (1 << 10) /* Enable/disable interrupt EP0DATADONE */
+#define USBD_INT_ENDISOIN (1 << 11) /* Enable/disable interrupt ENDISOIN */
+#define USBD_INT_ENDEPOUT(n) (1 << (12 + n)) /* Enable/disable interrupt ENDEPOUT[i] */
+#define USBD_INT_ENDISOOUT (1 << 20) /* Enable/disable interrupt ENDISOOUT */
+#define USBD_INT_SOF (1 << 21) /* Enable/disable interrupt SOF */
+#define USBD_INT_USBEVENT (1 << 22) /* Enable/disable interrupt USBEVENT */
+#define USBD_INT_EP0SETUP (1 << 23) /* Enable/disable interrupt EP0SETUP */
+#define USBD_INT_EPDATA (1 << 24) /* Enable/disable interrupt EPDATA */
+#define USBD_INT_ALL (0x1fffffff)
+
+/* EVENTCAUSE */
+
+#define USBD_EVENTCAUSE_ISOOUTCRC (1 << 0) /* CRC error */
+#define USBD_EVENTCAUSE_SUSPEND (1 << 8) /* Device suspended */
+#define USBD_EVENTCAUSE_RESUME (1 << 9) /* Device resumed */
+#define USBD_EVENTCAUSE_USBWUALLOWED (1 << 10) /* USB MAC woken up */
+#define USBD_EVENTCAUSE_READY (1 << 11) /* USB device is ready */
+
+/* HALTED.EPIN[n] and HALTED.EPOUT[n] */
+
+#define USBD_HALTED_GETSTATUS (1 << 0) /* Endpoint halted status */
+
+/* EPSTATUS */
+
+#define USBD_EPSTATUS_EPIN(n) (1 << (0 + n)) /* IN endpoint EasyDMA captured */
+#define USBD_EPSTATUS_EPOUT(n) (1 << (16 + n)) /* OUT endpoint EasyDMA captured */
+
+/* EPDATASTATUS */
+
+#define USBD_EPDATASTATUS_EPIN(n) (1 << (0 + n)) /* IN endpoint ACK */
+#define USBD_EPDATASTATUS_EPOUT(n) (1 << (16 + n)) /* OUT endpoint ACK */
+
+/* USBADDR */
+
+#define USBD_USBADDR_MASK (0x7f) /* Device USB address */
+
+/* BMREQUESTTYPE */
+
+#define USBD_BMREQUESTTYPE_RECIP_SHIFT (0) /* Data transfer type */
+#define USBD_BMREQUESTTYPE_RECIP_MASK (0x1f << USBD_BMREQUESTTYPE_RECIP_SHIFT)
+# define USBD_BMREQUESTTYPE_RECIP_DEVICE (0 << USBD_BMREQUESTTYPE_RECIP_SHIFT)
+# define USBD_BMREQUESTTYPE_RECIP_INTERFACE (1 << USBD_BMREQUESTTYPE_RECIP_SHIFT)
+# define USBD_BMREQUESTTYPE_RECIP_ENDPOINT (2 << USBD_BMREQUESTTYPE_RECIP_SHIFT)
+# define USBD_BMREQUESTTYPE_RECIP_OTHER (3 << USBD_BMREQUESTTYPE_RECIP_SHIFT)
+#define USBD_BMREQUESTTYPE_TYPE_SHIFT (5) /* Data transfer type */
+#define USBD_BMREQUESTTYPE_TYPE_MASK (0x3 << USBD_BMREQUESTTYPE_TYPE_SHIFT)
+# define USBD_BMREQUESTTYPE_TYPE_STANDARD (0 << USBD_BMREQUESTTYPE_TYPE_SHIFT)
+# define USBD_BMREQUESTTYPE_TYPE_CLASS (1 << USBD_BMREQUESTTYPE_TYPE_SHIFT)
+# define USBD_BMREQUESTTYPE_TYPE_VENDOR (2 << USBD_BMREQUESTTYPE_TYPE_SHIFT)
+#define USBD_BMREQUESTTYPE_DIR_HOST2DEV (0 << 7) /* Host-to-device */
+#define USBD_BMREQUESTTYPE_DIR_DEV2HOST (1 << 7) /* Device-to-host */
+
+/* BREQUEST */
+
+#define USBD_BREQUEST_MASK (0xff) /* SETUP data, byte 1, bRequest */
+#define USBD_BREQUEST_STD_GET_STATUS (0)
+#define USBD_BREQUEST_STD_CLEAR_FEATURE (1)
+#define USBD_BREQUEST_STD_SET_FEATURE (3)
+#define USBD_BREQUEST_STD_SET_ADDRESS (5)
+#define USBD_BREQUEST_STD_GET_DESCRIPTOR (6)
+#define USBD_BREQUEST_STD_SET_DESCRIPTOR (7)
+#define USBD_BREQUEST_STD_GET_CONFIGURATION (8)
+#define USBD_BREQUEST_STD_SET_CONFIGURATION (9)
+#define USBD_BREQUEST_STD_GET_INTERFACE (10)
+#define USBD_BREQUEST_STD_SET_INTERFACE (11)
+#define USBD_BREQUEST_STD_SYNCH_FRAME (12)
+
+/* WVALUEL */
+
+#define USBD_WVALUEL_MASK (0xff) /* SETUP data, byte 2, LSB of wValue */
+
+/* WVALUEH */
+
+#define USBD_WVALUEH_MASK (0xff) /* SETUP data, byte 3, MSB of wValue */
+
+/* WINDEXL */
+
+#define USBD_WINDEXL_MASK (0xff) /* SETUP data, byte 4, LSB of wIndex */
+
+/* WINDEXH */
+
+#define USBD_WINDEXH_MASK (0xff) /* SETUP data, byte 5, MSB of wIndex */
+
+/* WLENGTHL */
+
+#define USBD_WLENGTHL_MASK (0xff) /* SETUP data, byte 6, LSB of wLength */
+
+/* WLENGTHH */
+
+#define USBD_WLENGTHH_MASK (0xff) /* SETUP data, byte 7, MSB of wLength */
+
+/* SIZE.EPOUT[n] */
+
+#define USBD_SIZE_EPOUT_MASK (0x7f) /* EP OUT last data size */
+
+/* SIZE.ISOOUT */
+
+#define USBD_SIZE_ISOOUT_MASK (0x3ff) /* ISO OUT last data size */
+
+/* ENABLE */
+
+#define USBD_ENABLE_DISABLE (0) /* USB peripheral is disabled */
+#define USBD_ENABLE_ENABLE (1) /* USB peripheral is enabled */
+
+/* USBPULLUP */
+
+#define USBD_USBPULLUP_DISABLE (0) /* Pull-up is disconnected */
+#define USBD_USBPULLUP_ENABLE (1) /* Pull-up is connected to D+ */
+
+/* DPDMVALUE */
+
+#define USBD_DPDMVALUE_STATE_SHIFT (0) /* State D+ and D- lines will be forced into by the DPDMDRIVE task */
+#define USBD_DPDMVALUE_STATE_MASK (0x1f << USBD_DPDMVALUE_STATE_SHIFT)
+# define USBD_DPDMVALUE_STATE_RESUME (1 << USBD_DPDMVALUE_STATE_SHIFT)
+# define USBD_DPDMVALUE_STATE_J (2 << USBD_DPDMVALUE_STATE_SHIFT)
+# define USBD_DPDMVALUE_STATE_K (4 << USBD_DPDMVALUE_STATE_SHIFT)
+
+/* DTOGGLE */
+
+#define USBD_DTOGGLE_EP_SHIFT (0) /* Select bulk endpoint number */
+#define USBD_DTOGGLE_EP_MASK (0x7 << USBD_DTOGGLE_EP_SHIFT)
+# define USBD_DTOGGLE_EP(n) ((n << USBD_DTOGGLE_EP_SHIFT) & USBD_DTOGGLE_EP_MASK)
+#define USBD_DTOGGLE_IO_OUT (0 << 7)
+#define USBD_DTOGGLE_IO_IN (1 << 7)
+#define USBD_DTOGGLE_VALUE_SHIFT (8) /* Data toggle value */
+#define USBD_DTOGGLE_VALUE_MASK (0x3 << USBD_DTOGGLE_VALUE_SHIFT)
+# define USBD_DTOGGLE_VALUE_NOP (0 << USBD_DTOGGLE_VALUE_SHIFT)
+# define USBD_DTOGGLE_VALUE_DATA0 (1 << USBD_DTOGGLE_VALUE_SHIFT)
+# define USBD_DTOGGLE_VALUE_DATA1 (2 << USBD_DTOGGLE_VALUE_SHIFT)
+
+/* EPINEN */
+
+#define USBD_EPINEN_IN(n) (1 << (0 + n)) /* Enable IN endpoint i */
+#define USBD_EPINEN_ISOIN_DISABLE (0 << 8) /* Disable ISO IN endpoint */
+#define USBD_EPINEN_ISOIN_ENABLE (1 << 8) /* Enable ISO IN endpoint */
+
+/* EPOUTEN */
+
+#define USBD_EPOUTEN_OUT(n) (1 << (0 + n)) /* Enable OUT endpoint i */
+#define USBD_EPOUTEN_ISOOUT_DISABLE (0 << 8) /* Disable ISO OUT endpoint */
+#define USBD_EPOUTEN_ISOOUT_ENABLE (1 << 8) /* Enable ISO OUT endpoint */
+
+/* EPSTALL */
+
+#define USBD_EPSTALL_EP_SHIFT (0) /* Select endpoint number */
+#define USBD_EPSTALL_EP_MASK (0x7 << USBD_EPSTALL_EP_SHIFT)
+# define USBD_EPSTALL_EP(n) ((n << USBD_EPSTALL_EP_SHIFT) & USBD_EPSTALL_EP_MASK)
+#define USBD_EPSTALL_IO_OUT (0 << 7) /* Selects OUT endpoint */
+#define USBD_EPSTALL_IO_IN (1 << 7) /* Selects IN endpoint */
+#define USBD_EPSTALL_IO_UNSTALL (0 << 8) /* Don't stall selected endpoint */
+#define USBD_EPSTALL_IO_STALL (1 << 8) /* Stall selected endpoint */
+
+/* ISOSPLIT */
+
+#define USBD_ISOSPLIT_ONEDIR (0x0000)
+#define USBD_ISOSPLIT_HALFIN (0x0080)
+
+/* FRAMECNTR */
+
+#define USBD_FRAMECNTR_MASK (0x7ff)
+
+/* LOWPOWER */
+
+#define USBD_LOWPOWER_NORMAL (0)
+#define USBD_LOWPOWER_LOWPOWER (1)
+
+/* ISOINCONFIG */
+
+#define USBD_ISOINCONFIG_NORESP (0)
+#define USBD_ISOINCONFIG_ZERODATA (1)
+
+/* EPIN[n].MAXCNT */
+
+#define USBD_EPIN_MAXCNT_MASK (0x7f)
+
+/* EPIN[n].AMOUNT */
+
+#define USBD_EPIN_AMOUNT_MASK (0x7f)
+
+/* ISOIN.MAXCNT */
+
+#define USBD_ISOIN_MAXCNT_MASK (0x3ff)
+
+/* ISOIN.AMOUNT */
+
+#define USBD_ISOIN_AMOUNT_MASK (0x3ff)
+
+/* EPOUT[n].MAXCNT */
+
+#define USBD_EPOUT_MAXCNT_MASK (0x7f)
+
+/* EPOUT[n].AMOUNT */
+
+#define USBD_EPOUT_AMOUNT_MASK (0x7f)
+
+/* ISOOUT.MAXCNT */
+
+#define USBD_ISOOUT_MAXCNT_MASK (0x3ff)
+
+/* ISOOUT.AMOUNT */
+
+#define USBD_ISOOUT_AMOUNT_MASK (0x3ff)
+
+#endif /* __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_USBD_H */
diff --git a/arch/arm/src/nrf53/hardware/nrf53_usbreg.h b/arch/arm/src/nrf53/hardware/nrf53_usbreg.h
new file mode 100644
index 0000000000..89742cb157
--- /dev/null
+++ b/arch/arm/src/nrf53/hardware/nrf53_usbreg.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/hardware/nrf53_usbreg.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_USBREG_H
+#define __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_USBREG_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "nrf53_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define NRF53_USBREG_EVENTS_USBDETECTED_OFFSET 0x000100 /* Voltage supply detected on VBUS */
+#define NRF53_USBREG_EVENTS_USBREMOVED_OFFSET 0x000104 /* Voltage supply removed from VBUS*/
+#define NRF53_USBREG_EVENTS_USBPWRRDY_OFFSET 0x000108 /* USB 3.3 V supply ready */
+#define NRF53_USBREG_INTEN_OFFSET 0x000300 /* Enable or disable interrrupt */
+#define NRF53_USBREG_INTENSET_OFFSET 0x000304 /* Enable interrrupt */
+#define NRF53_USBREG_INTENCLR_OFFSET 0x000308 /* Disable interrrupt */
+#define NRF53_USBREG_USBREGSTATUS_OFFSET 0x000400 /* USB supply status */
+
+/* Register definitions *****************************************************/
+
+#define NRF53_USBREG_EVENTS_USBDETECTED (NRF53_USBREG_BASE + NRF53_USBREG_EVENTS_USBDETECTED_OFFSET)
+#define NRF53_USBREG_EVENTS_USBREMOVED (NRF53_USBREG_BASE + NRF53_USBREG_EVENTS_USBREMOVED_OFFSET)
+#define NRF53_USBREG_EVENTS_USBPWRRDY (NRF53_USBREG_BASE + NRF53_USBREG_EVENTS_USBPWRRDY_OFFSET)
+#define NRF53_USBREG_INTEN (NRF53_USBREG_BASE + NRF53_USBREG_INTEN_OFFSET)
+#define NRF53_USBREG_INTENSET (NRF53_USBREG_BASE + NRF53_USBREG_INTENSET_OFFSET)
+#define NRF53_USBREG_INTENCLR (NRF53_USBREG_BASE + NRF53_USBREG_INTENCLR_OFFSET)
+#define NRF53_USBREG_USBREGSTATUS (NRF53_USBREG_BASE + NRF53_USBREG_USBREGSTATUS_OFFSET)
+
+/* Register bit definitions *************************************************/
+
+/* USBREGSTATUS */
+
+#define USBREG_USBREGSTATUS_VBUSDETECT (1 << 0) /* Vbus Present */
+#define USBREG_USBREGSTATUS_OUTPUTRDY (1 << 1) /* Ready */
+
+#endif /* __ARCH_ARM_SRC_NRF53_HARDWARE_NRF53_USBREG_H */
diff --git a/arch/arm/src/nrf53/nrf53_usbd.c b/arch/arm/src/nrf53/nrf53_usbd.c
new file mode 100644
index 0000000000..79070d62d2
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_usbd.c
@@ -0,0 +1,3195 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_usbd.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/config.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.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 <nuttx/irq.h>
+
+#include "arm_internal.h"
+#include "nrf53_usbd.h"
+
+#include "hardware/nrf53_usbd.h"
+#include "hardware/nrf53_usbreg.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* USB trace ****************************************************************/
+
+/* Trace error codes */
+
+#define NRF53_TRACEERR_ALLOCFAIL 0x01
+#define NRF53_TRACEERR_BADEPNO 0x02
+#define NRF53_TRACEERR_BINDFAILED 0x03
+#define NRF53_TRACEERR_DRIVER 0x04
+#define NRF53_TRACEERR_DRIVERREGISTERED 0x05
+#define NRF53_TRACEERR_INVALIDPARMS 0x06
+#define NRF53_TRACEERR_NOEP 0x07
+#define NRF53_TRACEERR_NOTCONFIGURED 0x08
+#define NRF53_TRACEERR_EPOUTQEMPTY 0x09
+#define NRF53_TRACEERR_EPOUTNULLPACKET 0x0b
+#define NRF53_TRACEERR_EP0NOSETUP 0x0c
+#define NRF53_TRACEERR_EP0SETUPSTALLED 0x0d
+#define NRF53_TRACEERR_DISPATCHSTALL 0x0e
+#define NRF53_TRACEERR_BADEPGETSTATUS 0x0f
+#define NRF53_TRACEERR_BADDEVGETSTATUS 0x10
+#define NRF53_TRACEERR_BADCLEARFEATURE 0x11
+#define NRF53_TRACEERR_BADSETFEATURE 0x12
+#define NRF53_TRACEERR_INVALIDCTRLREQ 0x17
+#define NRF53_TRACEERR_BADGETSTATUS 0x18
+#define NRF53_TRACEERR_EPINREQEMPTY 0x19
+
+/* Trace interrupt codes */
+
+/* USB Interrupt entry/exit */
+
+#define NRF53_TRACEINTID_USB 1
+
+/* On each pass through the loop */
+
+#define NRF53_TRACEINTID_INTPENDING 2
+
+/* First level interrupt decode */
+
+#define NRF53_TRACEINTID_DEVRESET (10 + 0)
+#define NRF53_TRACEINTID_STARTED (10 + 1)
+#define NRF53_TRACEINTID_ENDEPIN (10 + 2)
+#define NRF53_TRACEINTID_ENDISOIN (10 + 4)
+#define NRF53_TRACEINTID_ENDEPOUT (10 + 5)
+#define NRF53_TRACEINTID_ENDISOOUT (10 + 6)
+#define NRF53_TRACEINTID_SOF (10 + 7)
+#define NRF53_TRACEINTID_USBEVENT (10 + 8)
+#define NRF53_TRACEINTID_EP0SETUP (10 + 9)
+#define NRF53_TRACEINTID_EP0DATADONE (10 + 10)
+#define NRF53_TRACEINTID_EPDATA (10 + 11)
+
+/* USBEVENT second level decode */
+
+#define NRF53_TRACEINTID_ISOOUTCRC (30 + 0)
+#define NRF53_TRACEINTID_SUSPEND (30 + 1)
+#define NRF53_TRACEINTID_RESUME (30 + 2)
+#define NRF53_TRACEINTID_USBWUALLOWED (30 + 3)
+#define NRF53_TRACEINTID_READY (30 + 4)
+
+/* EPOUT second level decode */
+
+#define NRF53_TRACEINTID_DISPATCH (50 + 0)
+#define NRF53_TRACEINTID_GETSTATUS (50 + 1)
+#define NRF53_TRACEINTID_DEVGETSTATUS (50 + 2)
+#define NRF53_TRACEINTID_IFGETSTATUS (50 + 3)
+#define NRF53_TRACEINTID_CLEARFEATURE (50 + 4)
+#define NRF53_TRACEINTID_SETFEATURE (50 + 5)
+#define NRF53_TRACEINTID_SETADDRESS (50 + 6)
+#define NRF53_TRACEINTID_GETSETDESC (50 + 7)
+#define NRF53_TRACEINTID_GETSETIFCONFIG (50 + 8)
+#define NRF53_TRACEINTID_SYNCHFRAME (50 + 9)
+#define NRF53_TRACEINTID_EPGETSTATUS (50 + 10)
+#define NRF53_TRACEINTID_TESTMODE (50 + 11)
+
+/* Low level USBD decode */
+
+#define NRF53_TRACEINTID_DMATASK (70 + 0)
+#define NRF53_TRACEINTID_DMAACK (70 + 1)
+#define NRF53_TRACEINTID_EPINSTART (70 + 2)
+#define NRF53_TRACEINTID_EPINSTOP (70 + 3)
+#define NRF53_TRACEINTID_EPOUTSTART (70 + 4)
+#define NRF53_TRACEINTID_EPOUTSTOP (70 + 5)
+#define NRF53_TRACEINTID_EP0RCVOUT (70 + 6)
+#define NRF53_TRACEINTID_EP0STATUS (70 + 7)
+
+/* Configuration ************************************************************/
+
+#define USBDEV_EP0_MAXSIZE (64)
+#define USBDEV_SETUP_MAXDATASIZE (USBDEV_EP0_MAXSIZE * 4)
+
+#ifdef CONFIG_USBDEV_ISOCHRONOUS
+# error not supported yet
+#endif
+
+#ifdef CONFIG_USBDEV_LOWPOWER
+# error not supported yet
+#endif
+
+/* Endpoints ****************************************************************/
+
+/* Odd physical endpoint numbers are IN; even are OUT */
+
+#define NRF53_EPPHYIN2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_IN)
+#define NRF53_EPPHYOUT2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_OUT)
+
+/* Endpoint 0 - control */
+
+#define EP0 (0)
+
+/* The set of all endpoints available to the class implementation (1-7) */
+
+#define NRF53_EP_AVAILABLE (0x0fe) /* All available endpoints */
+
+/* Maximum packet sizes for full speed endpoints */
+
+#define NRF53_MAXPACKET_SIZE (64)
+
+/* Request queue operations *************************************************/
+
+#define nrf53_rqempty(ep) ((ep)->head == NULL)
+#define nrf53_rqpeek(ep) ((ep)->head)
+
+/* Interrupts ***************************************************************/
+
+#ifdef CONFIG_USBDEV_SOFINTERRUPT
+# error TODO
+#else
+#define NRF53_INT_DEFAULT (USBD_INT_USBRESET | \
+ USBD_INT_EP0DATADONE | \
+ USBD_INT_USBEVENT | \
+ USBD_INT_EP0SETUP | \
+ USBD_INT_EPDATA | \
+ USBD_INT_ENDEPIN(0) | \
+ USBD_INT_ENDEPOUT(0))
+#endif
+
+/****************************************************************************
+ * Private Type Definitions
+ ****************************************************************************/
+
+/* Parsed control request */
+
+struct nrf53_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 nrf53_req_s
+{
+ struct usbdev_req_s req; /* Standard USB request */
+ struct nrf53_req_s *flink; /* Supports a singly linked list */
+};
+
+/* This is the internal representation of an endpoint */
+
+struct nrf53_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 nrf53_ep_s.
+ */
+
+ struct usbdev_ep_s ep; /* Standard endpoint structure */
+
+ /* NRF53-specific fields */
+
+ struct nrf53_usbdev_s *dev; /* Reference to private driver data */
+ struct nrf53_req_s *head; /* Request list for this endpoint */
+ struct nrf53_req_s *tail;
+ uint8_t *rxbuff; /* RX buffer */
+ uint8_t epphy; /* Physical EP address */
+ uint8_t eptype:2; /* Endpoint type */
+ uint8_t stalled:1; /* 1: Endpoint is stalled */
+ uint8_t isin:1; /* 1: IN Endpoint */
+};
+
+/* NRF53 USB device */
+
+struct nrf53_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 structnrf53_usbdev_s.
+ */
+
+ struct usbdev_s usbdev;
+
+ /* The bound device class driver */
+
+ struct usbdevclass_driver_s *driver;
+
+ /* NRF53-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 wakeup:1; /* 1: Device remote wake-up */
+ uint8_t ep0indone; /* 1: EP0 IN transfer complete */
+ uint8_t ep0outdone; /* 1: EP0 OUT transfer complete */
+ uint8_t epavail[2]; /* Bitset of available OUT/IN endpoints */
+ bool dmanow; /* DMA transfer pending */
+
+ /* E0 SETUP data buffering.
+ *
+ * ctrl
+ * 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.
+ *
+ * ep0datlen
+ * Length of OUT DATA received in ep0data[]
+ */
+
+ struct usb_ctrlreq_s ctrlreq;
+ uint8_t ep0data[USBDEV_SETUP_MAXDATASIZE];
+ uint16_t ep0datlen;
+ uint16_t ep0reqlen;
+
+ /* The endpoint list */
+
+ struct nrf53_ep_s epin[NRF53_NENDPOINTS];
+ struct nrf53_ep_s epout[NRF53_NENDPOINTS];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Register operations ******************************************************/
+
+#define nrf53_getreg(addr) getreg32(addr)
+#define nrf53_putreg(val,addr) putreg32(val,addr)
+
+/* DMA operations ***********************************************************/
+
+static void nrf53_startdma_task(struct nrf53_usbdev_s *priv, uint32_t addr);
+static void nrf53_startdma_ack(struct nrf53_usbdev_s *priv);
+
+static void nrf53_epout_start(struct nrf53_usbdev_s *priv, int epno);
+static void nrf53_epout_stop(struct nrf53_usbdev_s *priv, int epno);
+static void nrf53_epin_start(struct nrf53_usbdev_s *priv, int epno);
+static void nrf53_epin_stop(struct nrf53_usbdev_s *priv, int epno);
+static void nrf53_ep0rcvout_start(struct nrf53_usbdev_s *priv);
+static void nrf53_ep0status_start(struct nrf53_usbdev_s *priv);
+
+/* Request queue operations *************************************************/
+
+static struct nrf53_req_s *nrf53_req_remfirst(struct nrf53_ep_s *privep);
+static bool nrf53_req_addlast(struct nrf53_ep_s *privep,
+ struct nrf53_req_s *req);
+
+/* Low level data transfers and request operations **************************/
+
+/* Special endpoint 0 data transfer logic */
+
+static void nrf53_ep0out_stdrequest(struct nrf53_usbdev_s *priv,
+ struct nrf53_ctrlreq_s *ctrlreq);
+static void nrf53_ep0setup(struct nrf53_usbdev_s *priv);
+
+/* IN request handling */
+
+static void nrf53_epin_transfer(struct nrf53_ep_s *privep, uint8_t *buf,
+ int nbytes);
+static void nrf53_epin_request(struct nrf53_usbdev_s *priv,
+ struct nrf53_ep_s *privep);
+
+/* OUT request handling */
+
+static void nrf53_epout_allow(struct nrf53_ep_s *privep);
+static void nrf53_epout_transfer(struct nrf53_ep_s *privep);
+
+static void nrf53_epout_complete(struct nrf53_ep_s *privep);
+static void nrf53_ep0out_receive(struct nrf53_usbdev_s *priv);
+static void nrf53_epout_receive(struct nrf53_ep_s *privep);
+static void nrf53_epout_handle(struct nrf53_usbdev_s *priv,
+ struct nrf53_ep_s *privep);
+
+/* General request handling */
+
+static void nrf53_req_complete(struct nrf53_ep_s *privep, int16_t result);
+static void nrf53_req_cancel(struct nrf53_ep_s *privep, int16_t status);
+static int nrf53_req_dispatch(struct nrf53_usbdev_s *priv,
+ const struct usb_ctrlreq_s *ctrl);
+
+/* Interrupt handling *******************************************************/
+
+static struct nrf53_ep_s *
+nrf53_ep_findbyaddr(struct nrf53_usbdev_s *priv, uint16_t eplog);
+static void nrf53_usbreset(struct nrf53_usbdev_s *priv);
+
+/* Other second level interrupt processing */
+
+static void nrf53_resumeinterrupt(struct nrf53_usbdev_s *priv);
+static void nrf53_suspendinterrupt(struct nrf53_usbdev_s *priv);
+static void nrf53_eventinterrupt(struct nrf53_usbdev_s *priv);
+static void nrf53_ep0setupinterrupt(struct nrf53_usbdev_s *priv);
+static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv);
+static void nrf53_epdatainterrupt(struct nrf53_usbdev_s *priv);
+static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv);
+static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv);
+
+/* First level interrupt processing */
+
+static int nrf53_usbinterrupt(int irq, void *context, void *arg);
+
+/* Endpoint operations ******************************************************/
+
+/* Endpoint configuration */
+
+static int nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
+ uint16_t maxpacket);
+static int nrf53_epin_configure(struct nrf53_ep_s *privep, uint8_t eptype,
+ uint16_t maxpacket);
+static int nrf53_ep_configure(struct usbdev_ep_s *ep,
+ const struct usb_epdesc_s *desc, bool last);
+static void nrf53_ep0_configure(struct nrf53_usbdev_s *priv);
+
+/* Endpoint disable */
+
+static void nrf53_epout_disable(struct nrf53_ep_s *privep);
+static void nrf53_epin_disable(struct nrf53_ep_s *privep);
+static int nrf53_ep_disable(struct usbdev_ep_s *ep);
+
+/* Endpoint request management */
+
+static struct usbdev_req_s *nrf53_ep_allocreq(struct usbdev_ep_s *ep);
+static void nrf53_ep_freereq(struct usbdev_ep_s *ep, struct usbdev_req_s *);
+
+/* Endpoint buffer management */
+
+#ifdef CONFIG_USBDEV_DMA
+static void *nrf53_ep_allocbuffer(struct usbdev_ep_s *ep, unsigned bytes);
+static void nrf53_ep_freebuffer(struct usbdev_ep_s *ep, void *buf);
+#endif
+
+/* Endpoint request submission */
+
+static int nrf53_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req);
+
+/* Endpoint request cancellation */
+
+static int nrf53_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req);
+
+/* Stall handling */
+
+static int nrf53_ep_setstall(struct nrf53_ep_s *privep);
+static int nrf53_ep_clrstall(struct nrf53_ep_s *privep);
+static int nrf53_ep_stall(struct usbdev_ep_s *ep, bool resume);
+static void nrf53_ep0_stall(struct nrf53_usbdev_s *priv);
+
+/* Endpoint allocation */
+
+static struct usbdev_ep_s *
+nrf53_ep_alloc(struct usbdev_s *dev, uint8_t epno, bool in, uint8_t eptype);
+static void nrf53_ep_free(struct usbdev_s *dev, struct usbdev_ep_s *ep);
+
+/* USB device controller operations *****************************************/
+
+static int nrf53_getframe(struct usbdev_s *dev);
+static int nrf53_wakeup(struct usbdev_s *dev);
+static int nrf53_selfpowered(struct usbdev_s *dev, bool selfpowered);
+static int nrf53_pullup(struct usbdev_s *dev, bool enable);
+static void nrf53_setaddress(struct nrf53_usbdev_s *priv, uint16_t address);
+
+/* Initialization ***********************************************************/
+
+static void nrf53_swinitialize(struct nrf53_usbdev_s *priv);
+static void nrf53_hwinitialize(struct nrf53_usbdev_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct nrf53_usbdev_s g_usbdev;
+
+/* USB endpoint ops */
+
+static const struct usbdev_epops_s g_epops =
+{
+ .configure = nrf53_ep_configure,
+ .disable = nrf53_ep_disable,
+ .allocreq = nrf53_ep_allocreq,
+ .freereq = nrf53_ep_freereq,
+#ifdef CONFIG_USBDEV_DMA
+ .allocbuffer = nrf53_ep_allocbuffer,
+ .freebuffer = nrf53_ep_freebuffer,
+#endif
+ .submit = nrf53_ep_submit,
+ .cancel = nrf53_ep_cancel,
+ .stall = nrf53_ep_stall,
+};
+
+/* USB device ops */
+
+static const struct usbdev_ops_s g_devops =
+{
+ .allocep = nrf53_ep_alloc,
+ .freeep = nrf53_ep_free,
+ .getframe = nrf53_getframe,
+ .wakeup = nrf53_wakeup,
+ .selfpowered = nrf53_selfpowered,
+ .pullup = nrf53_pullup,
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_USBDEV_TRACE_STRINGS
+const struct trace_msg_t g_usb_trace_strings_deverror[] =
+{
+ TRACE_STR(NRF53_TRACEERR_ALLOCFAIL),
+ TRACE_STR(NRF53_TRACEERR_BADEPNO),
+ TRACE_STR(NRF53_TRACEERR_BINDFAILED),
+ TRACE_STR(NRF53_TRACEERR_DRIVER),
+ TRACE_STR(NRF53_TRACEERR_DRIVERREGISTERED),
+ TRACE_STR(NRF53_TRACEERR_INVALIDPARMS),
+ TRACE_STR(NRF53_TRACEERR_NOEP),
+ TRACE_STR(NRF53_TRACEERR_NOTCONFIGURED),
+ TRACE_STR(NRF53_TRACEERR_EPOUTQEMPTY),
+ TRACE_STR(NRF53_TRACEERR_EPOUTNULLPACKET),
+ TRACE_STR(NRF53_TRACEERR_EP0NOSETUP),
+ TRACE_STR(NRF53_TRACEERR_EP0SETUPSTALLED),
+ TRACE_STR(NRF53_TRACEERR_DISPATCHSTALL),
+ TRACE_STR(NRF53_TRACEERR_BADEPGETSTATUS),
+ TRACE_STR(NRF53_TRACEERR_BADEPGETSTATUS),
+ TRACE_STR(NRF53_TRACEERR_BADDEVGETSTATUS),
+ TRACE_STR(NRF53_TRACEERR_BADCLEARFEATURE),
+ TRACE_STR(NRF53_TRACEERR_BADSETFEATURE),
+ TRACE_STR(NRF53_TRACEERR_INVALIDCTRLREQ),
+ TRACE_STR(NRF53_TRACEERR_BADGETSTATUS),
+ TRACE_STR(NRF53_TRACEERR_EPINREQEMPTY),
+ TRACE_STR_END
+};
+#endif
+
+#ifdef CONFIG_USBDEV_TRACE_STRINGS
+const struct trace_msg_t g_usb_trace_strings_intdecode[] =
+{
+ TRACE_STR(NRF53_TRACEINTID_USB),
+ TRACE_STR(NRF53_TRACEINTID_INTPENDING),
+
+ TRACE_STR(NRF53_TRACEINTID_DEVRESET),
+ TRACE_STR(NRF53_TRACEINTID_STARTED),
+ TRACE_STR(NRF53_TRACEINTID_ENDEPIN),
+ TRACE_STR(NRF53_TRACEINTID_ENDISOIN),
+ TRACE_STR(NRF53_TRACEINTID_ENDEPOUT),
+ TRACE_STR(NRF53_TRACEINTID_ENDISOOUT),
+ TRACE_STR(NRF53_TRACEINTID_SOF),
+ TRACE_STR(NRF53_TRACEINTID_USBEVENT),
+ TRACE_STR(NRF53_TRACEINTID_EP0SETUP),
+ TRACE_STR(NRF53_TRACEINTID_EP0DATADONE),
+ TRACE_STR(NRF53_TRACEINTID_EPDATA),
+
+ TRACE_STR(NRF53_TRACEINTID_ISOOUTCRC),
+ TRACE_STR(NRF53_TRACEINTID_SUSPEND),
+ TRACE_STR(NRF53_TRACEINTID_RESUME),
+ TRACE_STR(NRF53_TRACEINTID_USBWUALLOWED),
+ TRACE_STR(NRF53_TRACEINTID_READY),
+
+ TRACE_STR(NRF53_TRACEINTID_DISPATCH),
+ TRACE_STR(NRF53_TRACEINTID_GETSTATUS),
+ TRACE_STR(NRF53_TRACEINTID_DEVGETSTATUS),
+ TRACE_STR(NRF53_TRACEINTID_IFGETSTATUS),
+ TRACE_STR(NRF53_TRACEINTID_CLEARFEATURE),
+ TRACE_STR(NRF53_TRACEINTID_SETFEATURE),
+ TRACE_STR(NRF53_TRACEINTID_SETADDRESS),
+ TRACE_STR(NRF53_TRACEINTID_GETSETDESC),
+ TRACE_STR(NRF53_TRACEINTID_GETSETIFCONFIG),
+ TRACE_STR(NRF53_TRACEINTID_SYNCHFRAME),
+ TRACE_STR(NRF53_TRACEINTID_EPGETSTATUS),
+ TRACE_STR(NRF53_TRACEINTID_TESTMODE),
+
+ TRACE_STR(NRF53_TRACEINTID_DMATASK),
+ TRACE_STR(NRF53_TRACEINTID_DMAACK),
+ TRACE_STR(NRF53_TRACEINTID_EPINSTART),
+ TRACE_STR(NRF53_TRACEINTID_EPINSTOP),
+ TRACE_STR(NRF53_TRACEINTID_EPOUTSTART),
+ TRACE_STR(NRF53_TRACEINTID_EPOUTSTOP),
+ TRACE_STR(NRF53_TRACEINTID_EP0RCVOUT),
+ TRACE_STR(NRF53_TRACEINTID_EP0STATUS),
+
+ TRACE_STR_END
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_startdma_task and nrf53_startdma_ack
+ *
+ * Description:
+ * Errata [199] USBD: USBD cannot receive tasks during DMA
+ *
+ ****************************************************************************/
+
+static void nrf53_startdma_task(struct nrf53_usbdev_s *priv, uint32_t addr)
+{
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DMATASK), addr);
+
+ *(volatile uint32_t *)0x40027c1c = 0x00000082;
+ nrf53_putreg(1, addr);
+
+ priv->dmanow = true;
+}
+
+static void nrf53_startdma_ack(struct nrf53_usbdev_s *priv)
+{
+ if (priv->dmanow == true)
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DMAACK), 0);
+
+ *(volatile uint32_t *)0x40027c1c = 0x00000000;
+
+ priv->dmanow = false;
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_xxx_start and nrf53_xxx_stop
+ *
+ * Description:
+ * Start or stop tasks
+ *
+ ****************************************************************************/
+
+static void nrf53_epout_start(struct nrf53_usbdev_s *priv, int epno)
+{
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPOUTSTART), epno);
+ nrf53_startdma_task(priv, NRF53_USBD_TASKS_STARTEPOUT(epno));
+}
+
+static void nrf53_epout_stop(struct nrf53_usbdev_s *priv, int epno)
+{
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPOUTSTOP), epno);
+ nrf53_putreg(0, NRF53_USBD_TASKS_STARTEPOUT(epno));
+}
+
+static void nrf53_epin_start(struct nrf53_usbdev_s *priv, int epno)
+{
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPINSTART), epno);
+ nrf53_startdma_task(priv, NRF53_USBD_TASKS_STARTEPIN(epno));
+}
+
+static void nrf53_epin_stop(struct nrf53_usbdev_s *priv, int epno)
+{
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPINSTOP), epno);
+ nrf53_putreg(0, NRF53_USBD_TASKS_STARTEPIN(epno));
+}
+
+static void nrf53_ep0rcvout_start(struct nrf53_usbdev_s *priv)
+{
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0RCVOUT), 0);
+ nrf53_putreg(1, NRF53_USBD_TASKS_EP0RCVOUT);
+}
+
+static void nrf53_ep0status_start(struct nrf53_usbdev_s *priv)
+{
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0STATUS), 0);
+ nrf53_putreg(1, NRF53_USBD_TASKS_EP0STATUS);
+}
+
+/****************************************************************************
+ * Name: nrf53_req_remfirst
+ *
+ * Description:
+ * Remove a request from the head of an endpoint request queue
+ *
+ ****************************************************************************/
+
+static struct nrf53_req_s *nrf53_req_remfirst(struct nrf53_ep_s *privep)
+{
+ struct nrf53_req_s *ret = privep->head;
+
+ if (ret)
+ {
+ privep->head = ret->flink;
+ if (!privep->head)
+ {
+ privep->tail = NULL;
+ }
+
+ ret->flink = NULL;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_req_addlast
+ *
+ * Description:
+ * Add a request to the end of an endpoint request queue
+ *
+ ****************************************************************************/
+
+static bool nrf53_req_addlast(struct nrf53_ep_s *privep,
+ struct nrf53_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: nrf53_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 void
+nrf53_ep0out_stdrequest(struct nrf53_usbdev_s *priv,
+ struct nrf53_ctrlreq_s *ctrlreq)
+{
+ struct nrf53_ep_s *privep = NULL;
+ uint8_t recipient = 0;
+
+ /* 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(NRF53_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(NRF53_TRACEINTID_EPGETSTATUS), 0);
+ privep = nrf53_ep_findbyaddr(priv, ctrlreq->index);
+ if (!privep)
+ {
+ usbtrace(
+ TRACE_DEVERROR(NRF53_TRACEERR_BADEPGETSTATUS), 0);
+ priv->stalled = true;
+ }
+ break;
+ }
+
+ case USB_REQ_RECIPIENT_DEVICE:
+ case USB_REQ_RECIPIENT_INTERFACE:
+ {
+ if (ctrlreq->index == 0)
+ {
+ usbtrace(TRACE_INTDECODE(
+ NRF53_TRACEINTID_DEVGETSTATUS), 0);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(
+ NRF53_TRACEERR_BADDEVGETSTATUS), 0);
+ priv->stalled = true;
+ }
+ break;
+ }
+
+ default:
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_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(NRF53_TRACEINTID_CLEARFEATURE), 0);
+ if (priv->addressed != 0 && ctrlreq->len == 0)
+ {
+ recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK;
+ if (recipient == USB_REQ_RECIPIENT_ENDPOINT &&
+ ctrlreq->value == USB_FEATURE_ENDPOINTHALT &&
+ (privep = nrf53_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
+ {
+ nrf53_ep_clrstall(privep);
+ }
+ else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
+ {
+ priv->wakeup = false;
+ }
+ else
+ {
+ nrf53_req_dispatch(priv, &priv->ctrlreq);
+ }
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_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(NRF53_TRACEINTID_SETFEATURE), 0);
+ if (priv->addressed != 0 && ctrlreq->len == 0)
+ {
+ recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK;
+ if (recipient == USB_REQ_RECIPIENT_ENDPOINT &&
+ ctrlreq->value == USB_FEATURE_ENDPOINTHALT &&
+ (privep = nrf53_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
+ {
+ nrf53_ep_setstall(privep);
+ }
+ else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
+ {
+ priv->wakeup = true;
+ }
+ else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
+ ctrlreq->value == USB_FEATURE_TESTMODE &&
+ ((ctrlreq->index & 0xff) == 0))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_TESTMODE), 0);
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_BADSETFEATURE), 0);
+ priv->stalled = true;
+ }
+ }
+ else
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_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(NRF53_TRACEINTID_SETADDRESS),
+ ctrlreq->value);
+ nrf53_setaddress(priv, (uint16_t)priv->ctrlreq.value[0]);
+
+ /* NOTE: The USBD peripheral handles the SetAddress
+ * transfer by itself.
+ *
+ * REVISTI: Documentation states that we shall not handle this
+ * command in the software at all, but if we don't
+ * send EP0STATUS response then enumeration fails.
+ */
+
+ 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(NRF53_TRACEINTID_GETSETDESC),
+ priv->ctrlreq.req);
+ nrf53_req_dispatch(priv, &priv->ctrlreq);
+ break;
+ }
+
+ case USB_REQ_GETCONFIGURATION:
+ /* type: device-to-host; recipient = device
+ * value: 0;
+ * index: 0;
+ * len: 1; data = configuration value
+ */
+
+ case USB_REQ_SETCONFIGURATION:
+ /* type: host-to-device; recipient = device
+ * value: configuration value
+ * index: 0;
+ * len: 0; data = none
+ */
+
+ 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(NRF53_TRACEINTID_GETSETIFCONFIG),
+ priv->ctrlreq.req);
+ nrf53_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(NRF53_TRACEINTID_SYNCHFRAME), 0);
+ break;
+ }
+
+ default:
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDCTRLREQ), 0);
+ priv->stalled = true;
+ }
+ break;
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_ep0setup
+ *
+ * Description:
+ * USB Ctrl EP Setup Event
+ *
+ ****************************************************************************/
+
+static void nrf53_ep0setup(struct nrf53_usbdev_s *priv)
+{
+ struct nrf53_ctrlreq_s ctrlreq;
+
+ /* Terminate any pending requests */
+
+ nrf53_req_cancel(&priv->epout[EP0], -EPROTO);
+ nrf53_req_cancel(&priv->epin[EP0], -EPROTO);
+
+ /* Assume NOT stalled */
+
+ priv->epout[EP0].stalled = false;
+ priv->epin[EP0].stalled = false;
+ priv->stalled = false;
+
+ /* Get ctrlreq */
+
+ 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);
+
+ uinfo("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 */
+
+ nrf53_req_dispatch(priv, &priv->ctrlreq);
+ }
+ else
+ {
+ /* Handle standard requests. */
+
+ nrf53_ep0out_stdrequest(priv, &ctrlreq);
+ }
+
+ /* Check if the setup processing resulted in a STALL */
+
+ if (priv->stalled)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EP0SETUPSTALLED), 0);
+ nrf53_ep0_stall(priv);
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_epin_transfer
+ *
+ * Description:
+ * Start the Tx data transfer
+ *
+ ****************************************************************************/
+
+static void nrf53_epin_transfer(struct nrf53_ep_s *privep, uint8_t *buf,
+ int nbytes)
+{
+ struct nrf53_usbdev_s *priv = NULL;
+
+ /* Sanity Checking */
+
+ DEBUGASSERT(privep && privep->dev);
+ priv = (struct nrf53_usbdev_s *)privep->dev;
+
+ /* ISOC not supported yet */
+
+ DEBUGASSERT(privep->eptype != USB_EP_ATTR_XFER_ISOC);
+ DEBUGASSERT(nbytes <= 64);
+
+ if (nbytes > 0)
+ {
+ /* Configure EasyDMA */
+
+ nrf53_putreg((uint32_t)buf, NRF53_USBD_EPIN_PTR(privep->epphy));
+ nrf53_putreg(nbytes, NRF53_USBD_EPIN_MAXCNT(privep->epphy));
+
+ /* Start EPIN task - DMA transfer */
+
+ nrf53_epin_start(priv, privep->epphy);
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_epout_allow
+ *
+ * Description:
+ * Allow OUT trafic on this endpoint
+ *
+ ****************************************************************************/
+
+static void nrf53_epout_allow(struct nrf53_ep_s *privep)
+{
+ /* Write to any value to accept further OUT traffic on this endpoint */
+
+ nrf53_putreg(0, NRF53_USBD_SIZE_EPOUT(privep->epphy));
+}
+
+/****************************************************************************
+ * Name: nrf53_epout_transfer
+ *
+ * Description:
+ * Start the Rx data transfer
+ *
+ ****************************************************************************/
+
+static void nrf53_epout_transfer(struct nrf53_ep_s *privep)
+{
+ struct nrf53_usbdev_s *priv = NULL;
+ int nbytes = 0;
+
+ /* Sanity Checking */
+
+ DEBUGASSERT(privep && privep->dev);
+ priv = (struct nrf53_usbdev_s *)privep->dev;
+
+ /* Number of bytes received last in the data stage of this OUT endpoint */
+
+ nbytes = nrf53_getreg(NRF53_USBD_SIZE_EPOUT(privep->epphy));
+
+ /* Configure EasyDMA */
+
+ nrf53_putreg((uint32_t)privep->rxbuff,
+ NRF53_USBD_EPOUT_PTR(privep->epphy));
+ nrf53_putreg(nbytes, NRF53_USBD_EPOUT_MAXCNT(privep->epphy));
+
+ /* Start EPOUT task */
+
+ nrf53_epout_start(priv, privep->epphy);
+}
+
+/****************************************************************************
+ * Name: nrf53_epin_request
+ *
+ * Description:
+ * Begin or continue write request processing.
+ *
+ ****************************************************************************/
+
+static void nrf53_epin_request(struct nrf53_usbdev_s *priv,
+ struct nrf53_ep_s *privep)
+{
+ struct nrf53_req_s *privreq = NULL;
+ uint8_t *buf = NULL;
+ int bytesleft = 0;
+ int nbytes = 0;
+
+ /* Check the request from the head of the endpoint request queue */
+
+ privreq = nrf53_rqpeek(privep);
+ if (!privreq)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPINREQEMPTY), privep->epphy);
+ return;
+ }
+
+ uinfo("EP%" PRId8 " req=%p: len=%" PRId16 " xfrd=%" PRId16 "\n",
+ privep->epphy, privreq, privreq->req.len, privreq->req.xfrd);
+
+ /* Add one more packet. We will wait for the transfer
+ * complete event before we add the next packet.
+ */
+
+ if (privreq->req.xfrd < privreq->req.len)
+ {
+ /* Get the number of bytes left to be sent in the request */
+
+ bytesleft = privreq->req.len - privreq->req.xfrd;
+ nbytes = bytesleft;
+
+ /* Limit the size of the transfer to one full packet */
+
+ 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;
+ }
+ }
+
+ /* Transfer data */
+
+ buf = privreq->req.buf + privreq->req.xfrd;
+ nrf53_epin_transfer(privep, buf, nbytes);
+
+ /* Update for the next time through the loop */
+
+ privreq->req.xfrd += nbytes;
+ }
+
+ else if (privreq->req.xfrd >= privreq->req.len)
+ {
+ usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
+
+ /* We are finished with the request (although the transfer has not
+ * yet completed).
+ */
+
+ nrf53_req_complete(privep, OK);
+
+ if (privep->epphy == EP0)
+ {
+ priv->ep0indone = true;
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_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 nrf53_epout_complete(struct nrf53_ep_s *privep)
+{
+ struct nrf53_req_s *privreq = NULL;
+
+ /* Sanity Checking */
+
+ DEBUGASSERT(privep);
+
+ /* Since a transfer just completed, there must be a read request at the
+ * head of the endpoint request queue.
+ */
+
+ privreq = nrf53_rqpeek(privep);
+ DEBUGASSERT(privreq);
+
+ if (!privreq)
+ {
+ /* An OUT transfer completed, but no packet to receive the data. This
+ * should not happen.
+ */
+
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTQEMPTY),
+ privep->epphy);
+ return;
+ }
+
+ uinfo("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);
+ nrf53_req_complete(privep, OK);
+
+ /* Allow OUT trafic on this endpoint */
+
+ nrf53_epout_allow(privep);
+}
+
+/****************************************************************************
+ * Name: nrf53_ep0out_receive
+ *
+ * Description:
+ * This function will simply copy the incoming data into pending request's
+ * data buffer.
+ *
+ ****************************************************************************/
+
+static void nrf53_ep0out_receive(struct nrf53_usbdev_s *priv)
+{
+ struct nrf53_ep_s *privep = &priv->epout[EP0];
+ uint16_t bcnt = 0;
+
+ /* Get data size */
+
+ bcnt = nrf53_getreg(NRF53_USBD_EPOUT_AMOUNT(0));
+
+ uinfo("EP0: bcnt=%d\n", bcnt);
+ usbtrace(TRACE_READ(EP0), bcnt);
+
+ /* Transfer the data from the RX buffer */
+
+ DEBUGASSERT(priv->ep0datlen + bcnt <= USBDEV_SETUP_MAXDATASIZE);
+ memcpy(priv->ep0data + priv->ep0datlen, privep->rxbuff, bcnt);
+ priv->ep0datlen += bcnt;
+
+ if (priv->ep0datlen >= priv->ep0reqlen)
+ {
+ /* Now we can process the setup command */
+
+ nrf53_ep0setup(priv);
+ priv->ep0datlen = 0;
+ priv->ep0outdone = true;
+ }
+ else
+ {
+ priv->ep0outdone = false;
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_epout_receive
+ *
+ * Description:
+ * This function will simply copy the incoming data into pending request's
+ * data buffer.
+ *
+ ****************************************************************************/
+
+static void nrf53_epout_receive(struct nrf53_ep_s *privep)
+{
+ struct nrf53_req_s *privreq = NULL;
+ uint8_t *dest = NULL;
+ int buflen = 0;
+ int readlen = 0;
+ int bcnt = 0;
+
+ /* Get data size */
+
+ bcnt = nrf53_getreg(NRF53_USBD_EPOUT_AMOUNT(privep->epphy));
+
+ /* Get a reference to the request at the head of the endpoint's request
+ * queue.
+ */
+
+ privreq = nrf53_rqpeek(privep);
+ if (!privreq)
+ {
+ /* Otherwise, the data is lost. This really should not happen if
+ * NAKing is working as expected.
+ */
+
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTQEMPTY),
+ privep->epphy);
+
+ return;
+ }
+
+ uinfo("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 */
+
+ 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 RX buffer */
+
+ memcpy(dest, privep->rxbuff, readlen);
+
+ /* Update the number of bytes transferred */
+
+ privreq->req.xfrd += readlen;
+
+ if (privreq->req.xfrd >= privreq->req.len ||
+ readlen < privep->ep.maxpacket)
+ {
+ /* Complete OUT transfer */
+
+ nrf53_epout_complete(privep);
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_epout_handle
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+static void nrf53_epout_handle(struct nrf53_usbdev_s *priv,
+ struct nrf53_ep_s *privep)
+{
+ struct nrf53_req_s *privreq = NULL;
+
+ /* Not for EP0 */
+
+ DEBUGASSERT(privep->epphy != EP0);
+
+ /* 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 = nrf53_rqpeek(privep);
+ if (!privreq)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTQEMPTY),
+ privep->epphy);
+ return;
+ }
+
+ uinfo("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(NRF53_TRACEERR_EPOUTNULLPACKET), 0);
+ nrf53_req_complete(privep, OK);
+ }
+
+ /* Otherwise, we have a usable read request...
+ * break out of the loop
+ */
+
+ else
+ {
+ break;
+ }
+ }
+
+ /* Prepare EP OUT DMA transfer */
+
+ nrf53_epout_transfer(privep);
+}
+
+/****************************************************************************
+ * Name: nrf53_req_complete
+ *
+ * Description:
+ * Handle termination of the request at the head of the endpoint request
+ * queue.
+ *
+ ****************************************************************************/
+
+static void nrf53_req_complete(struct nrf53_ep_s *privep, int16_t result)
+{
+ struct nrf53_req_s *privreq = NULL;
+ bool stalled = false;
+
+ /* Remove the request at the head of the request list */
+
+ privreq = nrf53_req_remfirst(privep);
+ DEBUGASSERT(privreq != NULL);
+
+ /* If endpoint 0, temporarily reflect the state of protocol stalled
+ * in the callback.
+ */
+
+ 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: nrf53_req_cancel
+ *
+ * Description:
+ * Cancel all pending requests for an endpoint
+ *
+ ****************************************************************************/
+
+static void nrf53_req_cancel(struct nrf53_ep_s *privep, int16_t status)
+{
+ while (!nrf53_rqempty(privep))
+ {
+ usbtrace(TRACE_COMPLETE(privep->epphy),
+ (nrf53_rqpeek(privep))->req.xfrd);
+ nrf53_req_complete(privep, status);
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_req_dispatch
+ *
+ * Description:
+ * Provide unhandled setup actions to the class driver. This is logically
+ * part of the USB interrupt handler.
+ *
+ ****************************************************************************/
+
+static int nrf53_req_dispatch(struct nrf53_usbdev_s *priv,
+ const struct usb_ctrlreq_s *ctrl)
+{
+ int ret = -EIO;
+
+ usbtrace(TRACE_INTDECODE(NRF53_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(NRF53_TRACEERR_DISPATCHSTALL), 0);
+ priv->stalled = true;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_findbyaddr
+ *
+ * Description:
+ * Find the physical endpoint structure corresponding to a logic endpoint
+ * address
+ *
+ ****************************************************************************/
+
+static struct nrf53_ep_s *nrf53_ep_findbyaddr(struct nrf53_usbdev_s *priv,
+ uint16_t eplog)
+{
+ struct nrf53_ep_s *privep = NULL;
+ uint8_t epphy = USB_EPNO(eplog);
+
+ if (epphy >= NRF53_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: nrf53_usbreset
+ *
+ * Description:
+ * Reset Usb engine
+ *
+ ****************************************************************************/
+
+static void nrf53_usbreset(struct nrf53_usbdev_s *priv)
+{
+ struct nrf53_ep_s *privep = NULL;
+ uint32_t regval = 0;
+ int i = 0;
+
+ uinfo("nrf53_usbreset\n");
+
+ /* 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] = NRF53_EP_AVAILABLE;
+ priv->epavail[1] = NRF53_EP_AVAILABLE;
+
+ /* Disable all end points */
+
+ for (i = 0; i < NRF53_NENDPOINTS ; i++)
+ {
+ /* Return write requests to the class implementation */
+
+ privep = &priv->epin[i];
+ nrf53_req_cancel(privep, -ESHUTDOWN);
+
+ /* Reset IN endpoint status */
+
+ privep->stalled = false;
+
+ /* Stop EPIN taks */
+
+ nrf53_epin_stop(priv, i);
+
+ /* Return read requests to the class implementation */
+
+ privep = &priv->epout[i];
+ nrf53_req_cancel(privep, -ESHUTDOWN);
+
+ /* Reset endpoint status */
+
+ privep->stalled = false;
+
+ /* Stop EPOUT taks */
+
+ nrf53_epout_stop(priv, i);
+ }
+
+ /* Enable the interrupts */
+
+ regval = NRF53_INT_DEFAULT;
+ nrf53_putreg(regval, NRF53_USBD_INTEN);
+
+ /* Reset device address to 0 */
+
+ nrf53_setaddress(priv, 0);
+ priv->usbdev.speed = USB_SPEED_FULL;
+
+ /* Re-configure EP0 */
+
+ nrf53_ep0_configure(priv);
+}
+
+/****************************************************************************
+ * Name: nrf53_resumeinterrupt
+ *
+ * Description:
+ * Resume/remote wakeup detected interrupt
+ *
+ ****************************************************************************/
+
+static void nrf53_resumeinterrupt(struct nrf53_usbdev_s *priv)
+{
+#ifdef CONFIG_USBDEV_LOWPOWER
+ /* Force normal state */
+
+ nrf53_putreg(0, NRF53_USBD_LOWPOWER);
+
+ /* TODO: wait for event */
+#endif
+
+ /* Restore full power -- whatever that means for this particular board */
+
+ nrf53_usbsuspend((struct usbdev_s *)priv, true);
+
+ /* Notify the class driver of the resume event */
+
+ if (priv->driver)
+ {
+ CLASS_RESUME(priv->driver, &priv->usbdev);
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_suspendinterrupt
+ *
+ * Description:
+ * USB suspend interrupt
+ *
+ ****************************************************************************/
+
+static void nrf53_suspendinterrupt(struct nrf53_usbdev_s *priv)
+{
+ /* Notify the class driver of the suspend event */
+
+ if (priv->driver)
+ {
+ CLASS_SUSPEND(priv->driver, &priv->usbdev);
+ }
+
+#ifdef CONFIG_USBDEV_LOWPOWER
+ /* Force low power state */
+
+ nrf53_putreg(1, NRF53_USBD_LOWPOWER);
+#endif
+
+ /* Let the board-specific logic know that we have entered the suspend
+ * state
+ */
+
+ nrf53_usbsuspend((struct usbdev_s *)priv, false);
+}
+
+/****************************************************************************
+ * Name: nrf53_eventinterrupt
+ *
+ * Description:
+ * Handle EVENT events
+ *
+ ****************************************************************************/
+
+static void nrf53_eventinterrupt(struct nrf53_usbdev_s *priv)
+{
+ uint32_t regval = 0;
+ uint32_t clr = 0;
+
+ regval = nrf53_getreg(NRF53_USBD_EVENTCAUSE);
+
+ if (regval & USBD_EVENTCAUSE_ISOOUTCRC)
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ISOOUTCRC), 0);
+ clr |= USBD_EVENTCAUSE_ISOOUTCRC;
+ }
+
+ if (regval & USBD_EVENTCAUSE_SUSPEND)
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SUSPEND), 0);
+ nrf53_suspendinterrupt(priv);
+ clr |= USBD_EVENTCAUSE_SUSPEND;
+ }
+
+ if (regval & USBD_EVENTCAUSE_RESUME)
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_RESUME), 0);
+ nrf53_resumeinterrupt(priv);
+ clr |= USBD_EVENTCAUSE_RESUME;
+ }
+
+ if (regval & USBD_EVENTCAUSE_USBWUALLOWED)
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_USBWUALLOWED), 0);
+ clr |= USBD_EVENTCAUSE_USBWUALLOWED;
+ }
+
+ if (regval & USBD_EVENTCAUSE_READY)
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_READY), 0);
+ clr |= USBD_EVENTCAUSE_READY;
+ }
+
+ /* Clear all pending events */
+
+ nrf53_putreg(clr, NRF53_USBD_EVENTCAUSE);
+}
+
+/****************************************************************************
+ * Name: nrf53_ep0setupinterrupt
+ *
+ * Description:
+ * Handle EP0SETUP event
+ *
+ ****************************************************************************/
+
+static void nrf53_ep0setupinterrupt(struct nrf53_usbdev_s *priv)
+{
+ /* Get SETUP data */
+
+ priv->ctrlreq.type = nrf53_getreg(NRF53_USBD_BMREQUESTTYPE);
+ priv->ctrlreq.req = nrf53_getreg(NRF53_USBD_BREQUEST);
+ priv->ctrlreq.value[0] = nrf53_getreg(NRF53_USBD_WVALUEL);
+ priv->ctrlreq.value[1] = nrf53_getreg(NRF53_USBD_WVALUEH);
+ priv->ctrlreq.index[0] = nrf53_getreg(NRF53_USBD_WINDEXL);
+ priv->ctrlreq.index[1] = nrf53_getreg(NRF53_USBD_WINDEXH);
+ priv->ctrlreq.len[0] = nrf53_getreg(NRF53_USBD_WLENGTHL);
+ priv->ctrlreq.len[1] = nrf53_getreg(NRF53_USBD_WLENGTHH);
+
+ /* Store request len */
+
+ priv->ep0reqlen = GETUINT16(priv->ctrlreq.len);
+
+ if (USB_REQ_ISOUT(priv->ctrlreq.type))
+ {
+ priv->ep0datlen = 0;
+
+ if (priv->ep0reqlen == 0)
+ {
+ nrf53_ep0setup(priv);
+ }
+ else
+ {
+ /* Allows OUT data stage on control endpoint 0 */
+
+ nrf53_ep0rcvout_start(priv);
+ }
+ }
+ else
+ {
+ /* Start the setup */
+
+ nrf53_ep0setup(priv);
+ }
+
+ /* Handle zero length packets for IN and OUT */
+
+ if (priv->ep0reqlen == 0)
+ {
+ /* Allows status stage on control endpoint 0 */
+
+ nrf53_ep0status_start(priv);
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_ep0datainterrupt
+ *
+ * Description:
+ * Handle EP0DATADONE event
+ *
+ ****************************************************************************/
+
+static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv)
+{
+ struct nrf53_ep_s *privep = NULL;
+
+ nrf53_startdma_ack(priv);
+
+ if (USB_REQ_ISOUT(priv->ctrlreq.type))
+ {
+ /* Prepare EP OUT DMA transfer */
+
+ privep = &priv->epout[EP0];
+ nrf53_epout_transfer(privep);
+ }
+ else
+ {
+ /* Handle IN request */
+
+ privep = &priv->epin[EP0];
+ nrf53_epin_request(priv, privep);
+
+ if (priv->ep0indone)
+ {
+ /* Allows status stage on control endpoint 0 */
+
+ nrf53_ep0status_start(priv);
+ priv->ep0indone = false;
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_epdatainterrupt
+ *
+ * Description:
+ * Handle EPDATA event
+ *
+ ****************************************************************************/
+
+static void nrf53_epdatainterrupt(struct nrf53_usbdev_s *priv)
+{
+ struct nrf53_ep_s *privep = NULL;
+ uint32_t datastatus = 0;
+ int epno = 0;
+
+ nrf53_startdma_ack(priv);
+
+ /* Get pending data status */
+
+ datastatus = nrf53_getreg(NRF53_USBD_EPDATASTATUS);
+
+ /* Ignore EP0 */
+
+ for (epno = 1; epno < NRF53_NENDPOINTS; epno += 1)
+ {
+ /* A data transfer has occurred on a IN endpoint */
+
+ if (datastatus & USBD_EPDATASTATUS_EPIN(epno))
+ {
+ privep = &priv->epin[epno];
+ nrf53_epin_request(priv, privep);
+ }
+
+ /* A data transfer has occurred on a OUT endpoint */
+
+ if (datastatus & USBD_EPDATASTATUS_EPOUT(epno))
+ {
+ privep = &priv->epout[epno];
+ nrf53_epout_handle(priv, privep);
+ }
+ }
+
+ /* Clear register */
+
+ nrf53_putreg(datastatus, NRF53_USBD_EPDATASTATUS);
+}
+
+/****************************************************************************
+ * Name: nrf53_endepin
+ *
+ * Description:
+ * Handle ENDEPIN events
+ *
+ ****************************************************************************/
+
+static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv)
+{
+ int epno = 0;
+
+ nrf53_startdma_ack(priv);
+
+ /* Process each pending IN endpoint interrupt */
+
+ for (epno = 0; epno < NRF53_NENDPOINTS; epno += 1)
+ {
+ if (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPIN(epno)))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ENDEPIN), epno);
+
+ /* Clear event */
+
+ nrf53_putreg(0, NRF53_USBD_EVENTS_ENDEPIN(epno));
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_endepout
+ *
+ * Description:
+ * Handle ENDEPOUT events
+ *
+ ****************************************************************************/
+
+static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv)
+{
+ struct nrf53_ep_s *privep = NULL;
+ int epno = 0;
+
+ nrf53_startdma_ack(priv);
+
+ /* Process each pending OUT endpoint interrupt */
+
+ for (epno = 0; epno < NRF53_NENDPOINTS; epno += 1)
+ {
+ if (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPOUT(epno)))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ENDEPOUT), epno);
+
+ /* The whole EPOUT buffer has ben consumed */
+
+ if (epno == 0)
+ {
+ nrf53_ep0out_receive(priv);
+
+ if (priv->ep0outdone)
+ {
+ /* Allows status stage on control endpoint 0 */
+
+ nrf53_ep0status_start(priv);
+ priv->ep0outdone = false;
+ }
+ else
+ {
+ /* Allows OUT data stage on control endpoint 0 */
+
+ nrf53_ep0rcvout_start(priv);
+ }
+ }
+ else
+ {
+ privep = &priv->epout[epno];
+ nrf53_epout_receive(privep);
+ }
+
+ /* Clear event */
+
+ nrf53_putreg(0, NRF53_USBD_EVENTS_ENDEPOUT(epno));
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_usbinterrupt
+ *
+ * Description:
+ * USB interrupt handler
+ *
+ ****************************************************************************/
+
+static int nrf53_usbinterrupt(int irq, void *context, void *arg)
+{
+ struct nrf53_usbdev_s *priv = &g_usbdev;
+
+ usbtrace(TRACE_INTENTRY(NRF53_TRACEINTID_USB), 0);
+
+ /* USB reset interrupt */
+
+ if (nrf53_getreg(NRF53_USBD_EVENTS_USBRESET))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DEVRESET), 0);
+ nrf53_usbreset(priv);
+ nrf53_putreg(0, NRF53_USBD_EVENTS_USBRESET);
+ goto intout;
+ }
+
+#ifdef CONFIG_USBDEV_SOFINTERRUPT
+ /* Handle SOF */
+
+ if (nrf53_getreg(NRF53_USBD_EVENTS_SOF))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SOF), 0);
+ nrf53_putreg(0, NRF53_USBD_EVENTS_SOF);
+ }
+#endif
+
+ /* Handle USBEVENT */
+
+ if (nrf53_getreg(NRF53_USBD_EVENTS_USBEVENT))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_USBEVENT), 0);
+ nrf53_eventinterrupt(priv);
+ nrf53_putreg(0, NRF53_USBD_EVENTS_USBEVENT);
+ }
+
+ /* Handle EP0SETUP */
+
+ if (nrf53_getreg(NRF53_USBD_EVENTS_EP0SETUP))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0SETUP), 0);
+ nrf53_ep0setupinterrupt(priv);
+ nrf53_putreg(0, NRF53_USBD_EVENTS_EP0SETUP);
+ }
+
+ /* Handle EP0DATADONE */
+
+ if (nrf53_getreg(NRF53_USBD_EVENTS_EP0DATADONE))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0DATADONE), 0);
+ nrf53_ep0datainterrupt(priv);
+ nrf53_putreg(0, NRF53_USBD_EVENTS_EP0DATADONE);
+ }
+
+ /* Handle EPDATA */
+
+ if (nrf53_getreg(NRF53_USBD_EVENTS_EPDATA))
+ {
+ usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPDATA), 0);
+ nrf53_epdatainterrupt(priv);
+ nrf53_putreg(0, NRF53_USBD_EVENTS_EPDATA);
+ }
+
+ /* Handle all END events */
+
+ nrf53_endepininterrupt(priv);
+ nrf53_endepoutinterrupt(priv);
+
+intout:
+ usbtrace(TRACE_INTEXIT(NRF53_TRACEINTID_USB), 0);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_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 nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
+ uint16_t maxpacket)
+{
+ uint32_t mpsiz = 0;
+ uint32_t regval = 0;
+
+ usbtrace(TRACE_EPCONFIGURE, privep->epphy);
+
+ /* The packet size is in bytes for all EP */
+
+ if (privep->epphy == EP0)
+ {
+ DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
+
+ /* EP0OUT MPSIZ and EPTYP is read only ! */
+
+ mpsiz = 0;
+ eptype = 0;
+ }
+ else
+ {
+ mpsiz = maxpacket;
+ }
+
+ /* Enable the endpoint */
+
+ regval = nrf53_getreg(NRF53_USBD_EPOUTEN);
+ regval |= USBD_EPOUTEN_OUT(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_EPOUTEN);
+
+ /* Configure the max packet size */
+
+ nrf53_putreg(mpsiz, NRF53_USBD_EPOUT_MAXCNT(privep->epphy));
+
+ /* Save the endpoint configuration */
+
+ privep->ep.maxpacket = maxpacket;
+ privep->eptype = eptype;
+ privep->stalled = false;
+
+ /* Allocate buffer for EPOUT */
+
+ privep->rxbuff = kmm_malloc(maxpacket);
+
+ /* Enable the interrupt for this endpoint */
+
+ regval = nrf53_getreg(NRF53_USBD_INTEN);
+ regval |= USBD_INT_ENDEPOUT(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_INTEN);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_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 nrf53_epin_configure(struct nrf53_ep_s *privep, uint8_t eptype,
+ uint16_t maxpacket)
+{
+ uint32_t mpsiz = 0;
+ uint32_t regval = 0;
+
+ usbtrace(TRACE_EPCONFIGURE, privep->epphy);
+
+ /* The packet size is in bytes for all EP */
+
+ mpsiz = maxpacket;
+
+ if (privep->epphy == EP0)
+ {
+ DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
+ }
+ else
+ {
+ DEBUGASSERT(eptype == USB_EP_ATTR_XFER_BULK || USB_EP_ATTR_XFER_INT);
+ }
+
+ /* Enable the endpoint */
+
+ regval = nrf53_getreg(NRF53_USBD_EPINEN);
+ regval |= USBD_EPINEN_IN(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_EPINEN);
+
+ /* Configure the max packet size */
+
+ nrf53_putreg(mpsiz, NRF53_USBD_EPIN_MAXCNT(privep->epphy));
+
+ /* Save the endpoint configuration */
+
+ privep->ep.maxpacket = maxpacket;
+ privep->eptype = eptype;
+ privep->stalled = false;
+
+ /* Enable the interrupt for this endpoint */
+
+ regval = nrf53_getreg(NRF53_USBD_INTEN);
+ regval |= USBD_INT_ENDEPIN(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_INTEN);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_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 last endpoint to be configured. Some hardware
+ * needs to take special action when all of the endpoints have been
+ * configured.
+ *
+ ****************************************************************************/
+
+static int nrf53_ep_configure(struct usbdev_ep_s *ep,
+ const struct usb_epdesc_s *desc, bool last)
+{
+ struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
+ uint16_t maxpacket = 0;
+ uint8_t eptype = 0;
+ int ret = 0;
+
+ 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 = nrf53_epin_configure(privep, eptype, maxpacket);
+ }
+ else
+ {
+ ret = nrf53_epout_configure(privep, eptype, maxpacket);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep0_configure
+ *
+ * Description:
+ * Reset Usb engine
+ *
+ ****************************************************************************/
+
+static void nrf53_ep0_configure(struct nrf53_usbdev_s *priv)
+{
+ /* Enable EP0 IN and OUT */
+
+ nrf53_epin_configure(&priv->epin[EP0],
+ USB_EP_ATTR_XFER_CONTROL,
+ USBDEV_EP0_MAXSIZE);
+ nrf53_epout_configure(&priv->epout[EP0],
+ USB_EP_ATTR_XFER_CONTROL,
+ USBDEV_EP0_MAXSIZE);
+}
+
+/****************************************************************************
+ * Name: nrf53_epout_disable
+ *
+ * Description:
+ * Disable an OUT endpoint will no longer be used
+ *
+ ****************************************************************************/
+
+static void nrf53_epout_disable(struct nrf53_ep_s *privep)
+{
+ uint32_t regval = 0;
+ irqstate_t flags;
+
+ flags = enter_critical_section();
+
+ /* Disable the endpoint */
+
+ regval = nrf53_getreg(NRF53_USBD_EPOUTEN);
+ regval &= ~USBD_EPOUTEN_OUT(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_EPOUTEN);
+
+ /* Disable endpoint interrupts */
+
+ regval = nrf53_getreg(NRF53_USBD_INTEN);
+ regval &= ~USBD_INT_ENDEPOUT(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_INTEN);
+
+ /* Cancel any queued write requests */
+
+ nrf53_req_cancel(privep, -ESHUTDOWN);
+
+ /* Free buffer */
+
+ if (privep->rxbuff)
+ {
+ kmm_free(privep->rxbuff);
+ }
+
+ leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: nrf53_epin_disable
+ *
+ * Description:
+ * Disable an IN endpoint when it will no longer be used
+ *
+ ****************************************************************************/
+
+static void nrf53_epin_disable(struct nrf53_ep_s *privep)
+{
+ irqstate_t flags;
+ uint32_t regval = 0;
+
+ flags = enter_critical_section();
+
+ /* Disable the endpoint */
+
+ regval = nrf53_getreg(NRF53_USBD_EPINEN);
+ regval &= ~USBD_EPINEN_IN(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_EPINEN);
+
+ /* Disable endpoint interrupts */
+
+ regval = nrf53_getreg(NRF53_USBD_INTEN);
+ regval &= ~USBD_INT_ENDEPIN(privep->epphy);
+ nrf53_putreg(regval, NRF53_USBD_INTEN);
+
+ /* Cancel any queued write requests */
+
+ nrf53_req_cancel(privep, -ESHUTDOWN);
+ leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_disable
+ *
+ * Description:
+ * The endpoint will no longer be used
+ *
+ ****************************************************************************/
+
+static int nrf53_ep_disable(struct usbdev_ep_s *ep)
+{
+ struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!ep)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_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 */
+
+ nrf53_epin_disable(privep);
+ }
+ else
+ {
+ /* Disable the OUT endpoint */
+
+ nrf53_epout_disable(privep);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_allocreq
+ *
+ * Description:
+ * Allocate an I/O request
+ *
+ ****************************************************************************/
+
+static struct usbdev_req_s *nrf53_ep_allocreq(struct usbdev_ep_s *ep)
+{
+ struct nrf53_req_s *privreq = NULL;
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!ep)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
+ return NULL;
+ }
+#endif
+
+ usbtrace(TRACE_EPALLOCREQ, ((struct nrf53_ep_s *)ep)->epphy);
+
+ privreq = (struct nrf53_req_s *)kmm_malloc(sizeof(struct nrf53_req_s));
+ if (!privreq)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_ALLOCFAIL), 0);
+ return NULL;
+ }
+
+ memset(privreq, 0, sizeof(struct nrf53_req_s));
+ return &privreq->req;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_freereq
+ *
+ * Description:
+ * Free an I/O request
+ *
+ ****************************************************************************/
+
+static void nrf53_ep_freereq(struct usbdev_ep_s *ep,
+ struct usbdev_req_s *req)
+{
+ struct nrf53_req_s *privreq = (struct nrf53_req_s *)req;
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!ep || !req)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
+ return;
+ }
+#endif
+
+ usbtrace(TRACE_EPFREEREQ, ((struct nrf53_ep_s *)ep)->epphy);
+ kmm_free(privreq);
+}
+
+#ifdef CONFIG_USBDEV_DMA
+/****************************************************************************
+ * Name: nrf53_ep_allocbuffer
+ *
+ * Description:
+ * Allocate an I/O buffer
+ *
+ ****************************************************************************/
+
+static void *nrf53_ep_allocbuffer(struct usbdev_ep_s *ep, unsigned bytes)
+{
+ usbtrace(TRACE_EPALLOCBUFFER, ((struct nrf53_ep_s *)ep)->epphy);
+ return kmm_malloc(bytes);
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_freebuffer
+ *
+ * Description:
+ * Free an I/O buffer
+ *
+ ****************************************************************************/
+
+static void nrf53_ep_freebuffer(struct usbdev_ep_s *ep, void *buf)
+{
+ usbtrace(TRACE_EPALLOCBUFFER, ((struct nrf53_ep_s *)ep)->epphy);
+ kmm_free(buf);
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf53_ep_submit
+ *
+ * Description:
+ * Submit an I/O request to the endpoint
+ *
+ ****************************************************************************/
+
+static int nrf53_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+{
+ struct nrf53_req_s *privreq = (struct nrf53_req_s *)req;
+ struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
+ struct nrf53_usbdev_s *priv = NULL;
+ irqstate_t flags;
+ int ret = OK;
+
+ /* Some sanity checking */
+
+ DEBUGASSERT(privep && privep->dev);
+ priv = (struct nrf53_usbdev_s *)privep->dev;
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!req || !req->callback || !req->buf || !ep)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
+ uinfo("req=%p callback=%p buf=%p ep=%p\n",
+ req, req->callback, req->buf, ep);
+ return -EINVAL;
+ }
+#endif
+
+ usbtrace(TRACE_EPSUBMIT, privep->epphy);
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_NOTCONFIGURED),
+ priv->usbdev.speed);
+ return -ESHUTDOWN;
+ }
+#endif
+
+ /* Handle the request from the class driver */
+
+ req->result = -EINPROGRESS;
+ req->xfrd = 0;
+
+ /* Disable Interrupts */
+
+ flags = enter_critical_section();
+
+ /* 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 (nrf53_req_addlast(privep, privreq))
+ {
+ /* 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);
+ nrf53_epin_request(priv, privep);
+ }
+
+ /* If the request was added to an OUT endpoint, 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);
+
+ /* Allow OUT trafic on this endpoint */
+
+ nrf53_epout_allow(privep);
+ }
+ }
+ }
+
+ leave_critical_section(flags);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_cancel
+ *
+ * Description:
+ * Cancel an I/O request previously sent to an endpoint
+ *
+ ****************************************************************************/
+
+static int nrf53_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
+{
+ struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
+ irqstate_t flags;
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!ep || !req)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+#endif
+
+ usbtrace(TRACE_EPCANCEL, privep->epphy);
+
+ flags = enter_critical_section();
+ nrf53_req_cancel(privep, -ESHUTDOWN);
+ leave_critical_section(flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_setstall
+ *
+ * Description:
+ * Stall an endpoint
+ *
+ ****************************************************************************/
+
+static int nrf53_ep_setstall(struct nrf53_ep_s *privep)
+{
+ uint32_t regval = 0;
+
+ /* Is this an IN endpoint? */
+
+ if (privep->isin == 1)
+ {
+ regval |= USBD_EPSTALL_IO_IN;
+ }
+ else
+ {
+ regval |= USBD_EPSTALL_IO_OUT;
+ }
+
+ /* Unstall a given EP */
+
+ regval |= USBD_EPSTALL_EP(privep->epphy) | USBD_EPSTALL_IO_STALL;
+ nrf53_putreg(regval, NRF53_USBD_EPSTALL);
+
+ /* The endpoint is now stalled */
+
+ privep->stalled = true;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_clrstall
+ *
+ * Description:
+ * Resume a stalled endpoint
+ *
+ ****************************************************************************/
+
+static int nrf53_ep_clrstall(struct nrf53_ep_s *privep)
+{
+ uint32_t regval = 0;
+
+ /* Is this an IN endpoint? */
+
+ if (privep->isin == 1)
+ {
+ regval |= USBD_EPSTALL_IO_IN;
+ }
+ else
+ {
+ regval |= USBD_EPSTALL_IO_OUT;
+ }
+
+ /* Unstall a given EP */
+
+ regval |= USBD_EPSTALL_EP(privep->epphy) | USBD_EPSTALL_IO_UNSTALL;
+ nrf53_putreg(regval, NRF53_USBD_EPSTALL);
+
+ /* The endpoint is no longer stalled */
+
+ privep->stalled = false;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_stall
+ *
+ * Description:
+ * Stall or resume an endpoint
+ *
+ ****************************************************************************/
+
+static int nrf53_ep_stall(struct usbdev_ep_s *ep, bool resume)
+{
+ struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
+ irqstate_t flags;
+ int ret = 0;
+
+ /* Set or clear the stall condition as requested */
+
+ flags = enter_critical_section();
+
+ if (resume)
+ {
+ ret = nrf53_ep_clrstall(privep);
+ }
+ else
+ {
+ ret = nrf53_ep_setstall(privep);
+ }
+
+ leave_critical_section(flags);
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep0_stall
+ *
+ * Description:
+ * Stall endpoint 0
+ *
+ ****************************************************************************/
+
+static void nrf53_ep0_stall(struct nrf53_usbdev_s *priv)
+{
+ nrf53_putreg(1, NRF53_USBD_TASKS_EP0STALL);
+ priv->stalled = true;
+}
+
+/****************************************************************************
+ * Name: nrf53_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 struct usbdev_ep_s *
+nrf53_ep_alloc(struct usbdev_s *dev, uint8_t eplog, bool in, uint8_t eptype)
+{
+ struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
+ irqstate_t flags;
+ uint8_t epavail = 0;
+ uint8_t bit = 0;
+ int epphy = 0;
+ 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 = enter_critical_section();
+ 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 >= NRF53_NENDPOINTS)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_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 < NRF53_NENDPOINTS; epno++)
+ {
+ 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 */
+
+ leave_critical_section(flags);
+ return in ? &priv->epin[epno].ep : &priv->epout[epno].ep;
+ }
+ }
+
+ /* We should not get here */
+ }
+
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_NOEP), (uint16_t)eplog);
+ leave_critical_section(flags);
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: nrf53_ep_free
+ *
+ * Description:
+ * Free the previously allocated endpoint
+ *
+ ****************************************************************************/
+
+static void nrf53_ep_free(struct usbdev_s *dev, struct usbdev_ep_s *ep)
+{
+ struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
+ struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy);
+
+ if (priv && privep)
+ {
+ /* Mark the endpoint as available */
+
+ flags = enter_critical_section();
+ priv->epavail[privep->isin] |= (1 << privep->epphy);
+ leave_critical_section(flags);
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_getframe
+ *
+ * Description:
+ * Returns the current frame number
+ *
+ ****************************************************************************/
+
+static int nrf53_getframe(struct usbdev_s *dev)
+{
+ usbtrace(TRACE_DEVGETFRAME, 0);
+
+ /* Return the last frame number of the last SOF detected by the hardware */
+
+ return nrf53_getreg(NRF53_USBD_FRAMECNTR) & USBD_FRAMECNTR_MASK;
+}
+
+/****************************************************************************
+ * Name: nrf53_wakeup
+ *
+ * Description:
+ * Exit suspend mode.
+ *
+ ****************************************************************************/
+
+static int nrf53_wakeup(struct usbdev_s *dev)
+{
+ struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVWAKEUP, 0);
+
+ /* Is wakeup enabled? */
+
+ flags = enter_critical_section();
+ if (priv->wakeup)
+ {
+#ifdef CONFIG_USBDEV_LOWPOWER
+ /* Force normal state */
+
+ nrf53_putreg(0, NRF53_USBD_LOWPOWER);
+
+ /* TODO: wait for event */
+#endif
+
+ /* Revisit: */
+#if 0
+ nrf53_putreg(USBD_DPDMVALUE_STATE_RESUME, NRF53_USBD_DPDMVALUE);
+ nrf53_putreg(1, NRF53_USBD_TASKS_DPDMDRIVE);
+#endif
+ }
+
+ leave_critical_section(flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_selfpowered
+ *
+ * Description:
+ * Sets/clears the device self-powered feature
+ *
+ ****************************************************************************/
+
+static int nrf53_selfpowered(struct usbdev_s *dev, bool selfpowered)
+{
+ struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
+
+ usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered);
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!dev)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
+ return -ENODEV;
+ }
+#endif
+
+ priv->selfpowered = selfpowered;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_pullup
+ *
+ * Description:
+ * Software-controlled connect to/disconnect from USB host
+ *
+ ****************************************************************************/
+
+int nrf53_pullup(struct usbdev_s *dev, bool enable)
+{
+ if (enable)
+ {
+ nrf53_putreg(USBD_USBPULLUP_ENABLE, NRF53_USBD_USBPULLUP);
+ }
+ else
+ {
+ nrf53_putreg(USBD_USBPULLUP_DISABLE, NRF53_USBD_USBPULLUP);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: nrf53_setaddress
+ *
+ * Description:
+ * Set the devices USB address
+ *
+ ****************************************************************************/
+
+static void nrf53_setaddress(struct nrf53_usbdev_s *priv, uint16_t address)
+{
+ /* Are we now addressed? (i.e., do we have a non-NULL device
+ * address?)
+ */
+
+ if (address != 0)
+ {
+ priv->addressed = true;
+ }
+ else
+ {
+ priv->addressed = false;
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_swinitialize
+ *
+ * Description:
+ * Initialize all driver data structures.
+ *
+ ****************************************************************************/
+
+static void nrf53_swinitialize(struct nrf53_usbdev_s *priv)
+{
+ struct nrf53_ep_s *privep;
+ int i;
+
+ /* Initialize the device state structure */
+
+ memset(priv, 0, sizeof(struct nrf53_usbdev_s));
+
+ priv->usbdev.ops = &g_devops;
+ priv->usbdev.ep0 = &priv->epin[EP0].ep;
+
+ priv->epavail[0] = NRF53_EP_AVAILABLE;
+ priv->epavail[1] = NRF53_EP_AVAILABLE;
+
+ /* Initialize the endpoint lists */
+
+ for (i = 0; i < NRF53_NENDPOINTS; i++)
+ {
+ 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 = NRF53_EPPHYIN2LOG(i);
+
+ /* Control until endpoint is activated */
+
+ privep->eptype = USB_EP_ATTR_XFER_CONTROL;
+ privep->ep.maxpacket = USBDEV_EP0_MAXSIZE;
+ }
+
+ /* Initialize the endpoint lists */
+
+ for (i = 0; i < NRF53_NENDPOINTS; i++)
+ {
+ 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 = NRF53_EPPHYOUT2LOG(i);
+
+ /* Control until endpoint is activated */
+
+ privep->eptype = USB_EP_ATTR_XFER_CONTROL;
+ privep->ep.maxpacket = USBDEV_EP0_MAXSIZE;
+ }
+}
+
+/****************************************************************************
+ * Name: nrf53_hwinitialize
+ *
+ * Description:
+ * Configure the USB core for operation.
+ *
+ ****************************************************************************/
+
+static void nrf53_hwinitialize(struct nrf53_usbdev_s *priv)
+{
+ /* Wait for VBUS */
+
+ /* TODO: connect to POWER USB events */
+
+ while (getreg32(NRF53_USBREG_EVENTS_USBDETECTED) == 0);
+
+ /* Enable the USB controller */
+
+ nrf53_putreg(USBD_ENABLE_ENABLE, NRF53_USBD_ENABLE);
+
+ while ((nrf53_getreg(NRF53_USBD_EVENTCAUSE) & USBD_EVENTCAUSE_READY) == 0);
+ nrf53_putreg(USBD_EVENTCAUSE_READY, NRF53_USBD_EVENTCAUSE);
+
+ /* Disable all endpoints */
+
+ nrf53_putreg(0, NRF53_USBD_EPOUTEN);
+ nrf53_putreg(0, NRF53_USBD_EPINEN);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_usbinitialize
+ *
+ * Description:
+ * Initialize the USB driver
+ *
+ ****************************************************************************/
+
+void arm_usbinitialize(void)
+{
+ struct nrf53_usbdev_s *priv = &g_usbdev;
+ int ret = 0;
+
+ usbtrace(TRACE_DEVINIT, 0);
+
+ /* Uninitialize the hardware so that we know that we are starting from a
+ * known state.
+ */
+
+ arm_usbuninitialize();
+
+ /* Initialie the driver data structure */
+
+ nrf53_swinitialize(priv);
+
+ /* Attach the USB interrupt handler */
+
+ ret = irq_attach(NRF53_IRQ_USBD, nrf53_usbinterrupt, NULL);
+ if (ret < 0)
+ {
+ uerr("ERROR: irq_attach failed: %d\n", ret);
+ goto errout;
+ }
+
+ /* Initialize the USB core */
+
+ nrf53_hwinitialize(priv);
+
+ /* Disconnect device */
+
+ nrf53_pullup(&priv->usbdev, false);
+
+ /* Reset/Re-initialize the USB hardware */
+
+ nrf53_usbreset(priv);
+
+ /* Enable USB controller interrupts at the NVIC */
+
+ up_enable_irq(NRF53_IRQ_USBD);
+ return;
+
+errout:
+ arm_usbuninitialize();
+}
+
+/****************************************************************************
+ * Name: arm_usbuninitialize
+ *
+ * Description:
+ * Initialize the USB driver
+ *
+ ****************************************************************************/
+
+void arm_usbuninitialize(void)
+{
+ struct nrf53_usbdev_s *priv = &g_usbdev;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVUNINIT, 0);
+
+ if (priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DRIVERREGISTERED), 0);
+ usbdev_unregister(priv->driver);
+ }
+
+ /* Disconnect device */
+
+ flags = enter_critical_section();
+ nrf53_pullup(&priv->usbdev, false);
+ priv->usbdev.speed = USB_SPEED_UNKNOWN;
+
+ /* Disable and detach IRQs */
+
+ up_disable_irq(NRF53_IRQ_USBD);
+ irq_detach(NRF53_IRQ_USBD);
+
+ /* Disable all interrupts */
+
+ nrf53_putreg(0, NRF53_USBD_INTEN);
+
+ /* Disable the USB controller */
+
+ nrf53_putreg(USBD_ENABLE_DISABLE, NRF53_USBD_ENABLE);
+
+ leave_critical_section(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)
+{
+ struct nrf53_usbdev_s *priv = &g_usbdev;
+ int ret = 0;
+
+ usbtrace(TRACE_DEVREGISTER, 0);
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (!driver || !driver->ops->bind || !driver->ops->unbind ||
+ !driver->ops->disconnect || !driver->ops->setup)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
+ return -EINVAL;
+ }
+
+ if (priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_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(NRF53_TRACEERR_BINDFAILED), (uint16_t)-ret);
+ priv->driver = NULL;
+ }
+ else
+ {
+ /* Enable USB controller interrupts */
+
+ up_enable_irq(NRF53_IRQ_USBD);
+
+ nrf53_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)
+{
+ struct nrf53_usbdev_s *priv = &g_usbdev;
+ irqstate_t flags;
+
+ usbtrace(TRACE_DEVUNREGISTER, 0);
+
+#ifdef CONFIG_DEBUG_FEATURES
+ if (driver != priv->driver)
+ {
+ usbtrace(TRACE_DEVERROR(NRF53_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 = enter_critical_section();
+ nrf53_usbreset(priv);
+ leave_critical_section(flags);
+
+ /* Unbind the class driver */
+
+ CLASS_UNBIND(driver, &priv->usbdev);
+
+ /* Disable USB controller interrupts */
+
+ flags = enter_critical_section();
+ up_disable_irq(NRF53_IRQ_USBD);
+
+ /* Disconnect device */
+
+ nrf53_pullup(&priv->usbdev, false);
+
+ /* Unhook the driver */
+
+ priv->driver = NULL;
+ leave_critical_section(flags);
+
+ return OK;
+}
diff --git a/arch/arm/src/nrf53/nrf53_usbd.h b/arch/arm/src/nrf53/nrf53_usbd.h
new file mode 100644
index 0000000000..dba0ec0231
--- /dev/null
+++ b/arch/arm/src/nrf53/nrf53_usbd.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * arch/arm/src/nrf53/nrf53_usbd.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF53_NRF53_USBD_H
+#define __ARCH_ARM_SRC_NRF53_NRF53_USBD_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdbool.h>
+
+#include <nuttx/config.h>
+#include <nuttx/usb/usbdev.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NRF53_NENDPOINTS (8) /* EP0-7 x 2 */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf53_usbsuspend
+ *
+ * Description:
+ * Board logic must provide the nrf53_usbsuspend logic if the USBDEV 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 nrf53_usbsuspend(struct usbdev_s *dev, bool resume);
+
+#endif /* __ARCH_ARM_SRC_NRF53_NRF53_USBD_H */