You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/08/13 17:08:15 UTC

[incubator-nuttx] branch master updated (c974839 -> 35e0d74)

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git.


    from c974839  make/export: Fix mkexport silently failing on missing tools
     new af85c78  arch: samd5e5 : Add watchdog timer drivers.
     new 4e8e21a  Style fixes
     new 35e0d74  arch: samd5e5 : Add USB host support. 		Fixes in USB device and i2c.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 arch/arm/src/samd5e5/Kconfig                       |    3 +
 arch/arm/src/samd5e5/Make.defs                     |    9 +
 arch/arm/src/samd5e5/hardware/sam_i2c_master.h     |   46 +-
 arch/arm/src/samd5e5/hardware/sam_usb.h            |  158 +-
 arch/arm/src/samd5e5/sam_i2c_master.c              |  126 +-
 .../arm/src/samd5e5/sam_i2c_master.h               |   50 +-
 arch/arm/src/samd5e5/sam_usb.c                     | 5356 ++++++++++++++++++--
 arch/arm/src/samd5e5/sam_usb.h                     |   23 +-
 arch/arm/src/samd5e5/sam_usbhost.c                 |  378 ++
 arch/arm/src/samd5e5/sam_usbhost.h                 |  293 ++
 boards/arm/samd5e5/metro-m4/Kconfig                |   29 +
 boards/arm/samd5e5/metro-m4/include/board.h        |   39 +-
 boards/arm/samd5e5/metro-m4/src/Makefile           |   24 +
 boards/arm/samd5e5/metro-m4/src/metro-m4.h         |   12 +-
 .../metro-m4}/src/sam_automount.c                  |  104 +-
 boards/arm/samd5e5/metro-m4/src/sam_bringup.c      |   49 +
 .../metro-m4}/src/sam_composite.c                  |   55 +-
 .../arm/samd5e5/metro-m4/src/sam_i2c.c             |   78 +-
 .../arm/samd5e5/metro-m4/src/sam_usbdev.c          |   75 +-
 .../metro-m4/src/sam_usbhost.c}                    |  134 +-
 .../samd5e5/metro-m4/src/sam_usbmsc.c}             |   36 +-
 21 files changed, 6279 insertions(+), 798 deletions(-)
 copy boards/arm/stm32/common/include/stm32_nunchuck.h => arch/arm/src/samd5e5/sam_i2c_master.h (74%)
 create mode 100644 arch/arm/src/samd5e5/sam_usbhost.c
 create mode 100644 arch/arm/src/samd5e5/sam_usbhost.h
 copy boards/arm/{samv7/samv71-xult => samd5e5/metro-m4}/src/sam_automount.c (78%)
 copy boards/arm/{samv7/samv71-xult => samd5e5/metro-m4}/src/sam_composite.c (83%)
 copy arch/arm/src/samd5e5/sam_wdt.h => boards/arm/samd5e5/metro-m4/src/sam_i2c.c (65%)
 copy arch/z16/src/common/z16_allocateheap.c => boards/arm/samd5e5/metro-m4/src/sam_usbdev.c (58%)
 copy boards/arm/{stm32/axoloti/src/stm32_usbhost.c => samd5e5/metro-m4/src/sam_usbhost.c} (54%)
 copy boards/{risc-v/litex/arty_a7/src/litex_boot.c => arm/samd5e5/metro-m4/src/sam_usbmsc.c} (71%)


[incubator-nuttx] 02/03: Style fixes

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 4e8e21a92a8f8bf4cb90239e4f153bb357ee8746
Author: leomarradke <le...@falker.com.br>
AuthorDate: Tue Aug 4 19:56:39 2020 -0300

    Style fixes
---
 arch/arm/src/samd5e5/hardware/sam_wdt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/src/samd5e5/hardware/sam_wdt.h b/arch/arm/src/samd5e5/hardware/sam_wdt.h
index 9d1d98b..f6911b5 100644
--- a/arch/arm/src/samd5e5/hardware/sam_wdt.h
+++ b/arch/arm/src/samd5e5/hardware/sam_wdt.h
@@ -143,4 +143,4 @@
  * Public Data
  ****************************************************************************/
 
-#endif /* __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_WDT_H */
\ No newline at end of file
+#endif /* __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_WDT_H */


[incubator-nuttx] 03/03: arch: samd5e5 : Add USB host support. Fixes in USB device and i2c.

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 35e0d74f3e926a77ce33b172d66e2c8b3ae420a1
Author: leomarradke <le...@falker.com.br>
AuthorDate: Mon Aug 10 17:11:34 2020 -0300

    arch: samd5e5 : Add USB host support.
    		Fixes in USB device and i2c.
    
    boards: metro-m4  Add support for:
    
    - vfat auto-mounted on a flash drive;
    - i2c inicialization;
    - usb-dev cdc;
    - sam_usbhost_vbusdrive needs your VBUS implementation.
    
    Testing:
    - Build check only.
    
    Signed-off-by: Leomar Mateus Radke  <le...@falker.com.br>
---
 arch/arm/src/samd5e5/Kconfig                    |    3 +
 arch/arm/src/samd5e5/Make.defs                  |    9 +
 arch/arm/src/samd5e5/hardware/sam_i2c_master.h  |   46 +-
 arch/arm/src/samd5e5/hardware/sam_usb.h         |  158 +-
 arch/arm/src/samd5e5/sam_i2c_master.c           |  126 +-
 arch/arm/src/samd5e5/sam_i2c_master.h           |   87 +
 arch/arm/src/samd5e5/sam_usb.c                  | 5356 +++++++++++++++++++++--
 arch/arm/src/samd5e5/sam_usb.h                  |   23 +-
 arch/arm/src/samd5e5/sam_usbhost.c              |  378 ++
 arch/arm/src/samd5e5/sam_usbhost.h              |  293 ++
 boards/arm/samd5e5/metro-m4/Kconfig             |   29 +
 boards/arm/samd5e5/metro-m4/include/board.h     |   39 +-
 boards/arm/samd5e5/metro-m4/src/Makefile        |   24 +
 boards/arm/samd5e5/metro-m4/src/metro-m4.h      |   12 +-
 boards/arm/samd5e5/metro-m4/src/sam_automount.c |  331 ++
 boards/arm/samd5e5/metro-m4/src/sam_bringup.c   |   49 +
 boards/arm/samd5e5/metro-m4/src/sam_composite.c |  348 ++
 boards/arm/samd5e5/metro-m4/src/sam_i2c.c       |   87 +
 boards/arm/samd5e5/metro-m4/src/sam_usbdev.c    |   92 +
 boards/arm/samd5e5/metro-m4/src/sam_usbhost.c   |  236 +
 boards/arm/samd5e5/metro-m4/src/sam_usbmsc.c    |   71 +
 21 files changed, 7284 insertions(+), 513 deletions(-)

diff --git a/arch/arm/src/samd5e5/Kconfig b/arch/arm/src/samd5e5/Kconfig
index 2d28100..85ae19b 100644
--- a/arch/arm/src/samd5e5/Kconfig
+++ b/arch/arm/src/samd5e5/Kconfig
@@ -465,6 +465,9 @@ config SAMD5E5_TC7
 config SAMD5E5_USB
 	bool "USB"
 	default n
+	select USBHOST_HAVE_ASYNCH
+	---help---
+		Build support for the SAMD51 USB full speed USB host.
 
 config SAMD5E5_EIC
 	bool "External Interrupt Controller"
diff --git a/arch/arm/src/samd5e5/Make.defs b/arch/arm/src/samd5e5/Make.defs
index 7a2198e..4a0b720 100644
--- a/arch/arm/src/samd5e5/Make.defs
+++ b/arch/arm/src/samd5e5/Make.defs
@@ -153,6 +153,15 @@ endif
 
 ifeq ($(CONFIG_SAMD5E5_USB),y)
 CHIP_CSRCS += sam_usb.c
+ifeq ($(CONFIG_USBHOST),y)
+ifeq ($(CONFIG_USBHOST_TRACE),y)
+CHIP_CSRCS += sam_usbhost.c
+else
+ifeq ($(CONFIG_DEBUG_USB),y)
+CHIP_CSRCS += sam_usbhost.c
+endif
+endif
+endif
 endif
 
 ifeq ($(CONFIG_SAMD5E5_SDHC0),y)
diff --git a/arch/arm/src/samd5e5/hardware/sam_i2c_master.h b/arch/arm/src/samd5e5/hardware/sam_i2c_master.h
index 8298f5f..87e5b5d 100644
--- a/arch/arm/src/samd5e5/hardware/sam_i2c_master.h
+++ b/arch/arm/src/samd5e5/hardware/sam_i2c_master.h
@@ -178,31 +178,31 @@
 #define I2C_CTRLA_MODE_SHIFT       (2)       /* Bits 2-4: Operating Mode */
 #define I2C_CTRLA_MODE_MASK        (7 << I2C_CTRLA_MODE_SHIFT)
 #  define I2C_CTRLA_MODE_MASTER    (5 << I2C_CTRLA_MODE_SHIFT) /* I2C master mode */
-#define I2C_CTRLA_RUNSTDBY         (1 << 7)  /* Bit 7:  Run in standby */
-#define I2C_CTRLA_PINOUT           (1 << 16) /* Bit 16: Transmit data pinout */
-#  define I2C_CTRLA_1WIRE          (0)              /* 4-wire operation disable */
-#  define I2C_CTRLA_4WIRE          I2C_CTRLA_PINOUT /* 4-wire operation enable */
-#define I2C_CTRLA_SDAHOLD_SHIFT    (20)      /* Bits 20-21: SDA Hold Time */
+#define I2C_CTRLA_RUNSTDBY         (1 << 7)                    /* Bit 7:  Run in standby */
+#define I2C_CTRLA_PINOUT           (1 << 16)                   /* Bit 16: Transmit data pinout */
+#  define I2C_CTRLA_1WIRE          (0)                         /* 4-wire operation disable */
+#  define I2C_CTRLA_4WIRE          I2C_CTRLA_PINOUT            /* 4-wire operation enable */
+#define I2C_CTRLA_SDAHOLD_SHIFT    (20)                        /* Bits 20-21: SDA Hold Time */
 #define I2C_CTRLA_SDAHOLD_MASK     (3 << I2C_CTRLA_SDAHOLD_SHIFT)
 #  define I2C_CTRLA_SDAHOLD_DIS    (0 << I2C_CTRLA_SDAHOLD_SHIFT) /* Disabled */
 #  define I2C_CTRLA_SDAHOLD_75NS   (1 << I2C_CTRLA_SDAHOLD_SHIFT) /* 50-100ns hold time */
 #  define I2C_CTRLA_SDAHOLD_450NS  (2 << I2C_CTRLA_SDAHOLD_SHIFT) /* 300-600ns hold time */
 #  define I2C_CTRLA_SDAHOLD_600NS  (3 << I2C_CTRLA_SDAHOLD_SHIFT) /* 400-800ns hold time */
-#define I2C_CTRLA_MEXTTOEN         (1 << 22) /* Bit 22: Master SCL low extend time-out */
-#define I2C_CTRLA_SEXTTOEN         (1 << 23) /* Bit 23: Slave SCL low extend time-out */
-#define I2C_CTRLA_SPEED_SHIFT      (24)      /* Bits 24-25: Transfer speed */
+#define I2C_CTRLA_MEXTTOEN         (1 << 22)                      /* Bit 22: Master SCL low extend time-out */
+#define I2C_CTRLA_SEXTTOEN         (1 << 23)                      /* Bit 23: Slave SCL low extend time-out */
+#define I2C_CTRLA_SPEED_SHIFT      (24)                           /* Bits 24-25: Transfer speed */
 #define I2C_CTRLA_SPEED_MASK       (3 << I2C_CTRLA_SPEED_SHIFT)
 #  define I2C_CTRLA_SPEED_STD      (0 << I2C_CTRLA_SPEED_SHIFT) /* Standard (<=100KHz) and fast (<=400KHz) */
 #  define I2C_CTRLA_SPEED_FAST     (1 << I2C_CTRLA_SPEED_SHIFT) /* Fast-mode plus (<=1MHz) */
 #  define I2C_CTRLA_SPEED_HIGH     (2 << I2C_CTRLA_SPEED_SHIFT) /* High speed mode (<=3.4Mhz */
-#define I2C_CTRLA_SCLAM            (1 << 27) /* Bit 27: CSL clock stretch mode */
-#define I2C_CTRLA_INACTOUT_SHIFT   (28)      /* Bits 28-29: Inactive Time-Out */
+#define I2C_CTRLA_SCLAM            (1 << 27)                    /* Bit 27: CSL clock stretch mode */
+#define I2C_CTRLA_INACTOUT_SHIFT   (28)                         /* Bits 28-29: Inactive Time-Out */
 #define I2C_CTRLA_INACTOUT_MASK    (7 << I2C_CTRLA_INACTOUT_SHIFT)
 #  define I2C_CTRLA_INACTOUT_DIS   (0 << I2C_CTRLA_INACTOUT_SHIFT) /* Disabled */
 #  define I2C_CTRLA_INACTOUT_55US  (1 << I2C_CTRLA_INACTOUT_SHIFT) /* 5-6 SCL cycle time-out (50-60�s) */
 #  define I2C_CTRLA_INACTOUT_105US (2 << I2C_CTRLA_INACTOUT_SHIFT) /* 10-11 SCL cycle time-out (100-110�s) */
 #  define I2C_CTRLA_INACTOUT_205US (3 << I2C_CTRLA_INACTOUT_SHIFT) /* 20-21 SCL cycle time-out (200-210�s) */
-#define I2C_CTRLA_LOWTOUT          (1 << 30)  /* Bit 30: SCL Low Time-Out */
+#define I2C_CTRLA_LOWTOUT          (1 << 30)                       /* Bit 30: SCL Low Time-Out */
 
 /* Control B register */
 
@@ -214,13 +214,13 @@
 #  define I2C_CTRLB_CMD_ACKREP     (1 << I2C_CTRLB_CMD_SHIFT) /* ACK followed by repeated START */
 #  define I2C_CTRLB_CMD_ACKREAD    (2 << I2C_CTRLB_CMD_SHIFT) /* ACK followed by read operation */
 #  define I2C_CTRLB_CMD_ACKSTOP    (3 << I2C_CTRLB_CMD_SHIFT) /* ACK followed by STOP */
-#define I2C_CTRLB_ACKACT           (1 << 18) /* Bit 18: Acknowledge Action */
-#  define I2C_CTRLB_ACK            (0)              /* Send ACK */
-#  define I2C_CTRLB_NACK           I2C_CTRLB_ACKACT /* Send NACK */
+#define I2C_CTRLB_ACKACT           (1 << 18)                  /* Bit 18: Acknowledge Action */
+#  define I2C_CTRLB_ACK            (0)                        /* Send ACK */
+#  define I2C_CTRLB_NACK           I2C_CTRLB_ACKACT           /* Send NACK */
 
 /* Control C register */
 
-#define I2C_CTRLC_DATA32B          (1 << 24) /* Bit 24: Data 32 Bit */
+#define I2C_CTRLC_DATA32B          (1 << 24)         /* Bit 24: Data 32 Bit */
 #  define I2C_CTRLC_DATA32B_8BIT   (0)               /* DATA register is 8-bit */
 #  define I2C_CTRLC_DATA32B_32BIT  I2C_CTRLC_DATA32B /* DATA register is 32-bit */
 
@@ -231,13 +231,13 @@
 #  define I2C_BAUD(n)              ((uint16)(n) << I2C_BAUD_SHIFT)
 #define I2C_BAUDLOW_SHIFT          (8)       /* Bits 8-15: Master Baud Rate Low */
 #define I2C_BAUDLOW_MASK           (0xff << I2C_BAUDLOW_SHIFT)
-#  define I2C_BAUDLOW(n)           (uint16)(n) << I2C_BAUDLOW_SHIFT)
+#  define I2C_BAUDLOW(n)           ((uint16)(n) << I2C_BAUDLOW_SHIFT)
 #define I2C_HSBAUD_SHIFT           (16)      /* Bits 16-23: High speed master Baud Rate */
 #define I2C_HSBAUD_MASK            (0xff << I2C_HSBAUD_SHIFT)
 #  define I2C_HSBAUD(n)            ((uint16)(n) << I2C_HSBAUD_SHIFT)
 #define I2C_HSBAUDLOW_SHIFT        (24)      /* Bits 24-31: High speed master Baud Rate Low */
 #define I2C_HSBAUDLOW_MASK         (0xff << I2C_HSBAUDLOW_SHIFT)
-#  define I2C_HSBAUDLOW(n)         (uint16)(n) << I2C_HSBAUDLOW_SHIFT)
+#  define I2C_HSBAUDLOW(n)         ((uint16)(n) << I2C_HSBAUDLOW_SHIFT)
 
 /* Interrupt enable clear, interrupt enable set, interrupt enable set, interrupt flag and
  * status clear registers.
@@ -260,11 +260,11 @@
 #  define I2C_STATUS_BUSSTATE_IDLE    (1 << I2C_STATUS_BUSSTATE_SHIFT) /* Waiting for transaction */
 #  define I2C_STATUS_BUSSTATE_OWNER   (2 << I2C_STATUS_BUSSTATE_SHIFT) /* Master of bus owner */
 #  define I2C_STATUS_BUSSTATE_BUSY    (3 << I2C_STATUS_BUSSTATE_SHIFT) /* Other master owns */
-#define I2C_STATUS_LOWTOUT         (1 << 6)  /* Bit 6:  SCL Low Time-Out */
-#define I2C_STATUS_CLKHOLD         (1 << 7)  /* Bit 7:  Clock Hold */
-#define I2C_STATUS_MEXTTOUT        (1 << 8)  /* Bit 8:  Master SCL low extend time-out */
-#define I2C_STATUS_SEXTTOUT        (1 << 9)  /* Bit 9:  Slave SCL low extend time-out */
-#define I2C_STATUS_LENERR          (1 << 10) /* Bit 10: Transaction length error */
+#define I2C_STATUS_LOWTOUT         (1 << 6)                            /* Bit 6:  SCL Low Time-Out */
+#define I2C_STATUS_CLKHOLD         (1 << 7)                            /* Bit 7:  Clock Hold */
+#define I2C_STATUS_MEXTTOUT        (1 << 8)                            /* Bit 8:  Master SCL low extend time-out */
+#define I2C_STATUS_SEXTTOUT        (1 << 9)                            /* Bit 9:  Slave SCL low extend time-out */
+#define I2C_STATUS_LENERR          (1 << 10)                           /* Bit 10: Transaction length error */
 
 /* Synchronization busy register */
 
@@ -301,7 +301,7 @@
  ********************************************************************************************/
 
 /********************************************************************************************
- * Public Functions
+ * Public Functions Prototypes
  ********************************************************************************************/
 
 #endif /* __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_I2C_MASTER_H */
diff --git a/arch/arm/src/samd5e5/hardware/sam_usb.h b/arch/arm/src/samd5e5/hardware/sam_usb.h
index 5c100e3..eaae793 100644
--- a/arch/arm/src/samd5e5/hardware/sam_usb.h
+++ b/arch/arm/src/samd5e5/hardware/sam_usb.h
@@ -1,55 +1,39 @@
-/********************************************************************************************
+/****************************************************************************
  * arch/arm/src/samd5e5/hardware/sam_usb.h
  *
- *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
+ * 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
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
+ * 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.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ********************************************************************************************/
-
+ ****************************************************************************/
 
 #ifndef __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_USB_H
 #define __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_USB_H
 
-/********************************************************************************************
+/****************************************************************************
  * Included Files
- ********************************************************************************************/
+ ****************************************************************************/
 
 #include <nuttx/config.h>
 
 #include "chip.h"
 
-/********************************************************************************************
+/****************************************************************************
  * Pre-processor Definitions
- ********************************************************************************************/
+ ****************************************************************************/
 
-/* Capabilities and characteristics of endpoints ********************************************/
+/* Capabilities and characteristics of endpoints */
 
 /*   EP  EP BANKS  EP SIZE   EP TYPE
  *   --- --------- --------- ---------
@@ -71,7 +55,7 @@
 #define SAM_USB_ISOCHRONOUS(ep)        (true)
 #define SAM_USB_INTERRUPT(ep)          (true)
 
-/* USB register offsets ********************************************************************/
+/* USB register offsets */
 
 /* Common USB Device/Host Register Offsets */
 
@@ -136,15 +120,15 @@
 
 /* Pipe Register n Register */
 
-#define SAM_USBHOST_PIPE_OFFSET(n)     (0x0100 + ((n) << 4))
+#define SAM_USBHOST_PIPE_OFFSET(n)     (0x0100 + ((n) << 5))
 
 /* The following are then relative to the pipe register n offset */
 
 #define SAM_USBHOST_PCFG_OFFSET        0x0000 /* Host Pipe Configuration Register */
 #define SAM_USBHOST_BINTERVAL_OFFSET   0x0003 /* Interval for Bulk-OUT/Ping Transaction Register */
 #define SAM_USBHOST_PSTATUSCLR_OFFSET  0x0004 /* Pipe Status Clear Register */
-#define SAM_USBHOST_PSTATUSET_OFFSET   0x0005 /* Pipe Status Set Register */
-#define SAM_USBHOST_PSTATUS_OFFSET     0x0006 /*  Pipe Status Register */
+#define SAM_USBHOST_PSTATUSSET_OFFSET  0x0005 /* Pipe Status Set Register */
+#define SAM_USBHOST_PSTATUS_OFFSET     0x0006 /* Pipe Status Register */
 #define SAM_USBHOST_PINTFLAG_OFFSET    0x0007 /* Host Pipe Interrupt Flag Register */
 #define SAM_USBHOST_PINTENCLR_OFFSET   0x0008 /* Host Pipe Interrupt Clear Register */
 #define SAM_USBHOST_PINTENSET_OFFSET   0x0009 /* Host Pipe Interrupt Set Register */
@@ -152,7 +136,7 @@
 #define SAM_USBHOST_PnCFG_OFFSET(n)       (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_PCFG_OFFSET)
 #define SAM_USBHOST_BINTERVALn_OFFSET(n)  (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_BINTERVAL_OFFSET)
 #define SAM_USBHOST_PnSTATUSCLR_OFFSET(n) (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_PSTATUSCLR_OFFSET)
-#define SAM_USBHOST_PnSTATUSET_OFFSET(n)  (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_PSTATUSET_OFFSET)
+#define SAM_USBHOST_PnSTATUSET_OFFSET(n)  (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_PSTATUSSET_OFFSET)
 #define SAM_USBHOST_PnSTATUS_OFFSET(n)    (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_PSTATUS_OFFSET)
 #define SAM_USBHOST_PnINTFLAG_OFFSET(n)   (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_PINTFLAG_OFFSET)
 #define SAM_USBHOST_PnINTENCLR_OFFSET(n)  (SAM_USBHOST_PIPE_OFFSET(n) + SAM_USBHOST_PINTENCLR_OFFSET)
@@ -167,7 +151,7 @@
 #define SAM_USBHOST_CTRLPIPE_OFFSET    0x000c /* Host control pipe (Bank 0 only) */
 #define SAM_USBHOST_STATUSPIPE_OFFSET  0x000e /* Host status pipe (Both banks) */
 
-/* USB register addresses ******************************************************************/
+/* USB register addresses */
 
 /* Common USB Device/Host Register Addresses */
 
@@ -224,13 +208,13 @@
 #define SAM_USBHOST_PCFG(n)            (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PCFG_OFFSET)
 #define SAM_USBHOST_BINTERVAL(n)       (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_BINTERVAL_OFFSET)
 #define SAM_USBHOST_PSTATUSCLR(n)      (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PSTATUSCLR_OFFSET)
-#define SAM_USBHOST_PSTATUSET(n)       (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PSTATUSET_OFFSET)
+#define SAM_USBHOST_PSTATUSSET(n)      (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PSTATUSSET_OFFSET)
 #define SAM_USBHOST_PSTATUS(n)         (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PSTATUS_OFFSET)
 #define SAM_USBHOST_PINTFLAG(n)        (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PINTFLAG_OFFSET)
 #define SAM_USBHOST_PINTENCLR(n)       (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PINTENCLR_OFFSET)
 #define SAM_USBHOST_PINTENSET(n)       (SAM_USBHOST_PIPE_BASE(n) + SAM_USBHOST_PINTENSET_OFFSET)
 
-/* USB register bit definitions ************************************************************/
+/* USB register bit definitions */
 
 /* Common USB Device/Host Register Offsets */
 
@@ -241,7 +225,7 @@
 #define USB_CTRLA_RUNSTBY              (1 << 2)  /* Bit 2:  Run in standby */
 #define USB_CTRLA_MODE                 (1 << 7)  /* Bit 7:  Operating mode */
 #  define USB_CTRLA_MODE_DEVICE        (0)       /*         0 = USB device mode */
-#   define USB_CTRLA_MODE_HOST         (1 << 7)  /*         1 = USB host mode */
+#  define USB_CTRLA_MODE_HOST          (1 << 7)  /*         1 = USB host mode */
 
 /* Synchronization Busy Register */
 
@@ -291,10 +275,8 @@
 #define USBDEV_CTRLB_UPRSM             (1 << 1)  /* Bit 1:  Upstream resume */
 #define USBDEV_CTRLB_SPDCONF_SHIFT     (2)       /* Bits 2-3: Speed configuration */
 #define USBDEV_CTRLB_SPDCONF_MASK      (3 << USBDEV_CTRLB_SPDCONF_SHIFT)
-#  define USBDEV_CTRLB_SPDCONF_FULL    (0 << USBDEV_CTRLB_SPDCONF_SHIFT) /* Full speed */
-#  define USBDEV_CTRLB_SPDCONF_LOW     (1 << USBDEV_CTRLB_SPDCONF_SHIFT) /* Low  speed */
-#  define USBDEV_CTRLB_SPDCONF_HIGH    (2 << USBDEV_CTRLB_SPDCONF_SHIFT) /* High speed capable */
-#  define USBDEV_CTRLB_SPDCONF_HIGH_TM (3 << USBDEV_CTRLB_SPDCONF_SHIFT) /* High speed Test Mode */
+#  define USBDEV_CTRLB_SPDCONF_FULL    (0 << USBDEV_CTRLB_SPDCONF_SHIFT)
+#  define USBDEV_CTRLB_SPDCONF_LOW     (1 << USBDEV_CTRLB_SPDCONF_SHIFT)
 #define USBDEV_CTRLB_NREPLY            (1 << 4)  /* Bit 4:  No reply except SETUP token */
 #define USBDEV_CTRLB_GNAK              (1 << 9)  /* Bit 9:  Global NAK */
 #define USBDEV_CTRLB_LPMHDSK_SHIFT     (10)      /* Bits 10-11: Link power management handshake */
@@ -314,8 +296,8 @@
 
 #define USBDEV_STATUS_SPEED_SHIFT      (2)       /* Bits 2-3: Speed status */
 #define USBDEV_STATUS_SPEED_MASK       (3 << USBDEV_STATUS_SPEED_SHIFT)
-#  define USBDEV_STATUS_SPEED_LOW      (0 << USBDEV_STATUS_SPEED_SHIFT) /* Low speed */
-#  define USBDEV_STATUS_SPEED_FULL     (1 << USBDEV_STATUS_SPEED_SHIFT) /* Full speed */
+#  define USBDEV_STATUS_SPEED_LOW      (0 << USBDEV_STATUS_SPEED_SHIFT)
+#  define USBDEV_STATUS_SPEED_FULL     (1 << USBDEV_STATUS_SPEED_SHIFT)
 #define USBDEV_STATUS_LNSTATE_SHIFT    (6)       /* Bits 6-7:  USB line status */
 #define USBDEV_STATUS_LNSTATE_MASK     (3 << USBDEV_STATUS_LNSTATE_SHIFT)
 #  define USBDEV_STATUS_LNSTATE_SE0    (0 << USBDEV_STATUS_LNSTATE_SHIFT) /* SE0/RESET */
@@ -330,8 +312,9 @@
 #define USBDEV_FNUM_MASK               (0x7ff << USBDEV_FNUM_SHIFT)
 #define USBDEV_FNUM_FNCERR             (1 << 15) /* Bit 15: Frame number CRC error */
 
-/* Common definitions for Device Interrupt Enable Clear Register, Device interrupt
- * Enable Set Register, and Device Interrupt Flag Status and Clear Register.
+/* Common definitions for Device Interrupt Enable Clear Register,
+ * Device interrupt, Enable Set Register,
+ * and Device Interrupt Flag Status and Clear Register.
  */
 
 #define USBDEV_INT_SUSPEND             (1 << 0)  /* Bit 0:  Suspend interrupt */
@@ -358,7 +341,7 @@
 #  define USBDEV_EPCCFG_EPTYPE0_BULKOUT  (3 << USBDEV_EPCFG_EPTYPE0_SHIFT) /* Bank 0 bulk OUT */
 #  define USBDEV_EPCCFG_EPTYPE0_INTOUT   (4 << USBDEV_EPCFG_EPTYPE0_SHIFT) /* Bank 0 interrupt OUT */
 #  define USBDEV_EPCCFG_EPTYPE0_DBIN     (5 << USBDEV_EPCFG_EPTYPE0_SHIFT) /* Bank 0 dual bank IN */
-#define USBDEV_EPCFG_EPTYPE1_SHIFT       (4)       /* Bits 4-6: Endpoint type for IN direction */
+#define USBDEV_EPCFG_EPTYPE1_SHIFT       (4)                               /* Bits 4-6: Endpoint type for IN direction */
 #define USBDEV_EPCFG_EPTYPE1_MASK        (7 << USBDEV_EPCFG_EPTYPE1_SHIFT)
 #  define USBDEV_EPCCFG_EPTYPE1_DISABLED (0 << USBDEV_EPCFG_EPTYPE1_SHIFT) /* Bank 1 disabled */
 #  define USBDEV_EPCCFG_EPTYPE1_CTRLIN   (1 << USBDEV_EPCFG_EPTYPE1_SHIFT) /* Bank 1 control IN */
@@ -379,11 +362,13 @@
 #define USBDEV_EPSTATUS_BK0RDY         (1 << 6)  /* Bit 6:  Bank 0 ready */
 #define USBDEV_EPSTATUS_BK1RDY         (1 << 7)  /* Bit 7:  Bank 1 ready */
 
-/* Common definitions for Device Endpoint Interrupt Flag Register, Device Endpoint
- * Interrupt Enable Register, and Device Endpoint Interrupt Set Register
+/* Common definitions for Device Endpoint Interrupt Flag Register,
+ * Device Endpoint, Interrupt Enable Register,
+ * and Device Endpoint Interrupt Set Register.
  *
- * REVISIT: Datasheet shows only one bit for TRCPT, TRFAIL, and STALL.  But text
- * (and code) use two bits, one for IN and one for OUT.  Both can't be true.
+ * REVISIT: Datasheet shows only one bit for TRCPT, TRFAIL, and STALL.
+ * But text (and code) use two bits, one for IN and one for OUT.
+ * Both can't be true.
  */
 
 #define USBDEV_EPINT_TRCPT0            (1 << 0)  /* Bit 0:  Transmit complete 0 interrupt */
@@ -416,7 +401,7 @@
 #  define USBDEV_PKTSIZE_SIZE_256B     (5 << USBDEV_PKTSIZE_SIZE_SHIFT) /* 256 bytes (isoc only) */
 #  define USBDEV_PKTSIZE_SIZE_512B     (6 << USBDEV_PKTSIZE_SIZE_SHIFT) /* 512 bytes (isoc only) */
 #  define USBDEV_PKTSIZE_SIZE_1023B    (7 << USBDEV_PKTSIZE_SIZE_SHIFT) /* 1023 bytes (isoc only) */
-#define USBDEV_PKTSIZE_AUTOZLP         (1 << 31) /* Bit 31: Automatic zero length packet */
+#define USBDEV_PKTSIZE_AUTOZLP         (1 << 31)                        /* Bit 31: Automatic zero length packet */
 
 /* Extended Register (Bank 0 only) */
 
@@ -440,10 +425,10 @@
 #define USBHOST_CTRLB_SPDCONF_SHIFT    (2)       /* Bits 2-3: Host speed configuration */
 #define USBHOST_CTRLB_SPDCONF_MASK     (3 << USBHOST_CTRLB_SPDCONF_SHIFT)
 #  define USBHOST_CTRLB_SPDCONF_LF     (0 << USBHOST_CTRLB_SPDCONF_SHIFT) /* Low and full capable */
-#define USBHOST_CTRLB_SOFE             (1 << 8)  /* Bit 8:  Start of frame generation enable */
-#define USBHOST_CTRLB_BUSRESET         (1 << 9)  /* Bit 9:  Send USB reset */
-#define USBHOST_CTRLB_VBUSOK           (1 << 10) /* Bit 10: VBUS is OK */
-#define USBHOST_CTRLB_L1RESUME         (1 << 11) /* Bit 11: Send USB L1 resume */
+#define USBHOST_CTRLB_SOFE             (1 << 8)                           /* Bit 8:  Start of frame generation enable */
+#define USBHOST_CTRLB_BUSRESET         (1 << 9)                           /* Bit 9:  Send USB reset */
+#define USBHOST_CTRLB_VBUSOK           (1 << 10)                          /* Bit 10: VBUS is OK */
+#define USBHOST_CTRLB_L1RESUME         (1 << 11)                          /* Bit 11: Send USB L1 resume */
 
 /* Host Start-of-Frame Control Register */
 
@@ -456,9 +441,9 @@
 
 #define USBHOST_STATUS_SPEED_SHIFT     (2)       /* Bits 2-3: Speed status */
 #define USBHOST_STATUS_SPEED_MASK      (3 << USBHOST_STATUS_SPEED_SHIFT)
-#  define USBHOST_STATUS_SPEED_LOW     (0 << USBHOST_STATUS_SPEED_SHIFT) /* Full speed mode */
-#  define USBHOST_STATUS_SPEED_FULL    (2 << USBHOST_STATUS_SPEED_SHIFT) /* Low speed mode */
-#define USBHOST_STATUS_LNSTATE_SHIFT   (6)       /* Bits 6-7:  USB line status */
+#  define USBHOST_STATUS_SPEED_FULL    (0 << USBHOST_STATUS_SPEED_SHIFT) /* Full speed mode */
+#  define USBHOST_STATUS_SPEED_LOW     (1 << USBHOST_STATUS_SPEED_SHIFT) /* Low speed mode */
+#define USBHOST_STATUS_LNSTATE_SHIFT   (6)                               /* Bits 6-7:  USB line status */
 #define USBHOST_STATUS_LNSTATE_MASK    (3 << USBHOST_STATUS_LNSTATE_SHIFT)
 #  define USBHOST_STATUS_LNSTATE_SE0   (0 << USBHOST_STATUS_LNSTATE_SHIFT) /* SE0/RESET */
 #  define USBHOST_STATUS_LNSTATE_FJLK  (1 << USBHOST_STATUS_LNSTATE_SHIFT) /* FS-J or LS-K */
@@ -471,8 +456,9 @@
 
 /* Host Frame Length Register (8-bit data) */
 
-/* Common definitions for Host Interrupt Enable Clear Register, Host Interrupt Enable
- * Set Register, and Host Interrupt Flag Status and Clear Register
+/* Common definitions for Host Interrupt Enable Clear Register,
+ * Host Interrupt Enable Set Register, and Host Interrupt Flag Status
+ * and Clear Register.
  */
 
 #define USBHOST_INT_HSOF               (1 << 2)  /* Bit 2:  Host start of frame interrupt */
@@ -500,6 +486,7 @@
   #define USBHOST_PCFG_BK_DUAL         (1 << 2)  /*         1=Dual bank endpoint */
 #define USBHOST_PCFG_PTYPE_SHIFT       (3)       /* Bits 3-5:  Type of pipe */
 #define USBHOST_PCFG_PTYPE_MASK        (7 << USBHOST_PCFG_PTYPE_SHIFT)
+#  define USBHOST_PCFG_PTYPE(n)        ((uint8_t)(n) << USBHOST_PCFG_PTYPE_SHIFT)
 #  define USBHOST_PCFG_PTYPE_DISABLED  (0 << USBHOST_PCFG_PTYPE_SHIFT) /* Disabled */
 #  define USBHOST_PCFG_PTYPE_CTRL      (1 << USBHOST_PCFG_PTYPE_SHIFT) /* Control pipe */
 #  define USBHOST_PCFG_PTYPE_ISOC      (2 << USBHOST_PCFG_PTYPE_SHIFT) /* Isochronous pipe */
@@ -509,8 +496,8 @@
 
 /* Interval for Bulk-OUT/Ping Transaction Register (8-bit data) */
 
-/* Common definitions for Pipe Status Clear Register, Pipe Status Set Register, and
- * Pipe Status Register
+/* Common definitions for Pipe Status Clear Register,
+ * Pipe Status Set Register, and Pipe Status Register
  */
 
 #define USBHOST_PSTATUS_DTGL           (1 << 0)  /* Bit 0:  Data toggle sequence */
@@ -519,10 +506,12 @@
 #define USBHOST_PSTATUS_BK0RDY         (1 << 6)  /* Bit 6:  Bank 0 ready */
 #define USBHOST_PSTATUS_BK1RDY         (1 << 7)  /* Bit 7:  Bank 1 ready */
 
-/* Common definitions for Host Pipe Interrupt Flag Register, Host Pipe Interrupt Clear
- * Register, and Host Pipe Interrupt Set Register
+/* Common definitions for Host Pipe Interrupt Flag Register,
+ * Host Pipe Interrupt Clear Register,
+ * and Host Pipe Interrupt Set Register
  *
- * REVISIT: Datasheet shows only one bit for TRCPT.  But text (and code) use two
+ * REVISIT: Datasheet shows only one bit for TRCPT.
+ * But text (and code) use two
  * bits, one for IN and one for OUT.  Both can't be true.
  */
 
@@ -539,14 +528,15 @@
 
 /* Packet size (Both banks) */
 
-#define USBHOST_PKTSIZE_BCNT_SHIFT     (8)       /* Bits 8-13: Byte count */
-#define USBHOST_PKTSIZE_BCNT_MASK      (0x3f << USBHOST_PKTSIZE_BCNT_SHIFT)
+#define USBHOST_PKTSIZE_BCNT_SHIFT     (0)       /* Bits 0-13: Byte count */
+#define USBHOST_PKTSIZE_BCNT_MASK      (0x3fff << USBHOST_PKTSIZE_BCNT_SHIFT)
 #  define USBHOST_PKTSIZE_BCNT(n)      ((uint32_t)(n) << USBHOST_PKTSIZE_BCNT_SHIFT)
 #define USBHOST_PKTSIZE_MPKTSIZE_SHIFT (14)      /* Bits 14-27:  Multi-packet IN/OUT size */
 #define USBHOST_PKTSIZE_MPKTSIZE_MASK  (0x3fff << USBHOST_PKTSIZE_MPKTSIZE_SHIFT)
 #  define USBHOST_PKTSIZE_MPKTSIZE(n)  ((uint32_t)(n) << USBHOST_PKTSIZE_MPKTSIZE_SHIFT)
 #define USBHOST_PKTSIZE_SIZE_SHIFT     (28)      /* Bits 28-30:  Pipe size */
 #define USBHOST_PKTSIZE_SIZE_MASK      (7 << USBHOST_PKTSIZE_SIZE_SHIFT)
+#  define USBHOST_PKTSIZE_SIZE(n)      ((uint8_t)(n) << USBHOST_PKTSIZE_SIZE_SHIFT)
 #  define USBHOST_PKTSIZE_SIZE_8B      (0 << USBHOST_PKTSIZE_SIZE_SHIFT) /* 8 bytes */
 #  define USBHOST_PKTSIZE_SIZE_16B     (1 << USBHOST_PKTSIZE_SIZE_SHIFT) /* 16 bytes */
 #  define USBHOST_PKTSIZE_SIZE_32B     (2 << USBHOST_PKTSIZE_SIZE_SHIFT) /* 32 bytes */
@@ -555,7 +545,7 @@
 #  define USBHOST_PKTSIZE_SIZE_256B    (5 << USBHOST_PKTSIZE_SIZE_SHIFT) /* 256 bytes (isoc only) */
 #  define USBHOST_PKTSIZE_SIZE_512B    (6 << USBHOST_PKTSIZE_SIZE_SHIFT) /* 512 bytes (isoc only) */
 #  define USBHOST_PKTSIZE_SIZE_1023B   (7 << USBHOST_PKTSIZE_SIZE_SHIFT) /* 1023 bytes (isoc only) */
-#define USBHOST_PKTSIZE_AUTOZLP        (1 << 31) /* Bit 31: Automatic zero length packet */
+#define USBHOST_PKTSIZE_AUTOZLP        (1 << 31)                         /* Bit 31: Automatic zero length packet */
 
 /* Extended register (Bank 0 only) */
 
@@ -577,8 +567,8 @@
 #define USBHOST_CTRLPIPE_PDADDR_MASK   (0x7f << USBHOST_CTRLPIPE_PDADDR_SHIFT)
 #  define USBHOST_CTRLPIPE_PDADDR(n)   ((uint16_t)(n) << USBHOST_CTRLPIPE_PDADDR_SHIFT)
 #define USBHOST_CTRLPIPE_PEPNUM_SHIFT  (8)       /* Bits 8-11:  Pipe endpoint number */
-#define USBHOST_CTRLPIPE_PEPNUM_MASK   (15 << USBHOST_CTRLPIPE_PEPNUM_SHIFTxx)
-#  define USBHOST_CTRLPIPE_PEPNUM(n)   ((uint16_t)(n) << USBHOST_CTRLPIPE_PEPNUM_SHIFTxx)
+#define USBHOST_CTRLPIPE_PEPNUM_MASK   (15 << USBHOST_CTRLPIPE_PEPNUM_SHIFT)
+#  define USBHOST_CTRLPIPE_PEPNUM(n)   ((uint16_t)(n) << USBHOST_CTRLPIPE_PEPNUM_SHIFT)
 #define USBHOST_CTRLPIPE_PEPMAX_SHIFT  (12)      /* Bitx 12-15:  Pipe error max number */
 #define USBHOST_CTRLPIPE_PEPMAX_MASK   (15 << USBHOST_CTRLPIPE_PEPMAX_SHIFT)
 #  define USBHOST_CTRLPIPE_PEPMAX(n)   ((uint16_t)(n) << USBHOST_CTRLPIPE_PEPMAX_SHIFT)
@@ -594,9 +584,9 @@
 #define USBHOST_STATUSPIPE_ERCNT_MASK  (7 << USBHOST_STATUSPIPE_ERCNT_SHIFT)
 #  define USBHOST_STATUSPIPE_ERCNT(n)  ((uint16_t)(n) << USBHOST_STATUSPIPE_ERCNT_SHIFT)
 
-/********************************************************************************************
+/****************************************************************************
  * Public Types
- ********************************************************************************************/
+ ****************************************************************************/
 
 /* Device Endpoint Descriptor.  See USBDEV_* bit definitions above. */
 
@@ -622,12 +612,12 @@ struct usbhost_pipedesc_s
   uint16_t statuspipe;  /* 0x000e-0x000f: Host status pipe (Both banks) */
 };
 
-/********************************************************************************************
+/****************************************************************************
  * Public Data
- ********************************************************************************************/
+ ****************************************************************************/
 
-/********************************************************************************************
- * Public Functions
- ********************************************************************************************/
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
 
 #endif /* __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_USB_H */
diff --git a/arch/arm/src/samd5e5/sam_i2c_master.c b/arch/arm/src/samd5e5/sam_i2c_master.c
index 2c33e87..b0a1fdc 100644
--- a/arch/arm/src/samd5e5/sam_i2c_master.c
+++ b/arch/arm/src/samd5e5/sam_i2c_master.c
@@ -3,9 +3,12 @@
  *
  *   Copyright (C) 2013-2014, 2018 Gregory Nutt. All rights reserved.
  *   Copyright (C) 2015 Filament - www.filament.com
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
  *   Author: Matt Thompson <mt...@hexwave.com>
  *   Author: Alan Carvalho de Assis <ac...@gmail.com>
  *   Author: Gregory Nutt <gn...@nuttx.org>
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -165,7 +168,7 @@ struct sam_i2c_dev_s
 
   /* Debug stuff */
 
-#ifdef CONFIG_SAM_I2C_REGDEBUG
+#ifdef CONFIG_SAMD5E5_I2C_REGDEBUG
   bool wrlast;                /* Last was a write */
   uint32_t addrlast;          /* Last address */
   uint32_t vallast;           /* Last value */
@@ -189,11 +192,10 @@ static uint32_t i2c_getreg32(struct sam_i2c_dev_s *priv, unsigned int offset);
 static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval,
                          unsigned int offset);
 
-static int i2c_takesem(sem_t * sem);
-static int i2c_takesem_noncancelable(sem_t * sem);
+static void i2c_takesem(sem_t * sem);
 #define i2c_givesem(sem) (nxsem_post(sem))
 
-#ifdef CONFIG_SAM_I2C_REGDEBUG
+#ifdef CONFIG_SAMD5E5_I2C_REGDEBUG
 static bool i2c_checkreg(struct sam_i2c_dev_s *priv, bool wr,
                          uint32_t value, uintptr_t address);
 static uint32_t i2c_getabs(struct sam_i2c_dev_s *priv, uintptr_t address);
@@ -241,7 +243,7 @@ static const struct i2c_attr_s g_i2c0attr =
 {
   .i2c       = 0,
   .sercom    = 0,
-  .irq       = SAM_IRQ_SERCOM0,
+  .irq       = SAM_IRQ_SERCOM0_0,
   .coregen   = BOARD_SERCOM0_GCLKGEN,
   .slowgen   = BOARD_SERCOM0_SLOW_GCLKGEN,
   .pad0      = BOARD_SERCOM0_PINMAP_PAD0,
@@ -259,7 +261,7 @@ static const struct i2c_attr_s g_i2c1attr =
 {
   .i2c       = 1,
   .sercom    = 1,
-  .irq       = SAM_IRQ_SERCOM1,
+  .irq       = SAM_IRQ_SERCOM1_0,
   .coregen   = BOARD_SERCOM1_GCLKGEN,
   .slowgen   = BOARD_SERCOM1_SLOW_GCLKGEN,
   .pad0      = BOARD_SERCOM1_PINMAP_PAD0,
@@ -277,7 +279,7 @@ static const struct i2c_attr_s g_i2c2attr =
 {
   .i2c       = 2,
   .sercom    = 2,
-  .irq       = SAM_IRQ_SERCOM2,
+  .irq       = SAM_IRQ_SERCOM2_0,
   .coregen   = BOARD_SERCOM2_GCLKGEN,
   .slowgen   = BOARD_SERCOM2_SLOW_GCLKGEN,
   .pad0      = BOARD_SERCOM2_PINMAP_PAD0,
@@ -295,7 +297,7 @@ static const struct i2c_attr_s g_i2c3attr =
 {
   .i2c       = 3,
   .sercom    = 3,
-  .irq       = SAM_IRQ_SERCOM3,
+  .irq       = SAM_IRQ_SERCOM3_0, /* !!! SAM_IRQ_SERCOM3 */
   .coregen   = BOARD_SERCOM3_GCLKGEN,
   .slowgen   = BOARD_SERCOM3_SLOW_GCLKGEN,
   .pad0      = BOARD_SERCOM3_PINMAP_PAD0,
@@ -313,7 +315,7 @@ static const struct i2c_attr_s g_i2c4attr =
 {
   .i2c       = 4,
   .sercom    = 4,
-  .irq       = SAM_IRQ_SERCOM4,
+  .irq       = SAM_IRQ_SERCOM4_0,
   .coregen   = BOARD_SERCOM4_GCLKGEN,
   .slowgen   = BOARD_SERCOM4_SLOW_GCLKGEN,
   .pad0      = BOARD_SERCOM4_PINMAP_PAD0,
@@ -331,7 +333,7 @@ static const struct i2c_attr_s g_i2c5attr =
 {
   .i2c       = 5,
   .sercom    = 5,
-  .irq       = SAM_IRQ_SERCOM5,
+  .irq       = SAM_IRQ_SERCOM5_0, /* !!! SAM_IRQ_SERCOM5 */
   .coregen   = BOARD_SERCOM5_GCLKGEN,
   .slowgen   = BOARD_SERCOM5_SLOW_GCLKGEN,
   .pad0      = BOARD_SERCOM5_PINMAP_PAD0,
@@ -487,29 +489,23 @@ static void i2c_putreg32(struct sam_i2c_dev_s *priv, uint32_t regval,
  *
  *******************************************************************************/
 
-static int i2c_takesem(sem_t *sem)
+static void i2c_takesem(sem_t *sem)
 {
-  return nxsem_wait(sem);
-}
+  int ret;
 
-/*******************************************************************************
- * Name: i2c_takesem_noncancelable
- *
- * Description:
- *   Take the wait semaphore (handling false alarm wake-ups due to the receipt
- *   of signals).
- *
- * Input Parameters:
- *   dev - Instance of the SDIO device driver state structure.
- *
- * Returned Value:
- *   None
- *
- *******************************************************************************/
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
 
-static int i2c_takesem_noncancelable(sem_t *sem)
-{
-  return nxsem_wait_uninterruptible(sem);
+      ret = nxsem_wait(sem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
 }
 
 /*******************************************************************************
@@ -528,7 +524,7 @@ static int i2c_takesem_noncancelable(sem_t *sem)
  *
  *******************************************************************************/
 
-#ifdef CONFIG_SAM_I2C_REGDEBUG
+#ifdef CONFIG_SAMD5E5_I2C_REGDEBUG
 static bool i2c_checkreg(struct sam_i2c_dev_s *priv, bool wr, uint32_t value,
                          uint32_t address)
 {
@@ -574,7 +570,7 @@ static bool i2c_checkreg(struct sam_i2c_dev_s *priv, bool wr, uint32_t value,
  *
  *******************************************************************************/
 
-#ifdef CONFIG_SAM_I2C_REGDEBUG
+#ifdef CONFIG_SAMD5E5_I2C_REGDEBUG
 static uint32_t i2c_getabs(struct sam_i2c_dev_s *priv, uintptr_t address)
 {
   uint32_t value = getreg32(address);
@@ -596,7 +592,7 @@ static uint32_t i2c_getabs(struct sam_i2c_dev_s *priv, uintptr_t address)
  *
  *******************************************************************************/
 
-#ifdef CONFIG_SAM_I2C_REGDEBUG
+#ifdef CONFIG_SAMD5E5_I2C_REGDEBUG
 static void i2c_putabs(struct sam_i2c_dev_s *priv, uintptr_t address,
                        uint32_t value)
 {
@@ -658,9 +654,18 @@ static int i2c_wait_for_bus(struct sam_i2c_dev_s *priv, unsigned int size)
 {
   struct timespec ts;
   int ret;
+  long usec;
 
   clock_gettime(CLOCK_REALTIME, &ts);
-  ts.tv_nsec += 200e3;
+
+  usec = size * I2C_TIMEOUT_MSPB + ts.tv_nsec / 1000;
+  while (usec > USEC_PER_SEC)
+    {
+      ts.tv_sec += 1;
+      usec      -= USEC_PER_SEC;
+    }
+
+  ts.tv_nsec = usec * 1000;
 
   ret = nxsem_timedwait(&priv->waitsem, (const struct timespec *)&ts);
   if (ret < 0)
@@ -781,6 +786,7 @@ static int i2c_interrupt(int irq, FAR void *context, FAR void *arg)
 
   if ((i2c_getreg8(priv, SAM_I2C_INTFLAG_OFFSET) & I2C_INT_MB) == I2C_INT_MB)
     {
+      i2cinfo("I2C INT MB!\n");
       /* If no device responded to the address packet, STATUS.RXNACK will be
        * set
        */
@@ -869,6 +875,7 @@ static void i2c_startread(struct sam_i2c_dev_s *priv, struct i2c_msg_s *msg)
 
   /* Set the ADDR register */
 
+  i2cinfo("readaddr=%x\n", regval);
   i2c_putreg32(priv, regval, SAM_I2C_ADDR_OFFSET);
   i2c_wait_synchronization(priv);
 }
@@ -924,10 +931,12 @@ static void i2c_startwrite(struct sam_i2c_dev_s *priv, struct i2c_msg_s *msg)
 
   if ((msg->flags & I2C_M_NOSTART) == 0)
     {
+      i2cinfo("writeaddr=%x\n", regval);
       i2c_putreg32(priv, regval, SAM_I2C_ADDR_OFFSET);
     }
   else
     {
+      i2cinfo("data=%x\n", msg->buffer[priv->xfrd]);
       i2c_putreg8(priv, msg->buffer[priv->xfrd++], SAM_I2C_DATA_OFFSET);
     }
 
@@ -946,10 +955,12 @@ static void i2c_startmessage(struct sam_i2c_dev_s *priv, struct i2c_msg_s *msg)
 {
   if ((msg->flags & I2C_M_READ) != 0)
     {
+      i2cinfo("startread\n");
       i2c_startread(priv, msg);
     }
   else
     {
+      i2cinfo("startwrite\n");
       i2c_startwrite(priv, msg);
     }
 }
@@ -977,7 +988,7 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev,
   irqstate_t flags;
   unsigned int size;
   int i;
-  int ret;
+  int ret = -EBUSY;
 
   DEBUGASSERT(dev != NULL && msgs != NULL && count > 0);
 
@@ -985,8 +996,10 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev,
 
   if (count)
     {
+      i2cinfo("msgs->frequency=%d\n", msgs->frequency);
       if (priv->frequency != msgs->frequency)
         {
+          i2cinfo("priv->frequency=%d\n", priv->frequency);
           sam_i2c_setfrequency(priv, msgs->frequency);
           priv->frequency = msgs->frequency;
         }
@@ -1006,21 +1019,16 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev,
 
   /* Get exclusive access to the device */
 
-  ret = i2c_takesem(&priv->exclsem);
-  if (ret < 0)
-    {
-      return ret;
-    }
+  i2c_takesem(&priv->exclsem);
 
   /* Initiate the message transfer */
 
-  ret = -EBUSY;
-
   /* Initiate the transfer.  The rest will be handled from interrupt logic.
    * Interrupts must be disabled to prevent re-entrance from the interrupt
    * level.
    */
 
+  i2cinfo("count=%d\n", count);
   while (count--)
     {
       priv->msg = msgs;
@@ -1035,13 +1043,6 @@ static int sam_i2c_transfer(FAR struct i2c_master_s *dev,
       ret = i2c_wait_for_bus(priv, msgs->length);
       if (ret < 0)
         {
-#if 0
-          i2cerr("ERROR: Transfer failed: %d\n", ret);
-          i2cinfo("STATUS: 0x%08x\n",
-                  i2c_getreg16(priv, SAM_I2C_STATUS_OFFSET));
-          i2cinfo("INTFLAG: 0x%02x\n",
-                  i2c_getreg8(priv, SAM_I2C_INTFLAG_OFFSET));
-#endif
           leave_critical_section(flags);
           i2c_givesem(&priv->exclsem);
           return ret;
@@ -1078,6 +1079,8 @@ static uint32_t sam_i2c_setfrequency(struct sam_i2c_dev_s *priv,
   uint32_t baud_hs = 0;
   uint32_t ctrla;
 
+  i2cinfo("sercom=%d frequency=%d\n", priv->attr->sercom, frequency);
+
   /* Check if the configured BAUD is within the valid range */
 
   maxfreq = (priv->attr->srcfreq >> 1);
@@ -1210,7 +1213,7 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
 
   i2c_pad_configure(priv);
 
-  ctrla = I2C_CTRLA_MODE_MASTER | I2C_CTRLA_RUNSTDBY | I2C_CTRLA_SPEED_FAST |
+  ctrla = I2C_CTRLA_MODE_MASTER | I2C_CTRLA_RUNSTDBY | I2C_CTRLA_SPEED_STD |
           I2C_CTRLA_SDAHOLD_450NS | priv->attr->muxconfig;
   i2c_putreg32(priv, ctrla, SAM_I2C_CTRLA_OFFSET);
   i2c_wait_synchronization(priv);
@@ -1219,7 +1222,11 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
 
   i2c_putreg32(priv, I2C_CTRLB_SMEN, SAM_I2C_CTRLB_OFFSET);
 
-  /* Set an initial baud value. */
+  /* 8bit Mode */
+
+  i2c_putreg32(priv, I2C_CTRLC_DATA32B_8BIT, SAM_I2C_CTRLC_OFFSET);
+
+  /* Set an initial baud value */
 
   sam_i2c_setfrequency(priv, 100000);
 
@@ -1241,6 +1248,7 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
   /* Enable SERCOM interrupts at the NVIC */
 
   up_enable_irq(priv->attr->irq);
+  up_enable_irq(priv->attr->irq + 1);
   leave_critical_section(flags);
 }
 
@@ -1430,6 +1438,14 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus)
       return NULL;
     }
 
+  ret = irq_attach(priv->attr->irq + 1, i2c_interrupt, priv);
+  if (ret < 0)
+    {
+      i2cerr("ERROR: Failed to attach irq %d\n", priv->attr->irq);
+      leave_critical_section(flags);
+      return NULL;
+    }
+
   /* Initialize the I2C driver structure */
 
   priv->dev.ops = &g_i2cops;
@@ -1462,6 +1478,7 @@ int sam_i2c_uninitialize(FAR struct i2c_master_s *dev)
   /* Disable I2C interrupts */
 
   up_disable_irq(priv->attr->irq);
+  up_disable_irq(priv->attr->irq + 1);
 
   /* Reset data structures */
 
@@ -1492,15 +1509,12 @@ int sam_i2c_reset(FAR struct i2c_master_s *dev)
 
   /* Get exclusive access to the I2C device */
 
-  ret = i2c_takesem_noncancelable(&priv->exclsem);
-  if (ret < 0)
-    {
-      return ret;
-    }
+  i2c_takesem(&priv->exclsem);
 
   /* Disable I2C interrupts */
 
   up_disable_irq(priv->attr->irq);
+  up_disable_irq(priv->attr->irq + 1);
 
   /* Disable I2C */
 
diff --git a/arch/arm/src/samd5e5/sam_i2c_master.h b/arch/arm/src/samd5e5/sam_i2c_master.h
new file mode 100644
index 0000000..d4eacda
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_i2c_master.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_i2c_master.h
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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_SAMD5E5_SAM_I2C_MASTER_H
+#define __ARCH_ARM_SRC_SAMD5E5_SAM_I2C_MASTER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include "sam_config.h"
+
+#if defined(CONFIG_ARCH_FAMILY_SAMD5X) || defined(CONFIG_ARCH_FAMILY_SAMD51)
+#  include "hardware/sam_i2c_master.h"
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_i2c_master_initialize
+ *
+ * Description:
+ *   Initialize a I2C device for I2C operation
+ *
+ ****************************************************************************/
+
+struct i2c_master_s;  /* Forward reference */
+struct i2c_master_s *sam_i2c_master_initialize(int bus);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_ARM_SRC_SAMD5E5_SAM_I2C_MASTER_H */
diff --git a/arch/arm/src/samd5e5/sam_usb.c b/arch/arm/src/samd5e5/sam_usb.c
index 37e0368..bb48b00 100644
--- a/arch/arm/src/samd5e5/sam_usb.c
+++ b/arch/arm/src/samd5e5/sam_usb.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * arch/arm/src/samd5e5/sam_usb.h
+ * arch/arm/src/samd5e5/sam_usb.c
  *
  *   Copyright (C) 2015 Filament - www.filament.com
  *   Copyright (C) 2015 Offcode Ltd. All rights reserved.
@@ -8,6 +8,10 @@
  *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gn...@nuttx.org> (SAMD5E5 port)
  *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -100,10 +104,14 @@
 #include <nuttx/usb/usbdev.h>
 #include <nuttx/usb/usbdev_trace.h>
 
+#include <nuttx/usb/usbhost.h>
+#include <nuttx/usb/usbhost_devaddr.h>
+#include <nuttx/usb/usbhost_trace.h>
+
 #include <arch/board/board.h>
 
-#include "arm_arch.h"
 #include "arm_internal.h"
+#include "arm_arch.h"
 
 #include "chip.h"
 #include "hardware/sam_pinmap.h"
@@ -112,12 +120,9 @@
 #include "sam_port.h"
 #include "sam_periphclks.h"
 #include "sam_usb.h"
+#include "sam_usbhost.h"
 
-#if defined(CONFIG_USBHOST) && defined(CONFIG_SAMD5E5_USB)
-#  error USBHOST mode not yet implemented!
-#endif
-
-#if defined(CONFIG_USBDEV) && defined(CONFIG_SAMD5E5_USB)
+#if defined(CONFIG_SAMD5E5_USB)
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -125,6 +130,10 @@
 
 /* Configuration ************************************************************/
 
+#ifndef CONFIG_USB_EP0_DEFSIZE
+#  define CONFIG_USB_EP0_DEFSIZE 8
+#endif
+
 #ifndef CONFIG_USBDEV_EP0_MAXSIZE
 #  define CONFIG_USBDEV_EP0_MAXSIZE 64
 #endif
@@ -145,6 +154,20 @@
 #define SAM_EP_BIT(ep)      (1 << (ep))
 #define SAM_EP0_MAXPACKET   (CONFIG_USBDEV_EP0_MAXSIZE) /* EP0 Max. packet size */
 #define SAM_MAX_MULTIPACKET_SIZE  (0x3fff)
+#define SAM_RETRY_COUNT     3   /* Number of ctrl transfer retries */
+
+/* Delays */
+
+#define SAM_SETUP_DELAY         SEC2TICK(5) /* 5 seconds in system ticks */
+#define SAM_DATANAK_DELAY       SEC2TICK(5) /* 5 seconds in system ticks */
+#define USB_CTRL_DPKT_TIMEOUT (500)         /* Timeout between control data packets : 500ms */
+#define USB_CTRL_STAT_TIMEOUT (50)          /* Timeout of status packet : 50ms */
+
+/* Maximum size of a descriptor */
+
+#ifndef CONFIG_SAM_DESCSIZE
+#  define CONFIG_SAM_DESCSIZE 128
+#endif
 
 /* Request queue operations *************************************************/
 
@@ -230,6 +253,8 @@
 #define SAM_TRACEINTID_EPINTEN            0x0029
 #define SAM_TRACEINTID_EP0WRSTATUS        0x002a
 #define SAM_TRACEINTID_EPTRCPT0_LEN       0x002b
+#define SAM_TRACEINTID_PENDING_PIPE       0x002c
+#define SAM_TRACEINTID_PIPENO             0x002d
 
 /* Ever-present MIN and MAX macros */
 
@@ -255,20 +280,18 @@
  * Private Type Definitions
  ****************************************************************************/
 
+#ifdef CONFIG_USBDEV
+
 /* State of an endpoint */
 
 enum sam_epstate_e
 {
-  /* --- All Endpoints --- */
-
   USB_EPSTATE_DISABLED = 0, /* Endpoint is disabled */
   USB_EPSTATE_STALLED,      /* Endpoint is stalled */
   USB_EPSTATE_IDLE,         /* Endpoint is idle (i.e. ready for transmission) */
   USB_EPSTATE_SENDING,      /* Endpoint is sending data */
   USB_EPSTATE_RXSTOPPED,    /* OUT endpoint is stopped waiting for a read request */
-
-  /* --- Endpoint 0 Only --- */
-
+                            /* --- Endpoint 0 Only --- */
   USB_EPSTATE_EP0DATAOUT,   /* Endpoint 0 is receiving SETUP OUT data */
   USB_EPSTATE_EP0STATUSIN,  /* Endpoint 0 is sending SETUP status */
   USB_EPSTATE_EP0ADDRESS    /* Address change is pending completion of status */
@@ -369,11 +392,13 @@ struct sam_usbdev_s
 
   /* The endpoint list */
 
-  struct sam_ep_s eplist[SAM_USB_NENDPOINTS];
+  __attribute__((__aligned__(4))) struct sam_ep_s eplist[SAM_USB_NENDPOINTS];
 
   /* Endpoint descriptors 2 banks for each endpoint */
 
-  struct usbdev_epdesc_s ep_descriptors[SAM_USB_NENDPOINTS * 2];
+  __attribute__((__aligned__(4)))
+  struct usbdev_epdesc_s ep_descriptors[SAM_USB_NENDPOINTS *
+                                        SAM_USB_NBANKS()];
 
   /* EP0 data buffer.  For data that is included in an EP0 SETUP OUT
    * transaction.  In this case, no request is in place from the class
@@ -383,14 +408,317 @@ struct sam_usbdev_s
    * used and the class driver provides the buffering.
    */
 
-  uint8_t ep0out[SAM_EP0_MAXPACKET];
+  __attribute__((__aligned__(4))) uint8_t ep0out[SAM_EP0_MAXPACKET];
+};
+#endif
+
+#ifdef CONFIG_USBHOST
+/* The overall state of the device */
+
+enum sam_hoststate_e
+{
+  USB_HOSTSTATE_SUSPENDED = 0, /* The device is currently suspended */
+  USB_HOSTSTATE_POWERED,       /* Host is providing +5V through the USB cable */
+  USB_HOSTSTATE_DEFAULT,       /* Device has been reset */
+  USB_HOSTSTATE_ADDRESSED,     /* The device has been given an address on the bus */
+  USB_HOSTSTATE_CONFIGURED     /* A valid configuration has been selected. */
+};
+
+/**
+ * @brief      USB HCD pipe states
+ */
+
+enum usb_h_pipe_state
+{
+  USB_H_PIPE_S_FREE = 0x00,  /** Pipe is free to allocate */
+  USB_H_PIPE_S_CFG = 0x01,   /** Pipe is in configuration */
+  USB_H_PIPE_S_IDLE = 0x02,  /** Pipe is allocated and idle */
+  USB_H_PIPE_S_SETUP = 0x03, /** Pipe in control setup stage */
+  USB_H_PIPE_S_DATI = 0x05,  /** Pipe in data IN stage */
+  USB_H_PIPE_S_DATO = 0x06,  /** Pipe in data OUT stage */
+  USB_H_PIPE_S_ZLPI = 0x07,  /** Pipe in data IN ZLP stage */
+  USB_H_PIPE_S_ZLPO = 0x08,  /** Pipe in data OUT ZLP stage */
+  USB_H_PIPE_S_STATI = 0x09, /** Pipe in control status IN stage */
+  USB_H_PIPE_S_STATO = 0x0a, /** Pipe in control status OUT stage */
+  USB_H_PIPE_S_TAKEN = 0x10  /** Taken by physical pipe (in process) */
+};
+
+/**
+ * @brief      USB HCD status code
+ */
+
+enum usb_h_status
+{
+  USB_H_OK = 0,             /** OK */
+  USB_H_BUSY = -4,          /** Busy */
+  USB_H_DENIED = -17,       /** Denied */
+  USB_H_TIMEOUT = -8,       /** Timeout */
+  USB_H_ABORT = -3,         /** Abort */
+  USB_H_STALL = -25,        /** Stall protocol */
+  USB_H_RESET = -7,         /** Transfer reset by pipe re-configure */
+  USB_H_ERR_ARG = -13,      /** Argument error */
+  USB_H_ERR_UNSP_OP = -27,  /** Operation not supported */
+  USB_H_ERR_NO_RSC = -28,   /** No resource */
+  USB_H_ERR_NOT_INIT = -20, /** Not initialized */
+  USB_H_ERR = -6            /** Some general error */
+};
+
+/* The following enumeration represents the various states of the USB host
+ * state machine (for debug purposes only)
+ */
+
+enum sam_smstate_e
+{
+  SMSTATE_DETACHED = 0,  /* Not attached to a device */
+  SMSTATE_ATTACHED,      /* Attached to a device */
+  SMSTATE_ENUM,          /* Attached, enumerating */
+  SMSTATE_CLASS_BOUND,   /* Enumeration complete, class bound */
+};
+
+/* This enumeration provides the reason for the channel halt. */
+
+enum sam_chreason_e
+{
+  CHREASON_IDLE = 0,     /* Inactive (initial state) */
+  CHREASON_FREED,        /* Channel is no longer in use */
+  CHREASON_XFRC,         /* Transfer complete */
+  CHREASON_NAK,          /* NAK received */
+  CHREASON_NYET,         /* NotYet received */
+  CHREASON_STALL,        /* Endpoint stalled */
+  CHREASON_TXERR,        /* Transfer error received */
+  CHREASON_DTERR,        /* Data toggle error received */
+  CHREASON_FRMOR,        /* Frame overrun */
+  CHREASON_CANCELLED     /* Transfer cancelled */
+};
+
+/**
+ * @brief      Transfer descriptor for control transfer
+ *
+ * Timing in USB 2.0 spec.:
+ * - 9.2.6.1 : USB sets an upper limit of 5 seconds as the upper
+ *    limit for any command to be processed.
+ * - 9.2.6.3 : if a device receives a SetAddress() request,
+ *    the device must be able to complete processing
+ *    of the request and be able to
+ *    successfully complete the Status stage of the request within
+ *    50 ms.
+ *    After successful completion of the Status stage, the device is
+ *    allowed a SetAddress() recovery interval of 2 ms. At the end of
+ *    this interval, the device must be able to accept Setup packets
+ *    addressed to the new address.
+ * - 9.2.6.4 : For standard device requests that require no Data stage,
+ *    must be able to complete the request and be able to successfully
+ *    complete the Status stage of the request within 50 ms of receipt
+ *    of the request. This limitation applies to requests to the
+ *    device, interface, or endpoint. For standard device requests
+ *    that require data stage transfer to the host, the
+ *    device must be able to return the first data packet
+ *    to the host within 500 ms of receipt of the request. For
+ *    subsequent data packets, if any, the device must be able to
+ *    return them within 500 ms of successful completion of the
+ *    transmission of the previous packet. The device must then be
+ *    able to successfully complete the status stage
+ *    within 50 ms after returning the last data packet.
+ *    For standard device requests that require a data stage transfer
+ *    to the device, the 5-second limit applies.
+ * - 9.2.6.5 : Unless specifically exempted in the class document, all
+ *    class-specific requests must meet the timing limitations for
+ *    standard device requests.
+ *
+ * Conclusion:
+ * 1. Whole request with data: 5 seconds
+ * 2. Whole request without data: 50 ms
+ * 3. Data packets: 500 ms
+ */
+
+struct usb_h_ctrl_xfer
+{
+  uint8_t *data;        /* Pointer to transfer data */
+  uint8_t *setup;       /* Pointer to setup packet */
+  uint16_t size;        /* Expected transfer size */
+  uint16_t count;       /* Transfer count */
+  int16_t req_timeout;  /* Timeout for request, -1 if disable timeout */
+  int16_t pkt_timeout;  /* Timeout between packets */
+  uint16_t pkt_size;    /* Packet size during transfer (<= allocate max packet size) */
+  uint8_t state;        /* Transfer state */
+  int8_t status;        /* Last transfer status */
+};
+
+/**
+ * Transfer descriptor for bulk / interrupt / iso transfer
+ */
+
+struct usb_h_bulk_int_iso_xfer
+{
+  uint32_t size;  /** Expected transfer size */
+  uint32_t count; /** Transfer count */
+  uint8_t *data;  /** Pointer to transfer data */
+  uint16_t reserved[3];
+  uint8_t state;  /** Transfer state */
+  int8_t status;  /** Last transfer status */
+};
+
+/**
+ * Transfer descriptor for periodic high bandwidth transfer
+ */
+
+struct usb_h_high_bw_xfer
+{
+  uint32_t size;         /** Expected transfer size */
+  uint32_t count;        /** Transfer count */
+  uint8_t *data;         /** Pointer to transfer data */
+  uint16_t pkt_size[3];  /** Micro frame packet sizes */
+  uint8_t state;         /** Transfer state */
+  int8_t status;         /** Last transfer status */
+};
+
+/**
+ * General transfer descriptor
+ */
+
+struct usb_h_xfer
+{
+  /** Reserved for different transfer */
+
+  union
+  {
+    uint16_t u16[9];
+    uint8_t  u8[18];
+  } reserved;
+  uint8_t state; /** Transfer state */
+  int8_t status; /** Last transfer status */
+};
+
+/* USB Host Controller Driver Pipe structure */
+
+/* This is the internal representation of an pipe */
+
+struct sam_pipe_s
+{
+  struct usbhost_pipedesc_s *descb[2]; /* Pointers to this pipe descriptors */
+  volatile uint8_t pipestate;          /* State of the pipe (see enum usb_h_pipe_state) */
+  volatile uint8_t pipestatus;         /* Status of the pipe */
+  volatile int8_t  pipestatus_general; /* Status of the pipe */
+  volatile int8_t pipestate_general;
+  int16_t result;                      /* The result of the transfer */
+  uint32_t size;                       /* Expected transfer size */
+  uint32_t count;                      /* Transfer count */
+  uint8_t *data;                       /* Pointer to transfer data */
+  int16_t pkt_timeout;                 /* Timeout between packets (500ms for data and 50ms for status), -1 if disabled */
+  uint8_t zlp:1;                       /* Transfer ZLP support */
+
+  uint8_t              stalled:1;    /* true: Endpoint is stalled */
+  uint8_t              pending:1;    /* true: IN Endpoint stall is pending */
+  uint8_t              halted:1;     /* true: Endpoint feature halted */
+  uint8_t              zlpsent:1;    /* Zero length packet has been sent */
+  uint8_t              txbusy:1;     /* Write request queue is busy (recursion avoidance kludge) */
+  uint8_t              rxactive:1;   /* read request is active (for top of queue) */
+  bool              inuse;           /* True: This pipe is "in use" */
+  bool              in;              /* True: IN endpoint */
+  uint8_t           idx;             /* Pipe index */
+  uint8_t           epno;            /* Device endpoint number (0-127) */
+  uint8_t           eptype;          /* See _EPTYPE_* definitions */
+  uint8_t           funcaddr;        /* Device function address */
+  uint8_t           speed;           /* Device speed */
+  uint8_t           interval;        /* Interrupt/isochronous EP polling interval */
+  uint16_t          maxpacket;       /* Max packet size */
+
+  sem_t waitsem;               /* Channel wait semaphore */
+  volatile bool waiter;        /* True: Thread is waiting for a channel event */
+
+#ifdef CONFIG_USBHOST_ASYNCH
+  usbhost_asynch_t callback;   /* Transfer complete callback */
+  FAR void *arg;               /* Argument that accompanies the callback */
+#endif
+
+#ifdef HPL_USB_HOST      /* from: Atmel Start hpl_usb_host.h */
+  uint16_t max_pkt_size; /* Endpoint max packet size (bits 10..0) */
+  uint8_t ep;            /* Endpoint address */
+  uint8_t type;          /* Endpoint type: Control, Isochronous, Bulk or Interrupt */
+  uint8_t toggle;        /* Current toggle (driver dependent) */
+  uint8_t bank : 2;      /* Endpoint number of banks (HW dependent) */
+  uint8_t high_bw_out : 1;
+  uint8_t dma : 1;            /* Uses DMA (on transfer) */
+  uint8_t periodic_start : 1; /* Transfer periodic */
+
+  /** Transfer status */
+
+  union
+  {
+    struct usb_h_xfer general;          /* General transfer info */
+    struct usb_h_ctrl_xfer ctrl;        /* Control transfer status */
+    struct usb_h_bulk_int_iso_xfer bii; /* Bulk interrupt iso transfer status */
+    struct usb_h_high_bw_xfer hbw;      /* Periodic high bandwidth transfer status */
+  } x;
+#endif
+};
+
+/* This structure retains the state of the USB host controller */
+
+struct sam_usbhost_s
+{
+  /* Common device fields.  This must be the first thing defined in the
+   * structure so that it is possible to simply cast from struct usbhost_s
+   * to struct sam_usbhost_s.
+   */
+
+  struct usbhost_driver_s drvr;
+
+  /* This is the hub port description understood by class drivers */
+
+  struct usbhost_roothubport_s rhport;
+
+  /* Overall driver status */
+
+  uint8_t           hoststate; /* State of the device (see enum sam_hoststate_e) */
+  uint8_t           prevstate; /* Previous state of the device before SUSPEND */
+  uint16_t          epavail;   /* Bitset of available endpoints */
+  sem_t             exclsem;   /* Support mutually exclusive access */
+  bool              connected; /* Connected to device */
+  bool              change;    /* Connection change */
+  bool              pscwait;   /* True: Thread is waiting for a port event */
+  uint8_t           smstate;   /* The state of the USB host state machine */
+  uint8_t           irqset;    /* Set of enabled interrupts */
+  uint8_t           xfrtype;   /* See enum _hxfrdn_e */
+  sem_t             pscsem;    /* Semaphore to wait for a port event */
+
+  uint16_t pipes_unfreeze; /** Pipes to unfreeze after wakeup */
+  int8_t suspend_start;    /** Delayed suspend time in ms */
+  int8_t resume_start;     /** Delayed resume time in ms */
+  int8_t n_ctrl_req_user;  /** Control transfer request user count */
+  int8_t n_sof_user;       /** SOF user count (callback, suspend, resume, ctrl request) */
+  uint8_t pipe_pool_size;  /** Pipe pool size in number of pipes */
+
+#ifdef CONFIG_USBHOST_HUB
+
+  /* Used to pass external hub port events */
+
+  volatile struct usbhost_hubport_s *hport;
+#endif
+
+  /* The pipe list */
+
+  __attribute__((__aligned__(4)))
+  struct sam_pipe_s pipelist[SAM_USB_NENDPOINTS];
+
+  /* Pipe descriptors 2 banks for each pipe */
+
+  __attribute__((__aligned__(4)))
+  struct usbhost_pipedesc_s pipe_descriptors[SAM_USB_NENDPOINTS *
+                                             SAM_USB_NBANKS()];
+
+  /* CTRL */
+
+  usbhost_ep_t ep0; /* Root hub port EP0 description */
+  __attribute__((__aligned__(4))) uint8_t ctrl_buffer[64];
 };
+#endif
 
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
 
-/* Register operations ******************************************************/
+/* Register operations */
 
 #ifdef CONFIG_SAMD5E5_USB_REGDEBUG
 static void   sam_printreg(uintptr_t regaddr, uint32_t regval, bool iswrite);
@@ -402,6 +730,10 @@ static void   sam_putreg16(uint16_t regval, uintptr_t regaddr);
 static uint32_t sam_getreg8(uintptr_t regaddr);
 static void   sam_putreg8(uint8_t regval, uintptr_t regaddr);
 static void   sam_dumpep(struct sam_usbdev_s *priv, uint8_t epno);
+
+#ifdef CONFIG_USBHOST
+static void   sam_dumppipe(struct sam_usbhost_s *priv, uint8_t epno);
+#endif
 #else
 static inline uint32_t sam_getreg32(uintptr_t regaddr);
 static inline void sam_putreg32(uint32_t regval, uintptr_t regaddr);
@@ -409,17 +741,36 @@ static inline uint32_t sam_getreg16(uintptr_t regaddr);
 static inline void sam_putreg16(uint16_t regval, uintptr_t regaddr);
 static inline uint32_t sam_getreg8(uintptr_t regaddr);
 static inline void sam_putreg8(uint8_t regval, uintptr_t regaddr);
-# define sam_dumpep(priv,epno)
+# define sam_dumpep(priv, epno)
+#ifdef CONFIG_USBHOST
+# define sam_dumppipe(priv, epno)
+#endif
 #endif
+static inline void sam_modifyreg8(uint32_t clrbits,
+                                  uint32_t setbits,
+                                  uintptr_t regaddr);
 
-/* Suspend/Resume Helpers ***************************************************/
+/* Semaphores */
 
-#if 0 /* Not used */
-static void   sam_suspend(struct sam_usbdev_s *priv);
+static void sam_takesem(sem_t *sem);
+#define sam_givesem(s) nxsem_post(s);
+#ifdef CONFIG_USBHOST
 #endif
+
+/* Clks */
+
+static void sam_enableclks(void);
+
+#ifdef CONFIG_USBDEV
+
+static void sam_disableclks(void);
+
+/* Suspend/Resume Helpers */
+
+static void   sam_suspend(struct sam_usbdev_s *priv);
 static void   sam_resume(struct sam_usbdev_s *priv);
 
-/* Request Helpers **********************************************************/
+/* Request Helpers */
 
 static struct sam_req_s *
               sam_req_dequeue(struct sam_rqhead_s *queue);
@@ -434,7 +785,7 @@ static int    sam_req_read(struct sam_usbdev_s *priv,
                 struct sam_ep_s *privep, uint16_t recvsize);
 static void   sam_req_cancel(struct sam_ep_s *privep, int16_t status);
 
-/* Interrupt level processing ***********************************************/
+/* Interrupt level processing */
 
 static void   sam_ep0_ctrlread(struct sam_usbdev_s *priv);
 static void   sam_ep0_wrstatus(struct sam_usbdev_s *priv,
@@ -445,7 +796,7 @@ static void   sam_ep0_setup(struct sam_usbdev_s *priv);
 static void   sam_ep_interrupt(struct sam_usbdev_s *priv, int epno);
 static int    sam_usb_interrupt(int irq, void *context, void *arg);
 
-/* Endpoint helpers *********************************************************/
+/* Endpoint helpers */
 
 static void   sam_ep_reset(struct sam_usbdev_s *priv, uint8_t epno);
 static void   sam_epset_reset(struct sam_usbdev_s *priv, uint16_t epset);
@@ -461,7 +812,7 @@ static inline bool
 static int    sam_ep_configure_internal(struct sam_ep_s *privep,
                 const struct usb_epdesc_s *desc);
 
-/* Endpoint operations ******************************************************/
+/* Endpoint operations */
 
 static int    sam_ep_configure(struct usbdev_ep_s *ep,
                 const struct usb_epdesc_s *desc, bool last);
@@ -480,7 +831,7 @@ static int    sam_ep_cancel(struct usbdev_ep_s *ep,
                 struct usbdev_req_s *req);
 static int    sam_ep_stallresume(struct usbdev_ep_s *ep, bool resume);
 
-/* USB device controller operations *****************************************/
+/* USB device controller operations */
 
 static struct usbdev_ep_s *
               sam_allocep(struct usbdev_s *dev, uint8_t epno, bool in,
@@ -491,20 +842,211 @@ static int    sam_wakeup(struct usbdev_s *dev);
 static int    sam_selfpowered(struct usbdev_s *dev, bool selfpowered);
 static int    sam_pullup(struct usbdev_s *dev,  bool enable);
 
-/* Initialization/Reset *****************************************************/
+/* Initialization/Reset */
 
 static void   sam_reset(struct sam_usbdev_s *priv);
-static void   sam_enableclks(void);
-static void   sam_disableclks(void);
 static void   sam_hw_setup(struct sam_usbdev_s *priv);
 static void   sam_sw_setup(struct sam_usbdev_s *priv);
 static void   sam_hw_shutdown(struct sam_usbdev_s *priv);
 static void   sam_sw_shutdown(struct sam_usbdev_s *priv);
+#endif
+
+#ifdef CONFIG_USBHOST
+
+#undef CONFIG_SAM_USBHOST_PKTDUMP 
+#ifdef CONFIG_SAM_USBHOST_PKTDUMP
+#  define sam_pktdump(m,b,n) lib_dumpbuffer(m,b,n)
+#else
+#  define sam_pktdump(m,b,n)
+#endif
+
+/* Pipe helpers */
+
+static void   sam_reset_pipes(struct sam_usbhost_s *priv, bool warm_reset);
+static void   sam_pipe_reset(struct sam_usbhost_s *priv, uint8_t epno);
+static void   sam_pipeset_reset(struct sam_usbhost_s *priv, uint16_t epset);
+
+/* Byte stream access helper functions */
+
+static inline uint16_t sam_getle16(const uint8_t *val);
+
+/* Pipe management */
+
+static int sam_pipe_alloc(FAR struct sam_usbhost_s *priv);
+static inline void sam_pipe_free(FAR struct sam_usbhost_s *priv,
+              int idx);
+static void sam_pipe_configure(FAR struct sam_usbhost_s *priv, int idx);
+static int sam_pipe_waitsetup(FAR struct sam_usbhost_s *priv,
+              FAR struct sam_pipe_s *pipe);
+#ifdef CONFIG_USBHOST_ASYNCH
+static int sam_pipe_asynchsetup(FAR struct sam_usbhost_s *priv,
+                                FAR struct sam_pipe_s *pipe,
+                                usbhost_asynch_t callback, FAR void *arg);
+#endif
+static int sam_pipe_wait(FAR struct sam_usbhost_s *priv,
+              FAR struct sam_pipe_s *pipe);
+static void sam_pipe_wakeup(FAR struct sam_usbhost_s *priv,
+              FAR struct sam_pipe_s *pipe);
+static int sam_ctrlep_alloc(FAR struct sam_usbhost_s *priv,
+                            FAR const struct usbhost_epdesc_s *epdesc,
+                            FAR usbhost_ep_t *ep);
+static int sam_xfrep_alloc(FAR struct sam_usbhost_s *priv,
+                           FAR const struct usbhost_epdesc_s *epdesc,
+                           FAR usbhost_ep_t *ep);
+
+/* Control/data transfer logic */
+
+static void sam_transfer_terminate(FAR struct sam_usbhost_s *priv,
+              FAR struct sam_pipe_s *pipe, int result);
+static void sam_transfer_abort(FAR struct sam_usbhost_s *priv,
+              FAR struct sam_pipe_s *pipe, int result);
+
+/* OUT transfers */
+
+static void sam_send_continue(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe);
+static void sam_send_start(FAR struct sam_usbhost_s *priv,
+                           FAR struct sam_pipe_s *pipe);
+static ssize_t sam_out_transfer(FAR struct sam_usbhost_s *priv,
+                                FAR struct sam_pipe_s *pipe,
+                                FAR uint8_t *buffer,
+                                size_t buflen);
+#ifdef CONFIG_USBHOST_ASYNCH
+static void sam_out_next(FAR struct sam_usbhost_s *priv,
+                         FAR struct sam_pipe_s *pipe);
+static int  sam_out_asynch(FAR struct sam_usbhost_s *priv,
+                           FAR struct sam_pipe_s *pipe,
+                           FAR uint8_t *buffer, size_t buflen,
+                           usbhost_asynch_t callback, FAR void *arg);
+#endif
+
+/* Control transfers */
+
+static int  sam_ctrl_sendsetup(FAR struct sam_usbhost_s *priv,
+                               FAR struct sam_pipe_s *pipe,
+                               FAR const struct usb_ctrlreq_s *req);
+static int  sam_ctrl_senddata(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe,
+                              FAR uint8_t *buffer, unsigned int buflen);
+static int  sam_ctrl_recvdata(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe,
+                              FAR uint8_t *buffer, unsigned int buflen);
+static int  sam_in_setup(FAR struct sam_usbhost_s *priv,
+                         FAR struct sam_pipe_s *pipe);
+static int  sam_out_setup(FAR struct sam_usbhost_s *priv,
+                          FAR struct sam_pipe_s *pipe);
+
+/* IN transfers */
+
+static void sam_recv_continue(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe);
+static void sam_recv_restart(FAR struct sam_usbhost_s *priv,
+                             FAR struct sam_pipe_s *pipe);
+static void sam_recv_start(FAR struct sam_usbhost_s *priv,
+                           FAR struct sam_pipe_s *pipe);
+static ssize_t sam_in_transfer(FAR struct sam_usbhost_s *priv,
+                               FAR struct sam_pipe_s *pipe,
+                               FAR uint8_t *buffer,
+                               size_t buflen);
+#ifdef CONFIG_USBHOST_ASYNCH
+static void sam_in_next(FAR struct sam_usbhost_s *priv,
+                        FAR struct sam_pipe_s *pipe);
+static int  sam_in_asynch(FAR struct sam_usbhost_s *priv,
+                          FAR struct sam_pipe_s *pipe,
+                          FAR uint8_t *buffer, size_t buflen,
+                          usbhost_asynch_t callback, FAR void *arg);
+#endif
+
+/* Interrupt handling */
+
+/* Lower level interrupt handlers */
+
+static void sam_gint_connected(FAR struct sam_usbhost_s *priv);
+static void sam_gint_disconnected(FAR struct sam_usbhost_s *priv);
+
+static void sam_pipe_interrupt(struct sam_usbhost_s *priv, int idx);
+static int  sam_usbhost_interrupt(int irq, void *context, void *arg);
+
+/* USB host controller operations */
+
+static int sam_wait(FAR struct usbhost_connection_s *conn,
+                    FAR struct usbhost_hubport_s **hport);
+static int sam_rh_enumerate(FAR struct sam_usbhost_s *priv,
+                            FAR struct usbhost_connection_s *conn,
+                            FAR struct usbhost_hubport_s *hport);
+static int sam_enumerate(FAR struct usbhost_connection_s *conn,
+                         FAR struct usbhost_hubport_s *hport);
+static int sam_ep0configure(FAR struct usbhost_driver_s *drvr,
+                            usbhost_ep_t ep0, uint8_t funcaddr,
+                            uint8_t speed,
+                            uint16_t maxpacketsize);
+static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
+                       FAR const FAR struct usbhost_epdesc_s *epdesc,
+                       FAR usbhost_ep_t *ep);
+static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep);
+static int sam_alloc(FAR struct usbhost_driver_s *drvr,
+                     FAR uint8_t **buffer, FAR size_t *maxlen);
+static int sam_free(FAR struct usbhost_driver_s *drvr,
+                    FAR uint8_t *buffer);
+static int sam_ioalloc(FAR struct usbhost_driver_s *drvr,
+                       FAR uint8_t **buffer, size_t buflen);
+static int sam_iofree(FAR struct usbhost_driver_s *drvr,
+                      FAR uint8_t *buffer);
+static int sam_ctrlin(FAR struct usbhost_driver_s *drvr,
+                      usbhost_ep_t ep0,
+                      const struct usb_ctrlreq_s *req,
+                      FAR uint8_t *buffer);
+static int sam_ctrlout(FAR struct usbhost_driver_s *drvr,
+                       usbhost_ep_t ep0,
+                       FAR const struct usb_ctrlreq_s *req,
+                       FAR const uint8_t *buffer);
+static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr,
+                            usbhost_ep_t ep,
+                            FAR uint8_t *buffer, size_t buflen);
+#ifdef CONFIG_USBHOST_ASYNCH
+static int sam_asynch(FAR struct usbhost_driver_s *drvr,
+                      usbhost_ep_t ep,
+                      FAR uint8_t *buffer, size_t buflen,
+                      usbhost_asynch_t callback, FAR void *arg);
+#endif
+static int sam_cancel(FAR struct usbhost_driver_s *drvr,
+                      usbhost_ep_t ep);
+#ifdef CONFIG_USBHOST_HUB
+static int sam_connect(FAR struct usbhost_driver_s *drvr,
+                       FAR struct usbhost_hubport_s *hport,
+                       bool connected);
+#endif
+static void sam_disconnect(FAR struct usbhost_driver_s *drvr,
+                           FAR struct usbhost_hubport_s *hport);
+
+static void sam_hostreset(struct sam_usbhost_s *priv);
+static void sam_add_sof_user(struct sam_usbhost_s *priv);
+#endif
 
 /****************************************************************************
  * Private Data
  ****************************************************************************/
 
+#ifdef CONFIG_USBHOST
+
+/* In this driver implementation, support is provided for only a single
+ * USB host. All status information can be simply retained in a single global
+ * instance.
+ */
+
+static struct sam_usbhost_s g_usbhost;
+
+/* This is the connection/enumeration interface */
+
+static struct usbhost_connection_s g_usbconn =
+{
+  .wait             = sam_wait,
+  .enumerate        = sam_enumerate,
+};
+#endif
+
+#ifdef CONFIG_USBDEV
+
 /* Since there is only a single USB interface, all status information can be
  * be simply retained in a single global instance.
  */
@@ -550,6 +1092,7 @@ static const struct usb_epdesc_s g_ep0desc =
   },
   .interval      = 0
 };
+#endif
 
 /* Device error strings that may be enabled for more desciptive USB trace
  * output.
@@ -645,12 +1188,47 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
   TRACE_STR(SAM_TRACEINTID_EP0WRSTATUS),
   TRACE_STR(SAM_TRACEINTID_EPTRCPT0_LEN),
 
+  TRACE_STR(SAM_TRACEINTID_PENDING_PIPE),
+  TRACE_STR(SAM_TRACEINTID_PIPENO),
+
   TRACE_STR_END
 };
 #endif
 
 /****************************************************************************
- * Private Private Functions
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_takesem
+ *
+ * Description:
+ *   This is just a wrapper to handle the annoying behavior of semaphore
+ *   waits that return due to the receipt of a signal.
+ *
+ ****************************************************************************/
+
+static void sam_takesem(sem_t *sem)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(sem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * Register Operations
  ****************************************************************************/
 
 /****************************************************************************
@@ -664,7 +1242,7 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] =
 #ifdef CONFIG_SAMD5E5_USB_REGDEBUG
 static void sam_printreg(uintptr_t regaddr, uint32_t regval, bool iswrite)
 {
-  uinfo("%p%s%08x\n", regaddr, iswrite ? "<-" : "->", regval);
+  uinfo("%p%s0x%08x\n", regaddr, iswrite ? "<-" : "->", regval);
 }
 #endif
 
@@ -672,8 +1250,8 @@ static void sam_printreg(uintptr_t regaddr, uint32_t regval, bool iswrite)
  * Name: sam_checkreg
  *
  * Description:
- *   Check if it is time to output debug information for accesses to a
- *   SAMD5E5 USB registers
+ *   Check if it is time to output debug information for accesses
+ *   to a SAMD5E5 USB registers.
  *
  ****************************************************************************/
 
@@ -685,8 +1263,9 @@ static void sam_checkreg(uintptr_t regaddr, uint32_t regval, bool iswrite)
   static uint32_t  count     = 0;
   static bool      prevwrite = false;
 
-  /* Is this the same value that we read from/wrote to the same register
-   * last time?  Are we polling the register?  If so, suppress the output.
+  /* Is this the same value that we read from/wrote
+   * to the same register last time?
+   * Are we polling the register?  If so, suppress the output.
    */
 
   if (regaddr == prevaddr && regval == preval && prevwrite == iswrite)
@@ -897,92 +1476,190 @@ static inline void sam_putreg8(uint8_t regval, uint32_t regaddr)
  ****************************************************************************/
 
 #if defined(CONFIG_SAMD5E5_USB_REGDEBUG) && defined(CONFIG_DEBUG_USB)
+#ifdef CONFIG_USBDEV
 static void sam_dumpep(struct sam_usbdev_s *priv, uint8_t epno)
 {
   /* Global Registers */
 
   uinfo("Global Registers:\n");
-  uinfo("       CTRLB:    %04x\n",
-        sam_getreg16(SAM_USBDEV_CTRLB));
-  uinfo("        FNUM:    %04x\n",
-        sam_getreg16(SAM_USBDEV_FNUM));
-  uinfo("        DADD:    %02x\n",
-        sam_getreg8(SAM_USBDEV_DADD));
-  uinfo("       INTEN:    %04x\n",
-        sam_getreg16(SAM_USBDEV_INTENSET));
-  uinfo("      STATUS:    %02x\n",
-        sam_getreg8(SAM_USBDEV_STATUS));
-  uinfo("     INTFLAG:    %04x\n",
-        sam_getreg16(SAM_USBDEV_INTFLAG));
-  uinfo("   EPCFG[%d]:    %02x\n",
-        epno, sam_getreg8(SAM_USBDEV_EPCFG(epno)));
-  uinfo("EPSTATUS[%d]:    %02x\n",
-        epno, sam_getreg8(SAM_USBDEV_EPSTATUS(epno)));
+  uinfo("       CTRLB: 0x%04x\n", sam_getreg16(SAM_USBDEV_CTRLB));
+  uinfo("        FNUM: 0x%04x\n", sam_getreg16(SAM_USBDEV_FNUM));
+  uinfo("        DADD: 0x%02x\n", sam_getreg8(SAM_USBDEV_DADD));
+  uinfo("    INTENSET: 0x%04x\n", sam_getreg16(SAM_USBDEV_INTENSET));
+  uinfo("      STATUS: 0x%02x\n", sam_getreg8(SAM_USBDEV_STATUS));
+  uinfo("     INTFLAG: 0x%04x\n", sam_getreg16(SAM_USBDEV_INTFLAG));
+  uinfo("   EPCFG[%d]: 0x%02x\n", epno, sam_getreg8(SAM_USBDEV_EPCFG(epno)));
+  uinfo("EPSTATUS[%d]: 0x%02x\n", epno,
+                                  sam_getreg8(SAM_USBDEV_EPSTATUS(epno)));
 }
 #endif
 
-/****************************************************************************
- * Name: sam_req_dequeue
- ****************************************************************************/
-
-static struct sam_req_s *sam_req_dequeue(struct sam_rqhead_s *queue)
+#ifdef CONFIG_USBHOST
+static void sam_dumppipe(struct sam_usbhost_s *priv, uint8_t epno)
 {
-  struct sam_req_s *ret = queue->head;
-
-  if (ret)
-    {
-      queue->head = ret->flink;
-      if (!queue->head)
-        {
-          queue->tail = NULL;
-        }
-
-      ret->flink = NULL;
-    }
+  /* Global Registers */
 
-  return ret;
+  uinfo("Global Host Registers:\n");
+  uinfo("       CTRLB: 0x%04x\n", sam_getreg16(SAM_USBHOST_CTRLB));
+  uinfo("        FNUM: 0x%04x\n", sam_getreg16(SAM_USBHOST_FNUM));
+  uinfo("       HSOFC: 0x%02x\n", sam_getreg8(SAM_USBHOST_HSOFC));
+  uinfo("    INTENSET: 0x%04x\n", sam_getreg16(SAM_USBHOST_INTENSET));
+  uinfo("      STATUS: 0x%02x\n", sam_getreg8(SAM_USBHOST_STATUS));
+  uinfo("     INTFLAG: 0x%04x\n", sam_getreg16(SAM_USBHOST_INTFLAG));
+  uinfo(" PIPECFG[%d]: 0x%02x\n", epno, sam_getreg8(SAM_USBHOST_PCFG(epno)));
+  uinfo(" PSTATUS[%d]: 0x%02x\n", epno,
+                                  sam_getreg8(SAM_USBHOST_PSTATUS(epno)));
 }
+#endif
+#endif
 
 /****************************************************************************
- * Name: sam_req_enqueue
+ * Name: sam_modifyreg8
+ *
+ * Description:
+ *   Modify selected bits of an SAM register.
+ *
  ****************************************************************************/
 
-static void sam_req_enqueue(struct sam_rqhead_s *queue,
-                            struct sam_req_s *req)
+static inline void sam_modifyreg8(uint32_t clrbits,
+                                  uint32_t setbits, uintptr_t regaddr)
 {
-  req->flink = NULL;
-  if (!queue->head)
-    {
-      queue->head = req;
-      queue->tail = req;
-    }
-  else
-    {
-      queue->tail->flink = req;
-      queue->tail        = req;
-    }
+  sam_putreg8((((sam_getreg8(regaddr)) & (~clrbits)) | setbits), regaddr);
 }
 
 /****************************************************************************
- * Name: sam_req_complete
+ * Name: sam_enableclks
+ * Description:
+ *   Enable USB clock
  ****************************************************************************/
 
-static void sam_req_complete(struct sam_ep_s *privep, int16_t result)
+static void sam_enableclks(void)
 {
-  struct sam_req_s *privreq;
-  irqstate_t flags;
+  sam_gclk_chan_enable(GCLK_CHAN_USB, BOARD_USB_GCLKGEN, false);
+  sam_ahb_usb_enableperiph();
+  sam_apb_usb_enableperiph();
+}
 
-  /* Remove the completed request at the head of the endpoint request list */
+/****************************************************************************
+ * Name: sam_ctrla_write
+ *
+ * Description:
+ *   writes value to CTRLA register some bits needs write-synchronisation
+ *
+ ****************************************************************************/
 
-  flags = enter_critical_section();
-  privreq = sam_req_dequeue(&privep->reqq);
-  leave_critical_section(flags);
+static void sam_ctrla_write(uint8_t value)
+{
+  sam_putreg8(value, SAM_USB_CTRLA);
 
-  if (privreq)
+  if (value & USB_CTRLA_SWRST)
     {
-      /* Save the result in the request structure */
+      /* Due to synchronization there is a delay from writing CTRLA.SWRST
+       * until the reset is complete. CTRLA.SWRST and SYNCBUSY.SWRST will
+       * both be cleared when the reset is complete.
+       */
 
-      privreq->req.result = result;
+      while ((sam_getreg8(SAM_USB_CTRLA) & USB_CTRLA_SWRST) &&
+             (sam_getreg8(SAM_USB_SYNCBUSY) & USB_SYNCBUSY_SWRST))
+        ;
+
+      return;
+    }
+
+  if (value & USB_CTRLA_ENABLE)
+    {
+      /* Due to synchronization there is delay from writing CTRLA.ENABLE
+       * until the peripheral is enabled/disabled.
+       * SYNCBUSY.ENABLE will be cleared when the operation is complete.
+       */
+
+      while ((sam_getreg8(SAM_USB_SYNCBUSY) & USB_SYNCBUSY_ENABLE))
+        ;
+    }
+}
+
+#ifdef CONFIG_USBDEV
+
+/****************************************************************************
+ * Name: sam_disableclks
+ * Description:
+ *   Disable USB clock
+ ****************************************************************************/
+
+static void sam_disableclks(void)
+{
+  sam_gclk_chan_disable(GCLK_CHAN_USB);
+  sam_apb_usb_disableperiph();
+}
+
+/****************************************************************************
+ * Request Helpers
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_req_dequeue
+ ****************************************************************************/
+
+static struct sam_req_s *sam_req_dequeue(struct sam_rqhead_s *queue)
+{
+  struct sam_req_s *ret = queue->head;
+
+  if (ret)
+    {
+      queue->head = ret->flink;
+      if (!queue->head)
+        {
+          queue->tail = NULL;
+        }
+
+      ret->flink = NULL;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: sam_req_enqueue
+ ****************************************************************************/
+
+static void sam_req_enqueue(struct sam_rqhead_s *queue,
+                            struct sam_req_s *req)
+{
+  req->flink = NULL;
+  if (!queue->head)
+    {
+      queue->head = req;
+      queue->tail = req;
+    }
+  else
+    {
+      queue->tail->flink = req;
+      queue->tail        = req;
+    }
+}
+
+/****************************************************************************
+ * Name: sam_req_complete
+ ****************************************************************************/
+
+static void sam_req_complete(struct sam_ep_s *privep, int16_t result)
+{
+  struct sam_req_s *privreq;
+  irqstate_t flags;
+
+  uinfo("ENTRY\n");
+
+  /* Remove the completed request at the head of the endpoint request list */
+
+  flags = enter_critical_section();
+  privreq = sam_req_dequeue(&privep->reqq);
+  leave_critical_section(flags);
+
+  if (privreq)
+    {
+      /* Save the result in the request structure */
+
+      privreq->req.result = result;
 
       /* Callback to the request completion handler */
 
@@ -1046,6 +1723,7 @@ static void sam_req_wrsetup(struct sam_usbdev_s *priv,
   /* setup TX transfer using ep configured maxpacket size */
 
   priv->eplist[epno].descb[1]->addr = (uint32_t) buf;
+  uinfo("addr=%p\n", buf);
   packetsize = priv->eplist[epno].descb[1]->pktsize;
   packetsize &= ~USBDEV_PKTSIZE_BCNT_MASK;
   packetsize &= ~USBDEV_PKTSIZE_MPKTSIZE_MASK;
@@ -1170,7 +1848,7 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep)
        * (2) called with a request packet that has len == 0
        *
        * len == 0 means that it is requested to send a zero length packet
-       * required by protocol
+       * required by protocoll
        */
 
       else if ((privreq->req.len == 0) && !privep->zlpsent)
@@ -1187,6 +1865,7 @@ static int sam_req_write(struct sam_usbdev_s *priv, struct sam_ep_s *privep)
           /* setup 0 length TX transfer */
 
           priv->eplist[0].descb[1]->addr     = (uint32_t) &priv->ep0out[0];
+          uinfo("addr=%p\n", &priv->ep0out[0]);
           priv->eplist[0].descb[1]->pktsize &= ~USBDEV_PKTSIZE_BCNT_MASK;
           priv->eplist[0].descb[1]->pktsize &= ~USBDEV_PKTSIZE_MPKTSIZE_MASK;
           priv->eplist[0].descb[1]->pktsize |= USBDEV_PKTSIZE_BCNT(0);
@@ -1331,6 +2010,7 @@ static int sam_req_read(struct sam_usbdev_s *priv, struct sam_ep_s *privep,
   privreq->req.xfrd = 0;
   privreq->inflight = privreq->req.len;
   priv->eplist[epno].descb[0]->addr = (uint32_t) privreq->req.buf;
+  uinfo("addr=%p\n", privreq->req.buf);
   packetsize        = priv->eplist[epno].descb[0]->pktsize;
   packetsize       &= ~USBDEV_PKTSIZE_BCNT_MASK;
   packetsize       &= ~USBDEV_PKTSIZE_MPKTSIZE_MASK;
@@ -1380,10 +2060,10 @@ static int sam_ep_configure_internal(struct sam_ep_s *privep,
 
   DEBUGASSERT(privep && privep->dev && desc);
 
-  uinfo("len: %02x type: %02x addr: %02x attr: %02x "
-        "maxpacketsize: %02x %02x interval: %02x\n",
+  uinfo("len: 0x%02x type: 0x%02x addr: 0x%02x attr: 0x%02x "
+        "maxpacketsize: 0x%02x%02x interval: 0x%02x\n",
         desc->len, desc->type, desc->addr, desc->attr,
-        desc->mxpacketsize[0],  desc->mxpacketsize[1],
+        desc->mxpacketsize[1],  desc->mxpacketsize[0],
         desc->interval);
 
   /* Decode the endpoint descriptor */
@@ -1461,67 +2141,67 @@ static int sam_ep_configure_internal(struct sam_ep_s *privep,
 
   /* write back disabled config */
 
-  sam_putreg8(0x7e, SAM_USBDEV_EPINTENCLR(epno));
-  sam_putreg8(0x7e, SAM_USBDEV_EPINTFLAG(epno));
+  sam_putreg8(0x7f, SAM_USBDEV_EPINTENCLR(epno));
+  sam_putreg8(0x7f, SAM_USBDEV_EPINTFLAG(epno));
 
   /* Re-configure and enable the endpoint */
 
   switch (eptype)
     {
-    case USB_EP_ATTR_XFER_CONTROL:
-        {
-          epconf = USBDEV_EPCCFG_EPTYPE0_CTRLOUT |
-                   USBDEV_EPCCFG_EPTYPE1_CTRLIN;
+      case USB_EP_ATTR_XFER_CONTROL:
+      {
+        epconf = USBDEV_EPCCFG_EPTYPE0_CTRLOUT |
+                 USBDEV_EPCCFG_EPTYPE1_CTRLIN;
 
-          /* Also enable IN interrupts */
+        /* Also enable IN interrupts */
 
-          intflags =  USBDEV_EPINT_TRCPT0 | USBDEV_EPINT_STALL0;
-          intflags |= USBDEV_EPINT_TRCPT1 | USBDEV_EPINT_STALL1;
-          intflags |= USBDEV_EPINT_RXSTP;
-          sam_putreg8(USBDEV_EPSTATUS_BK0RDY, SAM_USBDEV_EPSTATUSSET(0));
-          sam_putreg8(USBDEV_EPSTATUS_BK1RDY, SAM_USBDEV_EPSTATUSCLR(0));
-        }
+        intflags =  USBDEV_EPINT_TRCPT0 | USBDEV_EPINT_STALL0;
+        intflags |= USBDEV_EPINT_TRCPT1 | USBDEV_EPINT_STALL1;
+        intflags |= USBDEV_EPINT_RXSTP;
+        sam_putreg8(USBDEV_EPSTATUS_BK0RDY, SAM_USBDEV_EPSTATUSSET(0));
+        sam_putreg8(USBDEV_EPSTATUS_BK1RDY, SAM_USBDEV_EPSTATUSCLR(0));
+      }
       break;
 
 #ifdef CONFIG_USBDEV_ISOCHRONOUS
-    case USB_EP_ATTR_XFER_ISOC:
-      if (dirin)
-        {
-          epconf |= USBDEV_EPCCFG_EPTYPE1_ISOCIN;
-        }
-      else
-        {
-          epconf |= USBDEV_EPCCFG_EPTYPE0_ISOCOUT;
-        }
+      case USB_EP_ATTR_XFER_ISOC:
+        if (dirin)
+          {
+            epconf |= USBDEV_EPCCFG_EPTYPE1_ISOCIN;
+          }
+        else
+          {
+            epconf |= USBDEV_EPCCFG_EPTYPE0_ISOCOUT;
+          }
       break;
 #endif
 
-    case USB_EP_ATTR_XFER_BULK:
-      if (dirin)
-        {
-          epconf |= USBDEV_EPCCFG_EPTYPE1_BULKIN;
-        }
-      else
-        {
-          epconf |= USBDEV_EPCCFG_EPTYPE0_BULKOUT;
-        }
-      break;
+      case USB_EP_ATTR_XFER_BULK:
+        if (dirin)
+          {
+            epconf |= USBDEV_EPCCFG_EPTYPE1_BULKIN;
+          }
+        else
+          {
+            epconf |= USBDEV_EPCCFG_EPTYPE0_BULKOUT;
+          }
+        break;
 
-    case USB_EP_ATTR_XFER_INT:
-      if (dirin)
-        {
-          epconf |= USBDEV_EPCCFG_EPTYPE1_INTIN;
-        }
-      else
-        {
-          epconf |= USBDEV_EPCCFG_EPTYPE0_INTOUT;
-        }
-      break;
+      case USB_EP_ATTR_XFER_INT:
+        if (dirin)
+          {
+            epconf |= USBDEV_EPCCFG_EPTYPE1_INTIN;
+          }
+        else
+          {
+            epconf |= USBDEV_EPCCFG_EPTYPE0_INTOUT;
+          }
+        break;
 
-    default:
-      usbtrace(TRACE_DEVERROR(SAM_TRACEERR_BADEPTYPE),
-               eptype >> USB_EP_ATTR_XFERTYPE_SHIFT);
-      return -EINVAL;
+      default:
+        usbtrace(TRACE_DEVERROR(SAM_TRACEERR_BADEPTYPE),
+                 eptype >> USB_EP_ATTR_XFERTYPE_SHIFT);
+        return -EINVAL;
     }
 
   sam_putreg8(epconf, SAM_USBDEV_EPCFG(epno));
@@ -1614,6 +2294,10 @@ sam_ep_reserved(struct sam_usbdev_s *priv, int epno)
 }
 
 /****************************************************************************
+ * Endpoint operations
+ ****************************************************************************/
+
+/****************************************************************************
  * Name: sam_ep_configure
  *
  * Description:
@@ -1753,6 +2437,7 @@ static void sam_ep_freereq(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
       return;
     }
 #endif
+
   usbtrace(TRACE_EPFREEREQ, USB_EPNO(ep->eplog));
 
   kmm_free(privreq);
@@ -1927,6 +2612,7 @@ static int sam_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
       return -EINVAL;
     }
 #endif
+
   usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog));
 
   flags = enter_critical_section();
@@ -2005,6 +2691,10 @@ static int sam_ep_stallresume(struct usbdev_ep_s *ep, bool resume)
 }
 
 /****************************************************************************
+ * Device Controller Operations
+ ****************************************************************************/
+
+/****************************************************************************
  * Name: sam_allocep
  *
  * Description:
@@ -2084,12 +2774,13 @@ static void sam_freeep(struct usbdev_s *dev, struct usbdev_ep_s *ep)
   struct sam_ep_s *privep;
 
 #ifdef CONFIG_DEBUG_USB
-  if (!dev || !ep)
+  if (!ep || !req)
     {
       usbtrace(TRACE_DEVERROR(SAM_TRACEERR_INVALIDPARMS), 0);
-      return;
+      return -EINVAL;
     }
 #endif
+
   priv   = (struct sam_usbdev_s *)dev;
   privep = (struct sam_ep_s *)ep;
   usbtrace(TRACE_DEVFREEEP, (uint16_t)USB_EPNO(ep->eplog));
@@ -2208,10 +2899,13 @@ static int sam_selfpowered(struct usbdev_s *dev, bool selfpowered)
 }
 
 /****************************************************************************
+ * Suspend/Resume Helpers
+ ****************************************************************************/
+
+/****************************************************************************
  * Name: sam_suspend
  ****************************************************************************/
 
-#if 0 /* Not used */
 static void sam_suspend(struct sam_usbdev_s *priv)
 {
   /* Don't do anything if the device is already suspended */
@@ -2242,7 +2936,6 @@ static void sam_suspend(struct sam_usbdev_s *priv)
       sam_usb_suspend((struct usbdev_s *)priv, false);
     }
 }
-#endif
 
 /****************************************************************************
  * Name: sam_resume
@@ -2267,7 +2960,9 @@ static void sam_resume(struct sam_usbdev_s *priv)
 
       sam_enableclks();
 
-      /* Restore full power -- whatever that means for this particular board */
+      /* Restore full power -- whatever that means for this
+       * particular board
+       */
 
       sam_usb_suspend((struct usbdev_s *)priv, true);
 
@@ -2281,6 +2976,10 @@ static void sam_resume(struct sam_usbdev_s *priv)
 }
 
 /****************************************************************************
+ * Initialization/Reset
+ ****************************************************************************/
+
+/****************************************************************************
  * Name: sam_reset
  ****************************************************************************/
 
@@ -2344,6 +3043,7 @@ static void sam_reset(struct sam_usbdev_s *priv)
   /* Re-configure the USB controller in its initial, unconnected state */
 
   priv->usbdev.speed = USB_SPEED_FULL;
+  priv->usbdev.dualspeed = 0;
 
   /* Clear all pending interrupt status */
 
@@ -2364,6 +3064,10 @@ static void sam_reset(struct sam_usbdev_s *priv)
 }
 
 /****************************************************************************
+ * Interrupt Level Processing
+ ****************************************************************************/
+
+/****************************************************************************
  * Name: sam_ep0_wrstatus
  *
  * Description:
@@ -2390,6 +3094,7 @@ static void sam_ep0_wrstatus(struct sam_usbdev_s *priv,
   /* setup TX transfer */
 
   priv->eplist[0].descb[1]->addr = (uint32_t) &priv->ep0out[0];
+  uinfo("addr=%p\n", &priv->ep0out[0]);
   packetsize = priv->eplist[0].descb[1]->pktsize;
   packetsize &= ~USBDEV_PKTSIZE_BCNT_MASK;
   packetsize &= ~USBDEV_PKTSIZE_MPKTSIZE_MASK;
@@ -2467,6 +3172,8 @@ static void sam_ep0_dispatch(struct sam_usbdev_s *priv)
 
 static void sam_setdevaddr(struct sam_usbdev_s *priv, uint8_t address)
 {
+  uinfo("ENTRY address=0x%x\n", address);
+
   DEBUGASSERT(address <= 0x7f);
   if (address)
     {
@@ -2648,13 +3355,13 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
          */
 
         usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_CLEARFEATURE),
-                 priv->ctrl.type);
-
+                                 priv->ctrl.type);
         if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) !=
-            USB_REQ_RECIPIENT_ENDPOINT)
+                               USB_REQ_RECIPIENT_ENDPOINT)
           {
-            /* Let the class implementation handle all recipients (except
-             * for the endpoint recipient)
+            /* Let the class implementation handle all
+             * recipients (except for the
+             * endpoint recipient)
              */
 
             sam_ep0_dispatch(priv);
@@ -2695,10 +3402,9 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
          */
 
         usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_SETFEATURE),
-                 priv->ctrl.type);
-
+                                 priv->ctrl.type);
         if (((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) ==
-            USB_REQ_RECIPIENT_DEVICE) &&
+                                USB_REQ_RECIPIENT_DEVICE) &&
             value.w == USB_FEATURE_TESTMODE)
           {
             /* Special case recipient=device test mode */
@@ -2708,9 +3414,9 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
         else if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) !=
                  USB_REQ_RECIPIENT_ENDPOINT)
           {
-            /* The class driver handles all recipients except
-             * recipient=endpoint.
-             */
+           /* The class driver handles all recipients
+            * except recipient=endpoint
+            */
 
             sam_ep0_dispatch(priv);
             ep0result = USB_EP0SETUP_DISPATCHED;
@@ -2991,44 +3697,6 @@ static void sam_ep0_setup(struct sam_usbdev_s *priv)
 }
 
 /****************************************************************************
- * Name: sam_ctrla_write
- *
- * Description:
- *   writes value to CTRLA register some bits needs write-synchronisation
- *
- ****************************************************************************/
-
-static void sam_ctrla_write(uint8_t value)
-{
-  sam_putreg8(value, SAM_USB_CTRLA);
-
-  if (value & USB_CTRLA_SWRST)
-    {
-      /* Due to synchronization there is a delay from writing CTRLA.SWRST
-       * until the reset is complete. CTRLA.SWRST and SYNCBUSY.SWRST will
-       * both be cleared when the reset is complete.
-       */
-
-      while ((sam_getreg8(SAM_USB_CTRLA) & USB_CTRLA_SWRST) &&
-             (sam_getreg8(SAM_USB_SYNCBUSY) & USB_SYNCBUSY_SWRST))
-        ;
-
-      return;
-    }
-
-  if (value & USB_CTRLA_ENABLE)
-    {
-      /* Due to synchronization there is delay from writing CTRLA.ENABLE
-       * until the peripheral is enabled/disabled.
-       * SYNCBUSY.ENABLE will be cleared when the operation is complete.
-       */
-
-      while ((sam_getreg8(SAM_USB_SYNCBUSY) & USB_SYNCBUSY_ENABLE))
-        ;
-    }
-}
-
-/****************************************************************************
  * Name: sam_ep_trcpt_interrupt
  *
  * Description:
@@ -3129,7 +3797,8 @@ static void sam_ep_trcpt_interrupt(struct sam_usbdev_s *priv,
 
 static void sam_ep0_ctrlread(struct sam_usbdev_s *priv)
 {
-  priv->eplist[0].descb[0]->addr    = (uint32_t) &priv->ep0out[0];
+  priv->eplist[0].descb[0]->addr = (uint32_t) &priv->ep0out[0];
+  uinfo("addr=%p\n", &priv->ep0out[0]);
   priv->eplist[0].descb[0]->pktsize = USBDEV_PKTSIZE_MPKTSIZE(8) |
                                       USBDEV_PKTSIZE_SIZE_64B;
   sam_putreg8(USBDEV_EPSTATUS_BK0RDY, SAM_USBDEV_EPSTATUSCLR(0));
@@ -3259,6 +3928,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
       privep->descb[0]->stausbk &= ~USBDEV_STATUSBK_ERRORFLOW;
       usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_EPTRFAIL0), flags);
     }
+
   if ((flags & USBDEV_EPINT_TRFAIL1) != 0)
     {
       sam_putreg8(USBDEV_EPINT_TRFAIL1, SAM_USBDEV_EPINTFLAG(epno));
@@ -3330,7 +4000,7 @@ static void sam_ep_interrupt(struct sam_usbdev_s *priv, int epno)
  *
  * Description:
  *   Handle the USB interrupt.
- *   Device Mode only TODO: Host
+ *   Device Mode only
  *
  ****************************************************************************/
 
@@ -3349,7 +4019,7 @@ static int sam_usb_interrupt(int irq, void *context, void *arg)
   regval  = sam_getreg16(SAM_USBDEV_INTENSET);
   pending = isr & regval;
 
-  /* Get the set of pending endpoint interrupts */
+  /* Get the set of pending enpoint interrupts */
 
   pendingep = sam_getreg16(SAM_USBDEV_EPINTSMRY);
 
@@ -3399,18 +4069,18 @@ static int sam_usb_interrupt(int irq, void *context, void *arg)
 
   /* SOF interrupt */
 
-  else if ((pending & USBDEV_INT_SOF) != 0)
+  if ((pending & USBDEV_INT_SOF) != 0)
     {
       /* Clear the pending SOF interrupt */
 
-      sam_putreg16(SAM_TRACEINTID_SOF, SAM_USBDEV_INTFLAG);
+      sam_putreg16(USBDEV_INT_SOF, SAM_USBDEV_INTFLAG);
 
       /* TODO: do we need check frame errors FNUM.FNCERR */
     }
 
   /* Resume or wakeup.  REVISIT:  Treat the same? */
 
-  else if ((pending & (USBDEV_INT_WAKEUP | USBDEV_INT_EORSM)) != 0)
+  if ((pending & (USBDEV_INT_WAKEUP | USBDEV_INT_EORSM)) != 0)
     {
       usbtrace(TRACE_INTDECODE(SAM_TRACEINTID_WAKEUP), (uint16_t)pending);
       sam_resume(priv);
@@ -3420,12 +4090,11 @@ static int sam_usb_interrupt(int irq, void *context, void *arg)
       sam_putreg16(USBDEV_INT_WAKEUP | USBDEV_INT_EORSM |
                    USBDEV_INT_SUSPEND, SAM_USBDEV_INTFLAG);
 
-      /* Disable wakeup and endofresume Enable suspend interrupt */
+      /* Disable wakup and endofresume Enable suspend interrupt */
 
-      sam_putreg16(USBDEV_INT_WAKEUP | USBDEV_INT_EORSM,
-                   SAM_USBDEV_INTENCLR);
-      sam_putreg16(USBDEV_INT_SUSPEND,
-                   SAM_USBDEV_INTENSET);
+      sam_putreg16(USBDEV_INT_WAKEUP |
+                   USBDEV_INT_EORSM, SAM_USBDEV_INTENCLR);
+      sam_putreg16(USBDEV_INT_SUSPEND, SAM_USBDEV_INTENSET);
     }
 
   /* End of Reset. Set by hardware when an End Of Reset has been
@@ -3447,99 +4116,41 @@ static int sam_usb_interrupt(int irq, void *context, void *arg)
       /* REVISIT: Set the device speed Why here ?? */
 
       priv->usbdev.speed = USB_SPEED_FULL;
+      priv->usbdev.dualspeed = 0;
     }
 
-#if 0
-  /* for DEBUG help: check for pending unhandled irq's */
-
-  isr = sam_getreg16(SAM_USBDEV_INTFLAG);
-  if (isr)
-    {
-      uwarn("WARNING: Unhandled:0x%X\n", isr);
-    }
-
-  pendingep = sam_getreg16(SAM_USBDEV_EPINTSMRY);
-  if (pendingep)
-    {
-      uwarn("WARNING: Unhandled_EP:0x%X\n", pendingep);
-    }
-#endif
-
   return OK;
 }
 
-void arm_usbuninitialize(void)
-{
-  uinfo("arm_usbuninitialize()\n");
-}
-
-void arm_usbinitialize(void)
-{
-  /* For now there is only one USB controller, but we will always refer to
-   * it using a pointer to make any future ports to multiple USB controllers
-   * easier.
-   */
+/****************************************************************************
+ * Endpoint Helpers
+ ****************************************************************************/
 
-  struct sam_usbdev_s *priv = &g_usbd;
+/****************************************************************************
+ * Name: sam_ep_reset
+ *
+ * Description:
+ *   Reset and disable one endpoints.
+ *
+ ****************************************************************************/
 
-  usbtrace(TRACE_DEVINIT, 0);
+static void sam_ep_reset(struct sam_usbdev_s *priv, uint8_t epno)
+{
+  struct sam_ep_s *privep = &priv->eplist[epno];
 
-  /* Software initialization */
+  /* Disable endpoint interrupts */
 
-  sam_sw_setup(priv);
+  sam_putreg8(0x7f, SAM_USBDEV_EPINTENCLR(epno));
+  sam_putreg8(0x7f, SAM_USBDEV_EPINTFLAG(epno));
 
-  /* Power up and initialize USB controller.  Interrupt from the USB
-   * controller is initialized here, but will not be enabled at the AIC
-   * until the class driver is installed.
+  /* Cancel any queued requests.  Since they are cancelled with status
+   * -ESHUTDOWN, then will not be requeued until the configuration is reset.
+   * NOTE:  This should not be necessary... the CLASS_DISCONNECT above
+   * should result in the class implementation calling sam_ep_disable
+   * for each of its configured endpoints.
    */
 
-  sam_hw_setup(priv);
-
-  /* Attach USB controller interrupt handlers.  The hardware will not be
-   * initialized and interrupts will not be enabled until the class device
-   * driver is bound.  Getting the IRQs here only makes sure that we have
-   * them when we need them later.
-   */
-
-  if (irq_attach(SAM_IRQ_USB, sam_usb_interrupt, priv) != 0)
-    {
-      usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
-               (uint16_t)SAM_IRQ_USB);
-      goto errout;
-    }
-
-  uinfo("OK\n");
-  return;
-
-errout:
-  arm_usbuninitialize();
-}
-
-/****************************************************************************
- * Name: sam_ep_reset
- *
- * Description:
- *   Reset and disable one endpoints.
- *
- ****************************************************************************/
-
-static void sam_ep_reset(struct sam_usbdev_s *priv, uint8_t epno)
-{
-  struct sam_ep_s *privep = &priv->eplist[epno];
-
-  /* Disable endpoint interrupts */
-
-  sam_putreg8(0x7e, SAM_USBDEV_EPINTENCLR(epno));
-  sam_putreg8(0x7e, SAM_USBDEV_EPINTFLAG(epno));
-
-  /* Cancel any queued requests.  Since they are cancelled with status
-   * -ESHUTDOWN, then will not be requeued until the configuration is reset.
-   * NOTE:  This should not be necessary... the CLASS_DISCONNECT above
-   * should result in the class implementation calling sam_ep_disable
-   * for each of its configured endpoints.
-   */
-
-  sam_req_cancel(privep, -ESHUTDOWN);
+  sam_req_cancel(privep, -ESHUTDOWN);
 
   /* Reset endpoint status */
 
@@ -3575,10 +4186,10 @@ static void sam_epset_reset(struct sam_usbdev_s *priv, uint16_t epset)
 
       if ((epset & bit) != 0)
         {
-           /* Yes.. reset and disable it */
+          /* Yes.. reset and disable it */
 
-           sam_ep_reset(priv, epno);
-           epset &= ~bit;
+          sam_ep_reset(priv, epno);
+          epset &= ~bit;
         }
     }
 }
@@ -3721,7 +4332,7 @@ static int sam_pullup(struct usbdev_s *dev, bool enable)
 
   /* Enable/disable the USB pull-up resistor */
 
-  regval = sam_getreg8(SAM_USBDEV_CTRLB);
+  regval = sam_getreg16(SAM_USBDEV_CTRLB);
 
   if (enable)
     {
@@ -3743,32 +4354,15 @@ static int sam_pullup(struct usbdev_s *dev, bool enable)
         }
     }
 
-  sam_putreg8((uint8_t)regval, SAM_USBDEV_CTRLB);
+  sam_putreg16((uint16_t)regval, SAM_USBDEV_CTRLB);
 
   return OK;
 }
 
 /****************************************************************************
- * Name: sam_enableclks
- ****************************************************************************/
-
-static void sam_enableclks(void)
-{
-  sam_ahb_usb_enableperiph();
-  sam_apb_usb_enableperiph();
-  sam_gclk_chan_enable(GCLK_CHAN_USB, BOARD_USB_GCLKGEN, false);
-}
-
-/****************************************************************************
- * Name: sam_disableclks
+ * Initialization/Reset
  ****************************************************************************/
 
-static void sam_disableclks(void)
-{
-  sam_gclk_chan_disable(GCLK_CHAN_USB);
-  sam_apb_usb_disableperiph();
-}
-
 /****************************************************************************
  * Name: sam_hw_setup
  ****************************************************************************/
@@ -3783,6 +4377,11 @@ static void sam_hw_setup(struct sam_usbdev_s *priv)
   uint8_t calib_transp;
   uint8_t calib_trim;
 
+  /* Set up the USB DP/DM pins */
+
+  sam_portconfig(PORT_USB_DP);
+  sam_portconfig(PORT_USB_DM);
+
   /* To use the USB, the programmer must first configure the USB clock
    * input,
    */
@@ -3792,23 +4391,37 @@ static void sam_hw_setup(struct sam_usbdev_s *priv)
   /* full reset USB */
 
   sam_ctrla_write(USB_CTRLA_SWRST);
+  while (sam_getreg32(SAM_USB_SYNCBUSY) == USB_SYNCBUSY_SWRST);
+
+  /* Enable USB core */
+
+  sam_ctrla_write(USB_CTRLA_ENABLE | USB_CTRLA_RUNSTBY |
+                                     USB_CTRLA_MODE_DEVICE);
+  while (sam_getreg32(SAM_USB_SYNCBUSY) == USB_SYNCBUSY_ENABLE);
 
   /* Load USB factory calibration values from NVRAM */
 
   calib_transn = (getreg32(SAM_FUSES_USBTRANSN_ADDR) &
                   SAM_FUSES_USBTRANSN_MASK) >> SAM_FUSES_USBTRANSN_SHIFT;
+  if (calib_transn == 0 || calib_transn == 0x1f)
+    calib_transn = 0x9;
 
   calib_transp = (getreg32(SAM_FUSES_USBTRANSP_ADDR) &
                   SAM_FUSES_USBTRANSP_ADDR) >> SAM_FUSES_USBTRANSP_SHIFT;
+  if (calib_transp == 0 || calib_transp == 0x1f)
+    calib_transp = 0x19;
 
   calib_trim   = (getreg32(SAM_FUSES_USBTRIM_ADDR) &
                   SAM_FUSES_USBTRIM_MASK) >> SAM_FUSES_USBTRIM_SHIFT;
+  if (calib_trim == 0 || calib_trim == 0x7)
+    calib_trim = 0x6;
 
   padcalib     = USB_PADCAL_TRANSP(calib_transp) |
                  USB_PADCAL_TRANSN(calib_transn) |
                  USB_PADCAL_TRIM(calib_trim);
 
-  sam_putreg32(padcalib, SAM_USB_PADCAL);
+  sam_putreg16(padcalib, SAM_USB_PADCAL);
+  uinfo("PADCAL: 0x%x\n", padcalib);
 
   /* set config
    * NREPLY = Any transaction to endpoint 0 will be ignored except SETUP
@@ -3824,20 +4437,6 @@ static void sam_hw_setup(struct sam_usbdev_s *priv)
 
   sam_putreg16(regval, SAM_USBDEV_CTRLB);
 
-  /* Enable USB core */
-
-#ifdef CONFIG_USBDEV
-  sam_ctrla_write(USB_CTRLA_ENABLE | USB_CTRLA_MODE_DEVICE);
-#endif
-#ifdef CONFIG_USBHOST
-  sam_ctrla_write(USB_CTRLA_ENABLE | USB_CTRLA_MODE_HOST);
-#endif
-
-  /* Set up the USB DP/DM pins */
-
-  sam_portconfig(PORT_USB_DP);
-  sam_portconfig(PORT_USB_DM);
-
   /* Reset and disable endpoints */
 
   sam_epset_reset(priv, SAM_EPSET_ALL);
@@ -3985,6 +4584,7 @@ int usbdev_register(struct usbdevclass_driver_s *driver)
   struct sam_usbdev_s *priv = &g_usbd;
   int ret;
 
+  uinfo("driver: 0x%x\n", driver);
   usbtrace(TRACE_DEVREGISTER, 0);
 
 #ifdef CONFIG_DEBUG_USB
@@ -4020,6 +4620,9 @@ int usbdev_register(struct usbdevclass_driver_s *driver)
 
       sam_hw_setup(priv);
       up_enable_irq(SAM_IRQ_USB);
+      up_enable_irq(SAM_IRQ_USBSOF);
+      up_enable_irq(SAM_IRQ_USBTRCPT0);
+      up_enable_irq(SAM_IRQ_USBTRCPT1);
 
       /* Enable EORST irq */
 
@@ -4032,6 +4635,7 @@ int usbdev_register(struct usbdevclass_driver_s *driver)
 
       sam_pullup(&priv->usbdev, true);
       priv->usbdev.speed = USB_SPEED_FULL;
+      priv->usbdev.dualspeed = 0;
     }
 
   return ret;
@@ -4081,6 +4685,9 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
   /* Disable USB controller interrupts (but keep them attached) */
 
   up_disable_irq(SAM_IRQ_USB);
+  up_disable_irq(SAM_IRQ_USBSOF);
+  up_disable_irq(SAM_IRQ_USBTRCPT0);
+  up_disable_irq(SAM_IRQ_USBTRCPT1);
 
   /* Put the hardware in an inactive state.  Then bring the hardware back up
    * in the initial state.  This is essentially the same state as we were
@@ -4100,4 +4707,4097 @@ int usbdev_unregister(struct usbdevclass_driver_s *driver)
   return OK;
 }
 
-#endif /* CONFIG_USBDEV && CONFIG_SAMD5E5_USB */
+void sam_usb_suspend(FAR struct usbdev_s *dev, bool resume)
+{
+}
+
+void arm_usbuninitialize(void)
+{
+  uinfo("arm_usbuninitialize()\n");
+}
+
+void arm_usbinitialize(void)
+{
+  /* For now there is only one USB controller, but we will always refer to
+   * it using a pointer to make any future ports to multiple USB controllers
+   * easier.
+   */
+
+  struct sam_usbdev_s *priv = &g_usbd;
+
+  uinfo("INIT\n");
+  usbtrace(TRACE_DEVINIT, 0);
+
+  /* Software initialization */
+
+  sam_sw_setup(priv);
+
+  /* Power up and initialize USB controller.  Interrupt from the USB
+   * controller is initialized here, but will not be enabled at the AIC
+   * until the class driver is installed.
+   */
+
+  sam_hw_setup(priv);
+
+  /* Attach USB controller interrupt handlers.  The hardware will not be
+   * initialized and interrupts will not be enabled until the class device
+   * driver is bound.  Getting the IRQs here only makes sure that we have
+   * them when we need them later.
+   */
+
+  if (irq_attach(SAM_IRQ_USB, sam_usb_interrupt, priv) != 0)
+    {
+      usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                     (uint16_t)SAM_IRQ_USB);
+      goto errout;
+    }
+
+  if (irq_attach(SAM_IRQ_USBSOF, sam_usb_interrupt, priv) != 0)
+    {
+      usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                  (uint16_t)SAM_IRQ_USBSOF);
+      goto errout;
+    }
+
+  if (irq_attach(SAM_IRQ_USBTRCPT0, sam_usb_interrupt, priv) != 0)
+    {
+      usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                  (uint16_t)SAM_IRQ_USBTRCPT0);
+      goto errout;
+    }
+
+  if (irq_attach(SAM_IRQ_USBTRCPT1, sam_usb_interrupt, priv) != 0)
+    {
+      usbtrace(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                  (uint16_t)SAM_IRQ_USBTRCPT1);
+      goto errout;
+    }
+
+  return;
+
+errout:
+  arm_usbuninitialize();
+}
+#endif /* CONFIG_USBDEV */
+
+#ifdef CONFIG_USBHOST
+
+/****************************************************************************
+ * Name: sam_getle16
+ *
+ * Description:
+ *   Get a (possibly unaligned) 16-bit little endian value.
+ *
+ ****************************************************************************/
+
+static inline uint16_t sam_getle16(const uint8_t *val)
+{
+  return (uint16_t)val[1] << 8 | (uint16_t)val[0];
+}
+
+/****************************************************************************
+ * Name: sam_add_sof_user
+ *
+ * Description:
+ *   Add one SOF IRQ user and enable SOF interrupt
+ *
+ ****************************************************************************/
+
+static void sam_add_sof_user(struct sam_usbhost_s *priv)
+{
+  priv->n_sof_user++;
+  sam_putreg16(USBHOST_INT_HSOF, SAM_USBHOST_INTENSET);
+}
+
+/****************************************************************************
+ * Name: sam_pipe_alloc
+ *
+ * Description:
+ *   Allocate a pipe.
+ *
+ ****************************************************************************/
+
+static int sam_pipe_alloc(FAR struct sam_usbhost_s *priv)
+{
+  int idx;
+
+  /* Search the table of pipes */
+
+  for (idx = 0; idx < SAM_USB_NENDPOINTS; idx++)
+    {
+      /* Is this pipe available? */
+
+      if (!priv->pipelist[idx].inuse)
+        {
+          /* Yes... make it "in use" and return the index */
+
+          priv->pipelist[idx].inuse = true;
+          return idx;
+        }
+    }
+
+  /* All of the pipes are "in-use" */
+
+  return -EBUSY;
+}
+
+/****************************************************************************
+ * Name: sam_pipe_free
+ *
+ * Description:
+ *   Free a previoiusly allocated pipe.
+ *
+ ****************************************************************************/
+
+static void sam_pipe_free(FAR struct sam_usbhost_s *priv, int idx)
+{
+  FAR struct sam_pipe_s *pipe = &priv->pipelist[idx];
+
+  uinfo("pipe%d\n", idx);
+  DEBUGASSERT((unsigned)idx < SAM_USB_NENDPOINTS);
+
+  /* Halt the pipe */
+
+  sam_putreg8(0, SAM_USBHOST_PCFG(pipe->idx));
+
+  /* Mark the pipe available */
+
+  priv->pipelist[idx].inuse = false;
+}
+
+/* Look up table PSIZE -> size of bytes */
+
+static const uint16_t psize_2_size[] =
+{
+  8,
+  16,
+  32,
+  64,
+  128,
+  256,
+  512,
+  1024
+};
+
+/****************************************************************************
+ * Name: sam_get_psize
+ *
+ * Description:
+ *   Convert bank size of bytes to PIPCFG.PSIZE -> size Size of bytes
+ *
+ ****************************************************************************/
+
+int8_t sam_get_psize(uint16_t size)
+{
+  uint8_t i;
+
+  for (i = 0; i < sizeof(psize_2_size) / sizeof(uint16_t); i++)
+    {
+      /* Size should be exactly PSIZE values */
+
+      if (size <= psize_2_size[i])
+      return i;
+    }
+
+  return 7;
+}
+
+/****************************************************************************
+ * Name: sam_pipe_configure
+ *
+ * Description:
+ *   Configure or re-configure a host pipe.  Host pipes are configured
+ *   when pipe is allocated and EP0 (only) is re-configured with the
+ *   max packet size or device address changes.
+ *
+ ****************************************************************************/
+
+static void sam_pipe_configure(FAR struct sam_usbhost_s *priv, int idx)
+{
+  FAR struct sam_pipe_s *pipe = &priv->pipelist[idx];
+
+  /* Clear any old pending interrupts for this host pipe. */
+
+  sam_putreg8(0x3f, SAM_USBHOST_PINTFLAG(pipe->idx));
+
+  /* Enable pipe interrupts required for transfers on this pipe. */
+
+  switch (pipe->eptype)
+    {
+    case USB_EP_ATTR_XFER_CONTROL:
+    case USB_EP_ATTR_XFER_BULK:
+      {
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+        uint16_t intrace;
+        uint16_t outtrace;
+
+        /* Determine the definitive trace ID to use below */
+
+        if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL)
+          {
+            intrace  = SAM_VTRACE2_PIPECONF_CTRL_IN;
+            outtrace = SAM_VTRACE2_PIPECONF_CTRL_OUT;
+          }
+        else
+          {
+            intrace  = SAM_VTRACE2_PIPECONF_BULK_IN;
+            outtrace = SAM_VTRACE2_PIPECONF_BULK_OUT;
+          }
+
+        /* Interrupts required for CTRL and BULK endpoints */
+
+        /* Additional setting for IN/OUT endpoints */
+
+        if (pipe->in)
+          {
+            usbhost_vtrace2(intrace, idx, pipe->epno);
+          }
+        else
+          {
+            usbhost_vtrace2(outtrace, idx, pipe->epno);
+          }
+#endif
+      }
+      break;
+
+    case USB_EP_ATTR_XFER_INT:
+      {
+        /* Interrupts required for INTR endpoints */
+
+        /* Additional setting for IN endpoints */
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+        if (pipe->in)
+          {
+            usbhost_vtrace2(SAM_VTRACE2_PIPECONF_INTR_IN, idx, pipe->epno);
+          }
+        else
+          {
+            usbhost_vtrace2(SAM_VTRACE2_PIPECONF_INTR_OUT, idx, pipe->epno);
+          }
+#endif
+      }
+      break;
+
+    case USB_EP_ATTR_XFER_ISOC:
+      {
+        /* Interrupts required for ISOC endpoints */
+
+        /* Additional setting for IN endpoints */
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+        if (pipe->in)
+          {
+            usbhost_vtrace2(SAM_VTRACE2_PIPECONF_ISOC_IN, idx, pipe->epno);
+          }
+        else
+          {
+            usbhost_vtrace2(SAM_VTRACE2_PIPECONF_ISOC_OUT, idx, pipe->epno);
+          }
+#endif
+      }
+      break;
+    }
+
+  /* Write the pipe configuration */
+
+  pipe->descb[0]->ctrlpipe = USBHOST_CTRLPIPE_PDADDR(pipe->funcaddr) |
+                    USBHOST_CTRLPIPE_PEPNUM(pipe->epno & USB_EPNO_MASK);
+  pipe->descb[0]->pktsize = USBHOST_PKTSIZE_SIZE(
+                            sam_get_psize(pipe->maxpacket));
+
+  sam_putreg8(USBHOST_PCFG_PTYPE(pipe->eptype + 1) |
+             (pipe->eptype == USB_EP_ATTR_XFER_CONTROL ?
+                              USBHOST_PCFG_PTOKEN_SETUP :
+                              (pipe->in ? USBHOST_PCFG_PTOKEN_IN :
+                              USBHOST_PCFG_PTOKEN_OUT)),
+                              SAM_USBHOST_PCFG(pipe->idx));
+
+  sam_putreg8(pipe->interval, SAM_USBHOST_BINTERVAL(pipe->idx));
+
+  /* Enable general error and stall interrupts */
+
+  pipe->pipestatus_general = 0;
+  sam_putreg8((USBHOST_PINTFLAG_TRFAIL |
+               USBHOST_PINTFLAG_PERR   |
+               USBHOST_PINTFLAG_STALL), SAM_USBHOST_PINTFLAG(pipe->idx));
+
+  sam_putreg8((USBHOST_PINTFLAG_TRFAIL |
+               USBHOST_PINTFLAG_PERR   |
+               USBHOST_PINTFLAG_STALL), SAM_USBHOST_PINTENSET(pipe->idx));
+
+  pipe->pipestate_general = USB_H_PIPE_S_IDLE;
+
+  uinfo("pipe%d pktsize=0x%x ctrl=0x%x status=0x%x\n", pipe->idx,
+                                                 pipe->descb[0]->pktsize,
+                                                 pipe->descb[0]->ctrlpipe,
+                                                 pipe->descb[0]->statuspipe);
+}
+
+/****************************************************************************
+ * Name: sam_pipe_waitsetup
+ *
+ * Description:
+ *   Set the request for the transfer complete event well
+ *   BEFORE enabling the transfer (as soon as we are
+ *   absolutely committed to the to avoid transfer).
+ *   We do this to minimize race conditions.
+ *   This logic would have to be expanded
+ *   if we want to have more than one packet in flight at a time!
+ *
+ * Assumptions:
+ *  Called from a normal thread context BEFORE the transfer has been started.
+ *
+ ****************************************************************************/
+
+static int sam_pipe_waitsetup(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe)
+{
+  irqstate_t flags = enter_critical_section();
+  int        ret   = -ENODEV;
+
+  DEBUGASSERT(priv != NULL && pipe != NULL);
+
+  /* Is the device still connected? */
+
+  if (priv->connected)
+    {
+      /* Yes.. then set waiter to indicate that we expect
+       * to be informed when either (1) the device is disconnected,
+       * or (2) the transfer completed.
+       */
+
+      pipe->waiter   = true;
+  #ifdef CONFIG_USBHOST_ASYNCH
+      pipe->callback = NULL;
+      pipe->arg      = NULL;
+  #endif
+      ret            = OK;
+    }
+
+  leave_critical_section(flags);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: sam_pipe_asynchsetup
+ *
+ * Description:
+ *   Set the request for the transfer complete event well BEFORE enabling the
+ *   transfer.
+ *   We do this to minimize race conditions.
+ *   This logic would have to be expanded
+ *   if we want to have more than one packet in flight at a time!
+ *
+ * Assumptions:
+ *   Might be called from the level of an interrupt handler
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_ASYNCH
+static int sam_pipe_asynchsetup(FAR struct sam_usbhost_s *priv,
+                                FAR struct sam_pipe_s *pipe,
+                                usbhost_asynch_t callback, FAR void *arg)
+{
+  irqstate_t flags = enter_critical_section();
+  int ret = -ENODEV;
+
+  DEBUGASSERT(priv != NULL && pipe != NULL);
+
+  /* Is the device still connected? */
+
+  if (priv->connected)
+    {
+      pipe->waiter   = false;      /* No waiter */
+      pipe->callback = callback;
+      pipe->arg      = arg;
+      ret            = OK;
+    }
+
+  leave_critical_section(flags);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_pipe_wait
+ *
+ * Description:
+ *   Wait for a transfer on a pipe to complete.
+ *
+ * Assumptions:
+ *   Called from a normal thread context
+ *
+ ****************************************************************************/
+
+static int sam_pipe_wait(FAR struct sam_usbhost_s *priv,
+                         FAR struct sam_pipe_s *pipe)
+{
+  irqstate_t flags;
+  int ret;
+
+  /* Disable interrupts so that the following operations will be atomic. On
+   * the host global interrupt needs to be disabled. However, here we disable
+   * all interrupts to exploit that fact that interrupts will be re-enabled
+   * while we wait.
+   */
+
+  flags = enter_critical_section();
+
+  /* Loop, testing for an end of transfer condition.  The pipe 'result'
+   * was set to EBUSY and 'waiter' was set to the pipe expecting the
+   * response before the transfer was started; 'waiter' will be nullified
+   * and 'result' will be set appropriately when the transfer is completed.
+   */
+
+  do
+    {
+      /* Wait for the transfer to complete.  NOTE the transfer may already
+       * completed before we get here or the transfer may complete while we
+       * wait here.
+       */
+
+      ret = nxsem_wait(&pipe->waitsem);
+
+      /* nxsem_wait should succeed.  But it is possible that we could be
+       * awakened by a signal too.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (pipe->waiter);
+
+  /* The transfer is complete re-enable interrupts and return the result */
+
+  ret = -(int)pipe->result;
+  leave_critical_section(flags);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: sam_pipe_wakeup
+ *
+ * Description:
+ *   A pipe transfer has completed... wakeup any threads waiting for the
+ *   transfer to complete.
+ *
+ * Assumptions:
+ *   This function is called from the transfer complete interrupt handler for
+ *   the pipe.  Interrupts are disabled.
+ *
+ ****************************************************************************/
+
+static void sam_pipe_wakeup(FAR struct sam_usbhost_s *priv,
+                            FAR struct sam_pipe_s *pipe)
+{
+  /* Is the transfer complete? */
+
+  if (pipe->result != EBUSY)
+    {
+      /* Is there a thread waiting for this transfer to complete? */
+
+      if (pipe->waiter)
+        {
+#ifdef CONFIG_USBHOST_ASYNCH
+          /* Yes.. there should not also be a callback scheduled */
+
+          DEBUGASSERT(pipe->callback == NULL);
+#endif
+          /* Wake'em up! */
+
+          usbhost_vtrace2(pipe->in ? SAM_VTRACE2_PIPEWAKEUP_IN :
+                                     SAM_VTRACE2_PIPEWAKEUP_OUT,
+                          pipe->epno, pipe->result);
+
+          sam_givesem(&pipe->waitsem);
+          pipe->waiter = false;
+        }
+
+     #ifdef CONFIG_USBHOST_ASYNCH
+      /* No.. is an asynchronous callback expected
+       * when the transfer completes?
+       */
+
+      else if (pipe->callback)
+        {
+          /* Handle continuation of IN/OUT pipes */
+
+          if (pipe->in)
+            {
+              sam_in_next(priv, pipe);
+            }
+          else
+            {
+              sam_out_next(priv, pipe);
+            }
+        }
+     #endif
+    }
+}
+
+/****************************************************************************
+ * Name: sam_ctrlep_alloc
+ *
+ * Description:
+ *   Allocate a container and pipes for control pipe.
+ *
+ * Input Parameters:
+ *   priv - The private USB host driver state.
+ *   epdesc - Describes the endpoint to be allocated.
+ *   ep - A memory location provided by the caller in which to receive the
+ *      allocated endpoint descriptor.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_ctrlep_alloc(FAR struct sam_usbhost_s *priv,
+                            FAR const struct usbhost_epdesc_s *epdesc,
+                            FAR usbhost_ep_t *ep)
+{
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct sam_pipe_s *pipe;
+  int idx;
+
+  /* Sanity check.  NOTE that this method should only be called if
+   * a device is connected (because we need a valid low speed indication).
+   */
+
+  DEBUGASSERT(epdesc->hport != NULL);
+  hport = epdesc->hport;
+
+  idx = sam_pipe_alloc(priv);
+  if (idx < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_PIPEALLOC_FAIL, -idx);
+      uerr("ERROR: Failed to allocate a host pipe\n");
+      return -ENOMEM;
+    }
+
+  pipe            = &priv->pipelist[idx];
+  pipe->epno      = epdesc->addr & USB_EPNO_MASK;
+  pipe->in        = false;
+  pipe->eptype    = USB_EP_ATTR_XFER_CONTROL;
+  pipe->funcaddr  = hport->funcaddr;
+  pipe->speed     = hport->speed;
+  pipe->interval  = 0;
+  pipe->maxpacket = SAM_EP0_MAXPACKET;
+
+  /* Configure control OUT pipe */
+
+  pipe->pipestate_general = USB_H_PIPE_S_CFG;
+  sam_pipe_configure(priv, idx);
+
+  /* Return a pointer to the control pipe container as the pipe "handle" */
+
+  *ep = (usbhost_ep_t)idx;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_xfrep_alloc
+ *
+ * Description:
+ *   Allocate and configure one unidirectional pipe.
+ *
+ * Input Parameters:
+ *   priv - The private USB host driver state.
+ *   epdesc - Describes the endpoint to be allocated.
+ *   ep - A memory location provided by the caller in which to receive the
+ *      allocated endpoint descriptor.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated
+ *   errno value is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_xfrep_alloc(FAR struct sam_usbhost_s *priv,
+                           FAR const struct usbhost_epdesc_s *epdesc,
+                           FAR usbhost_ep_t *ep)
+{
+  struct usbhost_hubport_s *hport;
+  FAR struct sam_pipe_s *pipe;
+  int idx;
+
+  /* Sanity check.  NOTE that this method should only be called if a device
+   * is connected (because we need a valid low speed indication).
+   */
+
+  DEBUGASSERT(epdesc->hport != NULL);
+  hport = epdesc->hport;
+  DEBUGASSERT(hport != NULL);
+
+  /* Allocate a host pipe for the endpoint */
+
+  idx = sam_pipe_alloc(priv);
+  if (idx < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_PIPEALLOC_FAIL, -idx);
+      uerr("ERROR: Failed to allocate a host pipe\n");
+      return -ENOMEM;
+    }
+
+  /* Decode the endpoint descriptor to initialize the pipe data structures.
+   * Note:  Here we depend on the fact that the endpoint point type is
+   * encoded in the same way in the endpoint descriptor as it is in the OTG
+   * HS hardware.
+   */
+
+  pipe            = &priv->pipelist[idx];
+  pipe->epno      = epdesc->addr & USB_EPNO_MASK;
+  pipe->in        = epdesc->in;
+  pipe->eptype    = epdesc->xfrtype;
+  pipe->funcaddr  = hport->funcaddr;
+  pipe->speed     = hport->speed;
+  pipe->interval  = epdesc->interval;
+  pipe->maxpacket = epdesc->mxpacketsize;
+  pipe->pipestate_general = pipe->in ? USB_H_PIPE_S_DATI : USB_H_PIPE_S_DATO;
+
+  /* Then configure the endpoint */
+
+  sam_pipe_configure(priv, idx);
+
+  /* Return the endpoint number as the endpoint "handle" */
+
+  *ep = (usbhost_ep_t)idx;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_transfer_terminate
+ *
+ * Description:
+ *   Terminate a IN or OUT transfer due to an error (or because a zero-
+ *   length OUT transfer occurred).
+ *
+ * Returned value:
+ *   OK     - Transfer successful
+ *  -EAGAIN - If devices NAKs the transfer.
+ *  -EPERM  - If the endpoint stalls
+ *  -BUSY   - The transfer is not complete
+ *  -EIO    - Other, undecoded error
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void sam_transfer_terminate(FAR struct sam_usbhost_s *priv,
+                                   FAR struct sam_pipe_s *pipe,
+                                   int result)
+{
+  /* Wake up any waiters for the end of transfer event */
+
+  sam_pipe_wakeup(priv, pipe);
+
+  if (pipe->pipestate_general < USB_H_PIPE_S_SETUP ||
+      pipe->pipestate_general > USB_H_PIPE_S_STATO)
+  return; /* Not busy */
+
+  if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL)
+    {
+      if (priv->n_ctrl_req_user)
+        priv->n_ctrl_req_user--;
+      if (priv->n_sof_user)
+        priv->n_sof_user--;
+    }
+
+  pipe->pipestate_general  = USB_H_PIPE_S_IDLE;
+  pipe->pipestatus_general = result;
+
+  /* Suspend delayed due to control request: start it */
+
+  if (priv->n_ctrl_req_user == 0 && priv->suspend_start < 0)
+    {
+      uint8_t i;
+      if (priv->n_ctrl_req_user)
+        {
+          /* Delay suspend after setup requests */
+
+          priv->suspend_start = -1;
+          return;
+        }
+
+      /* Save pipe freeze states and freeze pipes */
+
+      priv->pipes_unfreeze = 0;
+      for (i = 0; i < SAM_USB_NENDPOINTS; i++)
+        {
+          /* Skip frozen pipes */
+
+          if ((sam_getreg16(SAM_USBHOST_PSTATUS(i)) &
+               USBHOST_PSTATUS_PFREEZE) >> 4)
+            continue;
+
+          /* Log unfrozen pipes */
+
+          priv->pipes_unfreeze |= 1 << i;
+
+          /* Freeze it to suspend */
+
+          sam_putreg8(USBHOST_PSTATUS_PFREEZE, SAM_USBHOST_PSTATUSSET(i));
+        }
+
+      /* Wait 3 SOFs before entering in suspend state */
+
+      sam_add_sof_user(priv); /* SOF user: delayed suspend */
+      priv->suspend_start = 3;
+    }
+}
+
+static void sam_transfer_abort(FAR struct sam_usbhost_s *priv,
+                               FAR struct sam_pipe_s *pipe,
+                               int code)
+{
+  /* Stop transfer */
+
+  sam_putreg8(USBHOST_PSTATUS_PFREEZE, SAM_USBHOST_PSTATUSSET(pipe->idx));
+
+  /* Update byte count */
+
+  if (pipe->in == 0)
+    pipe->count += (pipe->descb[0]->pktsize &
+                    USBHOST_PKTSIZE_MPKTSIZE_MASK) >>
+                    USBHOST_PKTSIZE_MPKTSIZE_SHIFT;
+
+  /* Disable interrupts */
+
+  sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+               USBHOST_PINTFLAG_TRCPT1),
+               SAM_USBHOST_PINTENCLR(pipe->idx));
+
+  sam_transfer_terminate(priv, pipe, code);
+}
+
+/****************************************************************************
+ * Name: sam_send_continue
+ *
+ * Description:
+ *   Continue the send operation started by sam_send_start().
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void sam_send_continue(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe)
+{
+  uint8_t * src;
+  uint32_t size;
+  uint32_t count;
+  uint32_t n_tx = 0;
+  uint32_t n_remain;
+
+  if (pipe->pipestate_general == USB_H_PIPE_S_STATO)
+    {
+      /* Control status : ZLP OUT done */
+
+      sam_transfer_terminate(priv, pipe, OK);
+      return;
+    }
+
+  else if (pipe->pipestate_general != USB_H_PIPE_S_DATO)
+    return;
+
+  /* Reset packet timeout for control pipes */
+
+  if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL)
+    pipe->pkt_timeout = USB_CTRL_DPKT_TIMEOUT;
+
+  n_tx = (pipe->descb[0]->pktsize & USBHOST_PKTSIZE_BCNT_MASK) >>
+                                    USBHOST_PKTSIZE_BCNT_SHIFT;
+
+  /* ZLP cleared if it's short packet */
+
+  if (n_tx < pipe->maxpacket)
+    pipe->zlp = 0;
+
+  src = pipe->data;
+  size = pipe->size;
+  count = pipe->count;
+
+  if (n_tx)
+    {
+      count += n_tx;
+      pipe->count = count;
+    }
+
+  n_remain = size - count;
+
+  /* Now set n_tx to next transfer size */
+
+  if (n_remain > 16320)
+    n_tx = 16320;
+  else
+    n_tx = n_remain;
+
+  /* For Control, all data is done, to STATUS stage */
+
+  if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL &&
+                     pipe->count >= pipe->size &&
+                     !pipe->zlp)
+    {
+      pipe->pipestate = USB_H_PIPE_S_STATI;
+
+      /* Start IN ZLP request */
+
+      pipe->pkt_timeout = USB_CTRL_STAT_TIMEOUT;
+      sam_putreg8(USBHOST_PSTATUS_DTGL, SAM_USBHOST_PSTATUSSET(pipe->idx));
+      sam_recv_restart(priv, pipe);
+      return;
+    }
+
+  /* All transfer done, including ZLP */
+
+  if (count >= size && !pipe->zlp)
+    {
+      /* At least one bank there, wait to freeze pipe */
+
+      if (pipe->eptype != USB_EP_ATTR_XFER_CONTROL)
+        {
+          /* Busy interrupt when all banks are empty */
+
+          sam_transfer_terminate(priv, pipe, OK);
+        }
+      else /* No busy interrupt for control EPs */
+        {
+        }
+    }
+  else
+    {
+      sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+                   USBHOST_PINTFLAG_TRCPT1),
+                  SAM_USBHOST_PINTFLAG(pipe->idx));
+
+      sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+                   USBHOST_PINTFLAG_TRCPT1),
+                  SAM_USBHOST_PINTENSET(pipe->idx));
+
+      pipe->descb[0]->addr = (uint32_t)&src[count];
+      pipe->descb[0]->pktsize &= ~(USBHOST_PKTSIZE_MPKTSIZE_MASK |
+                                   USBHOST_PKTSIZE_BCNT_MASK);
+      pipe->descb[0]->pktsize |= USBHOST_PKTSIZE_BCNT(n_remain);
+
+      /* Send the OUT token */
+
+      sam_modifyreg8(USBHOST_PCFG_PTOKEN_MASK,
+                     USBHOST_PCFG_PTOKEN_OUT,
+                     SAM_USBHOST_PCFG(pipe->idx));
+
+      sam_putreg8(USBHOST_PSTATUS_BK0RDY,
+                  SAM_USBHOST_PSTATUSSET(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_PFREEZE,
+                  SAM_USBHOST_PSTATUSCLR(pipe->idx));
+    }
+}
+
+/****************************************************************************
+ * Name: sam_send_start
+ *
+ * Description:
+ *   Start at transfer on the selected IN or OUT pipe.
+ *
+ ****************************************************************************/
+
+static void sam_send_start(FAR struct sam_usbhost_s *priv,
+                           FAR struct sam_pipe_s *pipe)
+{
+  /* Set up the initial state of the transfer */
+
+  usbhost_vtrace2(SAM_VTRACE2_STARTTRANSFER1, pipe->idx, pipe->size);
+
+  pipe->result = EBUSY;
+  pipe->count = 0;
+
+  /* Make sure the peripheral address is correct */
+
+  pipe->descb[0]->ctrlpipe &= ~USBHOST_CTRLPIPE_PDADDR_MASK;
+  pipe->descb[0]->ctrlpipe |= USBHOST_CTRLPIPE_PDADDR(pipe->funcaddr);
+
+  /* Checkout for zero length packet */
+
+  if (pipe->size > 0)
+    {
+      /* No.. we need to copy the outgoing data and start the transfer */
+
+      sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+                   USBHOST_PINTFLAG_TRCPT1),
+                   SAM_USBHOST_PINTFLAG(pipe->idx));
+
+      sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+                   USBHOST_PINTFLAG_TRCPT1),
+                   SAM_USBHOST_PINTENSET(pipe->idx));
+
+      pipe->descb[0]->addr = (uint32_t)pipe->data;
+      pipe->descb[0]->pktsize &= ~(USBHOST_PKTSIZE_MPKTSIZE_MASK |
+                                   USBHOST_PKTSIZE_BCNT_MASK);
+      pipe->descb[0]->pktsize |= USBHOST_PKTSIZE_BCNT(pipe->size);
+
+      /* Send the OUT token */
+
+      sam_modifyreg8(USBHOST_PCFG_PTOKEN_MASK,
+                     USBHOST_PCFG_PTOKEN_OUT,
+                     SAM_USBHOST_PCFG(pipe->idx));
+
+      sam_putreg8(USBHOST_PSTATUS_BK0RDY,
+                  SAM_USBHOST_PSTATUSSET(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_PFREEZE,
+                  SAM_USBHOST_PSTATUSCLR(pipe->idx));
+    }
+  else
+    {
+      sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+                   USBHOST_PINTFLAG_TRCPT1),
+                   SAM_USBHOST_PINTFLAG(pipe->idx));
+      sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+                   USBHOST_PINTFLAG_TRCPT1),
+                   SAM_USBHOST_PINTENSET(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_DTGL,
+                  SAM_USBHOST_PSTATUSSET(pipe->idx));
+
+      /* Write the zero byte count */
+
+      pipe->descb[0]->addr = (uint32_t)priv->ctrl_buffer;
+      pipe->descb[0]->pktsize &= ~(USBHOST_PKTSIZE_MPKTSIZE_MASK |
+                                   USBHOST_PKTSIZE_BCNT_MASK);
+      pipe->descb[0]->pktsize |= USBHOST_PKTSIZE_AUTOZLP;
+
+      /* Send the OUT token */
+
+      sam_modifyreg8(USBHOST_PCFG_PTOKEN_MASK,
+                     USBHOST_PCFG_PTOKEN_OUT,
+                     SAM_USBHOST_PCFG(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_BK0RDY,
+                  SAM_USBHOST_PSTATUSSET(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_PFREEZE,
+                  SAM_USBHOST_PSTATUSCLR(pipe->idx));
+    }
+}
+
+/****************************************************************************
+ * Name: sam_out_transfer
+ *
+ * Description:
+ *   Transfer the 'buflen' bytes in 'buffer' through an OUT pipe.
+ *
+ * Assumptions:
+ *   This function is called only from the TRANSFER
+ *   interface.  The lock, for example,
+ *   must be relinquished before waiting.
+ *
+ ****************************************************************************/
+
+static ssize_t sam_out_transfer(FAR struct sam_usbhost_s *priv,
+                                FAR struct sam_pipe_s *pipe,
+                                FAR uint8_t *buffer, size_t buflen)
+{
+  clock_t start;
+  clock_t elapsed;
+  size_t xfrlen;
+  ssize_t xfrd;
+  int ret;
+
+  /* Loop until the transfer completes (i.e., buflen is decremented to zero)
+   * or a fatal error occurs (any error other than a simple NAK)
+   */
+
+  start = clock_systime_ticks();
+  xfrd  = 0;
+
+  while (buflen > 0)
+    {
+      /* Transfer one packet at a time.  The hardware is capable of queueing
+       * multiple OUT packets, but I just haven't figured out how to handle
+       * the case where a single OUT packet in the group is NAKed.
+       */
+
+      xfrlen = MIN(pipe->maxpacket, buflen);
+      pipe->data = buffer;
+      pipe->size = xfrlen;
+      pipe->count = 0;
+      uinfo("pipe%d buffer:%p buflen:%d\n",
+                                 pipe->idx,
+                                 pipe->data,
+                                 pipe->size);
+
+      /* Set up for the wait BEFORE starting the transfer */
+
+      ret = sam_pipe_waitsetup(priv, pipe);
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_DEVDISCONN1, 0);
+          return (ssize_t)ret;
+        }
+
+      /* Set up for the transfer based
+       * on the direction and the endpoint type
+       */
+
+      ret = sam_out_setup(priv, pipe);
+
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_OUTSETUP_FAIL1, -ret);
+          return (ssize_t)ret;
+        }
+
+      /* Wait for the transfer to complete and get the result */
+
+      ret = sam_pipe_wait(priv, pipe);
+
+      /* Handle transfer failures */
+
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_TRANSFER_FAILED1, ret);
+
+          /* Check for a special case:  If (1) the transfer was NAKed and (2)
+           * no SNDFIFO empty or Rx FIFO not-empty event occurred, then we
+           * should be able to just flush the Rx and SNDFIFOs and try again.
+           * We can detect this latter case because then the transfer buffer
+           * pointer and buffer size will be unaltered.
+           */
+
+          elapsed = clock_systime_ticks() - start;
+          if (ret != -EAGAIN ||                /* Not a NAK condition OR */
+              elapsed >= SAM_DATANAK_DELAY ||  /* Timeout has elapsed OR */
+              pipe->count > 0)                 /* Data has been partially transferred */
+            {
+              /* Break out and return the error */
+
+              usbhost_trace1(SAM_TRACE1_PIPEWAIT_FAIL, -ret);
+              return (ssize_t)ret;
+            }
+
+          /* Get the device a little time to catch up.
+           * Then retry the transfer
+           * using the same buffer pointer and length.
+           */
+
+          nxsig_usleep(20 * 1000);
+        }
+      else
+        {
+          /* Successfully transferred. Update the buffer pointer and length */
+
+          buffer += xfrlen;
+          buflen -= xfrlen;
+          xfrd   += pipe->count;
+        }
+    }
+
+  return xfrd;
+}
+
+/****************************************************************************
+ * Name: sam_out_next
+ *
+ * Description:
+ *   Initiate the next of a sequence of asynchronous transfers.
+ *
+ * Assumptions:
+ *   This function is always called from an interrupt handler
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_ASYNCH
+static void sam_out_next(FAR struct sam_usbhost_s *priv,
+                         FAR struct sam_pipe_s *pipe)
+{
+  usbhost_asynch_t callback;
+  FAR void *arg;
+  ssize_t nbytes;
+  int result;
+  int ret;
+
+  /* Is the full transfer complete?
+   * Did the last chunk transfer complete OK?
+   */
+
+  result = -(int)pipe->result;
+  if (pipe->count < pipe->size && result == OK)
+    {
+      /* Yes.. Set up for the next transfer based on the direction and the
+       * endpoint type
+       */
+
+      ret = sam_out_setup(priv, pipe);
+      if (ret >= 0)
+        {
+          return;
+        }
+
+      usbhost_trace1(SAM_TRACE1_OUTSETUP_FAIL2, -ret);
+      result = ret;
+    }
+
+  /* The transfer is complete, with or without an error */
+
+  usbhost_vtrace1(SAM_VTRACE1_TRANSFER_COMPLETE, result);
+
+  /* Extract the callback information */
+
+  callback = pipe->callback;
+  arg = pipe->arg;
+  nbytes = pipe->count;
+
+  pipe->callback = NULL;
+  pipe->arg = NULL;
+  pipe->count = 0;
+
+  /* Then perform the callback */
+
+  if (result < 0)
+    {
+      nbytes = (ssize_t)result;
+    }
+
+  callback(arg, nbytes);
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_out_asynch
+ *
+ * Description:
+ *   Initiate the first of a sequence of asynchronous transfers.
+ *
+ * Assumptions:
+ *   This function is called only from the ASYNCH.
+ *   The lock, for example, must be relinquished before waiting.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_ASYNCH
+static int sam_out_asynch(FAR struct sam_usbhost_s *priv,
+                          FAR struct sam_pipe_s *pipe,
+                          FAR uint8_t *buffer, size_t buflen,
+                          usbhost_asynch_t callback, FAR void *arg)
+{
+  int ret;
+
+  /* Set up for the transfer data and callback
+   * BEFORE starting the first transfer
+   */
+
+  pipe->data = buffer;
+  pipe->size = buflen;
+  pipe->count = 0;
+
+  ret = sam_pipe_asynchsetup(priv, pipe, callback, arg);
+  if (ret < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_ASYNCHSETUP_FAIL1, -ret);
+      return ret;
+    }
+
+  /* Set up for the transfer based on the
+   * direction and the endpoint type
+   */
+
+  ret = sam_out_setup(priv, pipe);
+
+  if (ret < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_OUTSETUP_FAIL3, -ret);
+    }
+
+  /* And return with the transfer pending */
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_ctrl_sendsetup
+ *
+ * Description:
+ *   Send an IN/OUT SETUP packet.
+ *
+ * Assumptions:
+ *   This function is called only from the CTRLIN and CTRLOUT interfaces.
+ *
+ ****************************************************************************/
+
+static int sam_ctrl_sendsetup(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe,
+                              FAR const struct usb_ctrlreq_s *req)
+{
+  clock_t start;
+  clock_t elapsed;
+  int ret;
+  int i;
+
+  /* Loop while the device reports NAK (and a timeout is not exceeded */
+
+  start = clock_systime_ticks();
+  do
+    {
+      /* Send the SETUP packet */
+
+      pipe->data = (FAR uint8_t *)req;
+      pipe->size = USB_SIZEOF_CTRLREQ;
+      pipe->count = 0;
+      pipe->result = EBUSY;
+      uinfo("pipe%d buffer:%p buflen:%d\n",
+                                 pipe->idx,
+                                 pipe->data,
+                                 pipe->size);
+      sam_pktdump("sam_ctrl_sendsetup", pipe->data, pipe->size);
+
+      /* Set up for the wait BEFORE starting the transfer */
+
+      ret = sam_pipe_waitsetup(priv, pipe);
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_DEVDISCONN2, 0);
+          return ret;
+        }
+
+      pipe->pipestate_general = USB_H_PIPE_S_SETUP;
+      sam_add_sof_user(priv);
+      priv->n_ctrl_req_user++;
+
+      /* Make sure the peripheral address is correct */
+
+      pipe->descb[0]->ctrlpipe &= ~USBHOST_CTRLPIPE_PDADDR_MASK;
+      pipe->descb[0]->ctrlpipe |= USBHOST_CTRLPIPE_PDADDR(pipe->funcaddr);
+
+      /* Write packet */
+
+      sam_putreg8(USBHOST_PINTFLAG_TXSTP, SAM_USBHOST_PINTFLAG(pipe->idx));
+      for (i = 0; i < USB_SIZEOF_CTRLREQ; i++)
+          priv->ctrl_buffer[i] = pipe->data[i];
+
+      pipe->descb[0]->addr = (uint32_t)pipe->data;
+      pipe->descb[0]->pktsize &= ~(USBHOST_PKTSIZE_MPKTSIZE_MASK |
+                                   USBHOST_PKTSIZE_BCNT_MASK);
+      pipe->descb[0]->pktsize |= USBHOST_PKTSIZE_BCNT(USB_SIZEOF_CTRLREQ);
+
+      pipe->descb[0]->ctrlpipe = USBHOST_CTRLPIPE_PDADDR(pipe->funcaddr) |
+                      USBHOST_CTRLPIPE_PEPNUM(pipe->epno & USB_EPNO_MASK);
+      uinfo("pipe%d pktsize=0x%x ctrl=0x%x status=0x%x\n",
+                                    pipe->idx,
+                                    pipe->descb[0]->pktsize,
+                                    pipe->descb[0]->ctrlpipe,
+                                    pipe->descb[0]->statuspipe);
+
+      /* Send the SETUP token (always EP0) */
+
+      sam_modifyreg8(USBHOST_PCFG_PTOKEN_MASK,
+                     USBHOST_PCFG_PTOKEN_SETUP,
+                     SAM_USBHOST_PCFG(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_DTGL, SAM_USBHOST_PSTATUSCLR(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_BK0RDY, SAM_USBHOST_PSTATUSSET(pipe->idx));
+      sam_putreg8(USBHOST_PINTFLAG_TXSTP, SAM_USBHOST_PINTENSET(pipe->idx));
+      sam_putreg8(USBHOST_PSTATUS_PFREEZE,
+                  SAM_USBHOST_PSTATUSCLR(pipe->idx));
+
+      /* Wait for the transfer to complete */
+
+      ret = sam_pipe_wait(priv, pipe);
+
+      /* Return on success and for all failures other than EAGAIN.  EAGAIN
+       * means that the device NAKed the SETUP command and that we should
+       * try a few more times.  NOTE:  The USB spec says that a peripheral
+       * must always ACK a SETUP packet.
+       */
+
+      if (ret != -EAGAIN)
+        {
+          /* Output some debug information if the transfer failed */
+
+          if (ret < 0)
+            {
+              usbhost_trace1(SAM_TRACE1_TRANSFER_FAILED2, ret);
+            }
+
+          /* Return the result in any event */
+
+          return ret;
+        }
+
+      /* Get the elapsed time (in frames) */
+
+      elapsed = clock_systime_ticks() - start;
+    }
+  while (elapsed < SAM_SETUP_DELAY);
+
+  return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: sam_ctrl_senddata
+ *
+ * Description:
+ *   Send data in the data phase of an OUT control transfer.  Or send status
+ *   in the status phase of an IN control transfer
+ *
+ * Assumptions:
+ *   This function is called only from the CTRLOUT interface.
+ *
+ ****************************************************************************/
+
+static int sam_ctrl_senddata(FAR struct sam_usbhost_s *priv,
+                             FAR struct sam_pipe_s *pipe,
+                             FAR uint8_t *buffer, unsigned int buflen)
+{
+  int ret;
+
+  uinfo("pipe%d buffer:%p buflen:%d\n", pipe->idx, buffer, buflen);
+
+  /* Save buffer information */
+
+  pipe->pipestate_general = USB_H_PIPE_S_DATO;
+  pipe->in = false;
+  pipe->data = buffer;
+  pipe->size = buflen;
+  pipe->count = 0;
+
+  /* Set up for the wait BEFORE starting the transfer */
+
+  ret = sam_pipe_waitsetup(priv, pipe);
+  if (ret < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_DEVDISCONN3, 0);
+      return ret;
+    }
+
+  /* Start the transfer */
+
+  sam_send_start(priv, pipe);
+
+  /* Wait for the transfer to complete and return the result */
+
+  return sam_pipe_wait(priv, pipe);
+}
+
+/****************************************************************************
+ * Name: sam_ctrl_recvdata
+ *
+ * Description:
+ *   Receive data in the data phase of an IN control transfer.
+ *   Or receive status in the status phase of
+ *   an OUT control transfer.
+ *
+ * Assumptions:
+ *   This function is called only from the CTRLIN interface.
+ *
+ ****************************************************************************/
+
+static int sam_ctrl_recvdata(FAR struct sam_usbhost_s *priv,
+                             FAR struct sam_pipe_s *pipe,
+                             FAR uint8_t *buffer, unsigned int buflen)
+{
+  int ret;
+
+  /* Save buffer information */
+
+  pipe->pipestate_general = USB_H_PIPE_S_DATI;
+
+  pipe->in = true;
+  pipe->data = buffer;
+  pipe->size = buflen;
+  pipe->count = 0;
+
+  /* Set up for the wait BEFORE starting the transfer */
+
+  ret = sam_pipe_waitsetup(priv, pipe);
+  if (ret < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_DEVDISCONN4, 0);
+      return ret;
+    }
+
+  /* Start the transfer */
+
+  sam_recv_start(priv, pipe);
+
+  /* Wait for the transfer to complete and return the result */
+
+  ret = sam_pipe_wait(priv, pipe);
+
+  uinfo("pipe%d buffer:%p buflen:%d ADDR=0x%x PKTSIZE=0x%x\n",
+        pipe->idx, buffer, buflen,
+        pipe->descb[0]->addr,
+        pipe->descb[0]->pktsize)
+
+  uinfo("EXTREG=0x%x STATUSBK=0x%x CTRLPIPE=0x%x STATUSPIPE=0x%x\n",
+        pipe->descb[0]->extreg,
+        pipe->descb[0]->stausbk,
+        pipe->descb[0]->ctrlpipe,
+        pipe->descb[0]->statuspipe);
+  sam_pktdump("sam_ctrl_recvdata", pipe->data, pipe->size);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: sam_in_setup
+ *
+ * Description:
+ *   Initiate an IN transfer on an bulk, interrupt, or isochronous pipe.
+ *
+ ****************************************************************************/
+
+static int sam_in_setup(FAR struct sam_usbhost_s *priv,
+                        FAR struct sam_pipe_s *pipe)
+{
+  uinfo("pipe%d\n", pipe->idx);
+
+  /* Set up for the transfer based on the direction and the endpoint type */
+
+  switch (pipe->eptype)
+    {
+      default:
+      case USB_EP_ATTR_XFER_CONTROL: /* Control */
+        {
+          /* This kind of transfer on control endpoints other than EP0 are
+           * not currently supported
+           */
+
+          return -ENOSYS;
+        }
+
+      case USB_EP_ATTR_XFER_ISOC: /* Isochronous */
+        {
+          /* Set up the IN DATA0 PID */
+
+          usbhost_vtrace2(SAM_VTRACE2_ISOCIN, pipe->idx, pipe->size);
+        }
+        break;
+
+      case USB_EP_ATTR_XFER_BULK: /* Bulk */
+        {
+          usbhost_vtrace2(SAM_VTRACE2_BULKIN, pipe->idx, pipe->size);
+          pipe->pipestate_general = pipe->in ?
+                USB_H_PIPE_S_DATI : USB_H_PIPE_S_DATO;
+        }
+        break;
+
+      case USB_EP_ATTR_XFER_INT: /* Interrupt */
+        {
+          usbhost_vtrace2(SAM_VTRACE2_INTRIN, pipe->idx, pipe->size);
+        }
+        break;
+    }
+
+  /* Start the transfer. */
+
+  sam_recv_start(priv, pipe);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_out_setup
+ *
+ * Description:
+ *   Initiate an OUT transfer on an bulk, interrupt, or isochronous pipe.
+ *
+ ****************************************************************************/
+
+static int sam_out_setup(FAR struct sam_usbhost_s *priv,
+                         FAR struct sam_pipe_s *pipe)
+{
+  /* Set up for the transfer based on the direction and the endpoint type */
+
+  switch (pipe->eptype)
+    {
+      default:
+      case USB_EP_ATTR_XFER_CONTROL: /* Control */
+        {
+          /* This kind of transfer on control endpoints other than EP0 are
+           * not currently supported
+           */
+
+          return -ENOSYS;
+        }
+
+      case USB_EP_ATTR_XFER_ISOC: /* Isochronous */
+        {
+          /* Set up the IN DATA0 PID */
+
+          usbhost_vtrace2(SAM_VTRACE2_ISOCOUT,
+                          pipe->idx, pipe->size);
+        }
+        break;
+
+      case USB_EP_ATTR_XFER_BULK: /* Bulk */
+        {
+          usbhost_vtrace2(SAM_VTRACE2_BULKOUT,
+                          pipe->idx, pipe->size);
+          pipe->pipestate_general = pipe->in ?
+                           USB_H_PIPE_S_DATI : USB_H_PIPE_S_DATO;
+        }
+        break;
+
+      case USB_EP_ATTR_XFER_INT: /* Interrupt */
+        {
+          usbhost_vtrace2(SAM_VTRACE2_INTROUT,
+                          pipe->idx, pipe->size);
+        }
+        break;
+    }
+
+  /* Start the transfer */
+
+  sam_send_start(priv, pipe);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_recv_continue
+ *
+ * Description:
+ *   Continue the receive operation started by sam_recv_start().  This
+ *   function is called from the interrupt handler worker when an interrupt
+ *   indicates that new, incoming data is available
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void sam_recv_continue(FAR struct sam_usbhost_s *priv,
+                              FAR struct sam_pipe_s *pipe)
+{
+  uint8_t *src;
+  uint8_t *dst;
+  uint32_t size;
+  uint32_t count;
+  uint32_t i;
+  uint32_t n_rx = 0;
+  uint32_t n_remain;
+  bool shortpkt = false;
+  bool full = false;
+
+  if (pipe->pipestate_general == USB_H_PIPE_S_STATI)
+    {
+      /* Control status : ZLP IN done */
+
+      sam_transfer_terminate(priv, pipe, OK);
+      return;
+    }
+  else if (pipe->pipestate_general != USB_H_PIPE_S_DATI)
+    return;
+
+  /* Read byte count */
+
+  n_rx = (pipe->descb[0]->pktsize & USBHOST_PKTSIZE_BCNT_MASK) >>
+                                    USBHOST_PKTSIZE_BCNT_SHIFT;
+  if (n_rx < pipe->maxpacket)
+    shortpkt = true;
+
+  if (n_rx)
+    {
+      dst = pipe->data;
+      size = pipe->size;
+      count = pipe->count;
+      n_remain = size - count;
+      src = (uint8_t *)pipe->descb[0]->addr;
+      dst = &dst[count];
+      if (n_rx >= n_remain)
+        {
+          n_rx = n_remain;
+          full = true;
+        }
+
+      count += n_rx;
+      for (i = 0; i < n_rx; i++)
+        *dst++ = *src++;
+
+      pipe->count = count;
+    }
+
+  /* Reset timeout for control pipes */
+
+  if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL)
+    pipe->pkt_timeout = USB_CTRL_DPKT_TIMEOUT;
+
+  /* Finish on error or short packet */
+
+  if (full || shortpkt)
+    {
+      if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL)
+        {
+          pipe->pipestate = USB_H_PIPE_S_STATO;
+          pipe->pkt_timeout = USB_CTRL_STAT_TIMEOUT;
+          sam_putreg8(USBHOST_PSTATUS_DTGL,
+                      SAM_USBHOST_PSTATUSSET(pipe->idx));
+          sam_send_start(priv, pipe);
+        }
+      else
+          sam_transfer_terminate(priv, pipe, OK);
+    }
+  else
+    {
+      /* Just wait another packet */
+
+      sam_recv_restart(priv, pipe);
+    }
+}
+
+/****************************************************************************
+ * Name: sam_recv_restart
+ *
+ * Description:
+ *   Start/Re-start the transfer on the selected IN or OUT pipe
+ *
+ ****************************************************************************/
+
+static void sam_recv_restart(FAR struct sam_usbhost_s *priv,
+                             FAR struct sam_pipe_s *pipe)
+{
+  /* Send the IN token. */
+
+  sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+               USBHOST_PINTFLAG_TRCPT1), SAM_USBHOST_PINTFLAG(pipe->idx));
+  sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+               USBHOST_PINTFLAG_TRCPT1), SAM_USBHOST_PINTENSET(pipe->idx));
+
+  if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL)
+    {
+      pipe->descb[0]->addr = (uint32_t)pipe->data;
+      pipe->descb[0]->pktsize &= ~(USBHOST_PKTSIZE_MPKTSIZE_MASK |
+                                   USBHOST_PKTSIZE_BCNT_MASK);
+      pipe->descb[0]->pktsize |= USBHOST_PKTSIZE_MPKTSIZE(pipe->maxpacket);
+    }
+  else
+    {
+      uint32_t n_next = pipe->size - pipe->count;
+
+      pipe->descb[0]->addr = (uint32_t)&pipe->data[pipe->count];
+      if (n_next > 16384)
+        n_next = 16384;
+
+      pipe->descb[0]->pktsize &= ~(USBHOST_PKTSIZE_MPKTSIZE_MASK |
+                                   USBHOST_PKTSIZE_BCNT_MASK);
+      pipe->descb[0]->pktsize |= USBHOST_PKTSIZE_MPKTSIZE(n_next);
+    }
+
+  sam_modifyreg8(USBHOST_PCFG_PTOKEN_MASK,
+                 USBHOST_PCFG_PTOKEN_IN,
+                 SAM_USBHOST_PCFG(pipe->idx));
+  sam_putreg8(USBHOST_PSTATUS_BK0RDY, SAM_USBHOST_PSTATUSCLR(pipe->idx));
+  sam_putreg8(USBHOST_PSTATUS_PFREEZE, SAM_USBHOST_PSTATUSCLR(pipe->idx));
+}
+
+/****************************************************************************
+ * Name: sam_recv_start
+ *
+ * Description:
+ *   Start at transfer on the selected IN or OUT pipe.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void sam_recv_start(FAR struct sam_usbhost_s *priv,
+                           FAR struct sam_pipe_s *pipe)
+{
+  /* Set up the initial state of the transfer */
+
+  usbhost_vtrace2(SAM_VTRACE2_STARTTRANSFER2, pipe->idx, pipe->size);
+
+  pipe->result = EBUSY;
+  pipe->count = 0;
+
+  /* Make sure the peripheral address is correct */
+
+  pipe->descb[0]->ctrlpipe &= ~USBHOST_CTRLPIPE_PDADDR_MASK;
+  pipe->descb[0]->ctrlpipe |= USBHOST_CTRLPIPE_PDADDR(pipe->funcaddr);
+
+  /* Start the transfer. */
+
+  sam_recv_restart(priv, pipe);
+}
+
+/****************************************************************************
+ * Name: sam_in_transfer
+ *
+ * Description:
+ *   Transfer 'buflen' bytes into 'buffer' from an IN pipe.
+ *
+ * Assumptions:
+ *   This function is called only from the TRANSFER.
+ *   The lock, for example, must be relinquished before waiting.
+ *
+ ****************************************************************************/
+
+static ssize_t sam_in_transfer(FAR struct sam_usbhost_s *priv,
+                               FAR struct sam_pipe_s *pipe,
+                               FAR uint8_t *buffer, size_t buflen)
+{
+  clock_t start;
+  ssize_t xfrd;
+  int ret;
+
+/* Loop until the transfer completes (i.e., buflen is decremented to zero)
+ * or a fatal error occurs any error other than a simple NAK.  NAK would
+ * simply indicate the end of the transfer (short-transfer).
+ */
+
+  pipe->data = buffer;
+  pipe->size = buflen;
+  pipe->count = 0;
+  xfrd = 0;
+
+  start = clock_systime_ticks();
+  while (pipe->count < pipe->size)
+    {
+      /* Set up for the wait BEFORE starting the transfer */
+
+      ret = sam_pipe_waitsetup(priv, pipe);
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_DEVDISCONN5, 0);
+          return (ssize_t)ret;
+        }
+
+      /* Set up for the transfer based on the direction
+       * and the endpoint type
+       */
+
+      ret = sam_in_setup(priv, pipe);
+
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_INSETUP_FAIL1, -ret);
+          return (ssize_t)ret;
+        }
+
+      /* Wait for the transfer to complete and get the result */
+
+      ret = sam_pipe_wait(priv, pipe);
+
+      /* EAGAIN indicates that the device NAKed the transfer. */
+
+      if (ret < 0)
+        {
+          /* The transfer failed.  If we received a NAK, return all data
+           * buffered so far (if any).
+           */
+
+          if (ret == -EAGAIN)
+            {
+              /* Was data buffered prior to the NAK? */
+
+              if (xfrd > 0)
+                  return xfrd;
+              else
+                {
+                  useconds_t delay;
+
+                  /* Get the elapsed time.
+                   * Has the timeout elapsed?
+                   * if not then try again.
+                   */
+
+                  clock_t elapsed = clock_systime_ticks() - start;
+                  if (elapsed >= SAM_DATANAK_DELAY)
+                    {
+                      /* Timeout out... break out returning the NAK as
+                       * as a failure.
+                       */
+
+                      return (ssize_t)ret;
+                    }
+
+                  /* Wait a bit before retrying after a NAK. */
+
+                  if (pipe->eptype == USB_EP_ATTR_XFER_INT)
+                    {
+      /* For interrupt (and isochronous) endpoints, the
+       * polling rate is determined by the bInterval field
+       * of the endpoint descriptor (in units of frames
+       * which we treat as milliseconds here).
+       */
+
+                      if (pipe->interval > 0)
+                        {
+                          /* Convert the delay to units of microseconds */
+
+                          delay = (useconds_t)pipe->interval * 1000;
+                        }
+                      else
+                        {
+                          /* Out of range! For interrupt endpoints, the valid
+                           * range is 1-255 frames.  Assume one frame.
+                           */
+
+                          delay = 1000;
+                        }
+                    }
+                  else
+                    {
+      /* For Isochronous endpoints, bInterval must be 1.  Bulk
+       * endpoints do not have a polling interval.  Rather,
+       * the should wait until data is received.
+       *
+       * REVISIT:  For bulk endpoints this 1 msec delay is only
+       * intended to give the CPU a break from the bulk EP tight
+       * polling loop.  But are there performance issues?
+       */
+
+                      delay = 1000;
+                    }
+
+      /* Wait for the next polling interval.  For interrupt and
+       * isochronous endpoints, this is necessary to assure the
+       * polling interval.  It is used in other cases only to
+       * prevent the polling from consuming too much CPU bandwidth.
+       *
+       * Small delays could require more resolution than is provided
+       * by the system timer.  For example, if the system timer
+       * resolution is 10MS, then nxsig_usleep(1000) will actually request
+       * a delay 20MS (due to both quantization and rounding).
+       *
+       * REVISIT: So which is better?  To ignore tiny delays and
+       * hog the system bandwidth?  Or to wait for an excessive
+       * amount and destroy system throughput?
+       */
+
+                  if (delay > CONFIG_USEC_PER_TICK)
+                    {
+                      nxsig_usleep(delay - CONFIG_USEC_PER_TICK);
+                    }
+                }
+            }
+          else
+            {
+              /* Some unexpected, fatal error occurred. */
+
+              usbhost_trace1(SAM_TRACE1_TRANSFER_FAILED3, -ret);
+
+              /* Break out and return the error */
+
+              return (ssize_t)ret;
+            }
+        }
+      else
+        {
+          /* Successfully received another chunk of data... add that to the
+           * running total.  Then continue reading until we read 'buflen'
+           * bytes of data or until the devices NAKs (implying a short
+           * packet).
+           */
+
+          xfrd += pipe->count;
+        }
+    }
+
+  return xfrd;
+}
+
+/****************************************************************************
+ * Name: sam_in_next
+ *
+ * Description:
+ *   Initiate the next of a sequence of asynchronous transfers.
+ *
+ * Assumptions:
+ *   This function is always called from an interrupt handler
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_ASYNCH
+static void sam_in_next(FAR struct sam_usbhost_s *priv,
+                        FAR struct sam_pipe_s *pipe)
+{
+  usbhost_asynch_t callback;
+  FAR void *arg;
+  ssize_t nbytes;
+  int result;
+  int ret;
+
+  /* Is the full transfer complete?
+   * Did the last chunk transfer complete OK?
+   */
+
+  result = -(int)pipe->result;
+  if (pipe->count < pipe->size && result == OK)
+    {
+      /* Yes.. Set up for the next transfer based on the direction and the
+       * endpoint type
+       */
+
+      ret = sam_in_setup(priv, pipe);
+      if (ret >= 0)
+        {
+          return;
+        }
+
+      usbhost_trace1(SAM_TRACE1_INSETUP_FAIL2, -ret);
+      result = ret;
+    }
+
+  /* The transfer is complete, with or without an error */
+
+  usbhost_vtrace2(SAM_VTRACE2_XFRCOMPLETE,
+                  (unsigned int)pipe->idx, pipe->size);
+
+  /* Extract the callback information */
+
+  callback       = pipe->callback;
+  arg            = pipe->arg;
+  nbytes         = pipe->count;
+
+  pipe->callback = NULL;
+  pipe->arg = NULL;
+  pipe->count = 0;
+
+  /* Then perform the callback */
+
+  if (result < 0)
+    {
+      nbytes = (ssize_t)result;
+    }
+
+  callback(arg, nbytes);
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_in_asynch
+ *
+ * Description:
+ *   Initiate the first of a sequence of asynchronous transfers.
+ *
+ * Assumptions:
+ *   This function is called only from the ASYNCH interface.
+ *   The lock, for example,
+ *   must be relinquished before waiting.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_ASYNCH
+static int sam_in_asynch(FAR struct sam_usbhost_s *priv,
+                         FAR struct sam_pipe_s *pipe,
+                         FAR uint8_t *buffer, size_t buflen,
+                         usbhost_asynch_t callback, FAR void *arg)
+{
+  int ret;
+
+  /* Set up for the transfer data and callback
+   * BEFORE starting the first transfer
+   */
+
+  pipe->data = buffer;
+  pipe->size = buflen;
+  pipe->count = 0;
+
+  ret = sam_pipe_asynchsetup(priv, pipe, callback, arg);
+  if (ret < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_ASYNCHSETUP_FAIL2, -ret);
+      return ret;
+    }
+
+  /* Set up for the transfer based on the direction and the endpoint type */
+
+  ret = sam_in_setup(priv, pipe);
+
+  if (ret < 0)
+    {
+      usbhost_trace1(SAM_TRACE1_INSETUP_FAIL3, -ret);
+    }
+
+  /* And return with the transfer pending */
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_gint_connected
+ *
+ * Description:
+ *   Handle a connection event.
+ *
+ ****************************************************************************/
+
+static void sam_gint_connected(FAR struct sam_usbhost_s *priv)
+{
+  /* We we previously disconnected? */
+
+  if (!priv->connected)
+    {
+      /* Yes.. then now we are connected */
+
+      usbhost_vtrace1(SAM_VTRACE1_CONNECTED1, 0);
+      priv->connected = true;
+      priv->change    = true;
+      DEBUGASSERT(priv->smstate == SMSTATE_DETACHED);
+
+      /* Notify any waiters */
+
+      priv->smstate = SMSTATE_ATTACHED;
+      if (priv->pscwait)
+        {
+          sam_givesem(&priv->pscsem);
+          priv->pscwait = false;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: sam_gint_disconnected
+ *
+ * Description:
+ *   Handle a disconnection event.
+ *
+ ****************************************************************************/
+
+static void sam_gint_disconnected(FAR struct sam_usbhost_s *priv)
+{
+  /* Were we previously connected? */
+
+  if (priv->connected)
+    {
+      /* Yes.. then we no longer connected */
+
+      usbhost_vtrace1(SAM_VTRACE1_DISCONNECTED1, 0);
+
+      /* Are we bound to a class driver? */
+
+      if (priv->rhport.hport.devclass)
+        {
+          /* Yes.. Disconnect the class driver */
+
+          CLASS_DISCONNECTED(priv->rhport.hport.devclass);
+          priv->rhport.hport.devclass = NULL;
+        }
+
+      /* Re-Initialize Host for new Enumeration */
+
+      priv->smstate   = SMSTATE_DETACHED;
+      priv->connected = false;
+      priv->change    = true;
+      sam_reset_pipes(priv, false);
+
+      priv->rhport.hport.speed = USB_SPEED_FULL;
+      priv->rhport.hport.funcaddr = 0;
+
+      /* Notify any waiters that there is a
+       * change in the connection state
+       */
+
+      if (priv->pscwait)
+        {
+          sam_givesem(&priv->pscsem);
+          priv->pscwait = false;
+        }
+    }
+}
+
+/****************************************************************************
+ * USB Host Controller Operations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_wait
+ *
+ * Description:
+ *   Wait for a device to be connected or disconnected to/from a hub port.
+ *
+ * Input Parameters:
+ *   conn - The USB host connection instance obtained as a parameter
+ *    from the call to the USB driver initialization logic.
+ *   hport - The location to return the hub port descriptor that detected the
+ *      connection related event.
+ *
+ * Returned Value:
+ *   Zero (OK) is returned on success when a device is connected or
+ *   disconnected. This function will not return until either (1) a device is
+ *   connected or disconnect to/from any hub port or until (2) some failure
+ *   occurs.  On a failure, a negated errno value is returned indicating the
+ *   nature of the failure
+ *
+ * Assumptions:
+ *   - Called from a single thread so no mutual exclusion is required.
+ *   - Never called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_wait(FAR struct usbhost_connection_s *conn,
+                    FAR struct usbhost_hubport_s **hport)
+{
+  FAR struct sam_usbhost_s *priv = &g_usbhost;
+  struct usbhost_hubport_s *connport;
+  irqstate_t flags;
+
+  /* Loop until a change in connection state is detected */
+
+  flags = enter_critical_section();
+  for (; ; )
+    {
+      /* Is there a change in the connection state of the single root hub
+       * port?
+       */
+
+      if (priv->change)
+        {
+          connport = &priv->rhport.hport;
+
+          /* Yes. Remember the new state */
+
+          connport->connected = priv->connected;
+          priv->change = false;
+
+          /* And return the root hub port */
+
+          *hport = connport;
+          leave_critical_section(flags);
+
+          uinfo("RHport Connected: %s\n", connport->connected ?
+                                                  "YES" : "NO");
+          return OK;
+        }
+
+ #ifdef CONFIG_USBHOST_HUB
+      /* Is a device connected to an external hub? */
+
+      if (priv->hport)
+        {
+          /* Yes.. return the external hub port */
+
+          connport = (struct usbhost_hubport_s *)priv->hport;
+          priv->hport = NULL;
+
+          *hport = connport;
+          leave_critical_section(flags);
+
+          uinfo("Hub port Connected: %s\n", connport->connected ?
+                                                   "YES" : "NO");
+          return OK;
+        }
+ #endif
+
+      /* Wait for the next connection event */
+
+      priv->pscwait = true;
+      sam_takesem(&priv->pscsem);
+    }
+}
+
+/****************************************************************************
+ * Name: sam_rh_enumerate
+ *
+ * Description:
+ *   Enumerate the connected device.  As part of this enumeration process,
+ *   the driver will (1) get the device's configuration descriptor, (2)
+ *   extract the class ID info from the configuration descriptor, (3) call
+ *   usbhost_findclass() to find the class that supports this device, (4)
+ *   call the create() method on the struct usbhost_registry_s interface
+ *   to get a class instance, and finally (5) call the connect() method
+ *   of the struct usbhost_class_s interface.  After that, the class is in
+ *   charge of the sequence of operations.
+ *
+ * Input Parameters:
+ *   conn - The USB host connection instance obtained as a parameter from
+ *      the call to the USB driver initialization logic.
+ *   hport - The descriptor of the hub port that has the newly connected
+ *      device.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure,
+ *   a negated errno value is returned
+ *   indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_rh_enumerate(FAR struct sam_usbhost_s *priv,
+                            FAR struct usbhost_connection_s *conn,
+                            FAR struct usbhost_hubport_s *hport)
+{
+  uint32_t regval;
+  int ret;
+
+  uinfo("ENTRY\n");
+  DEBUGASSERT(conn != NULL && hport != NULL && hport->port == 0);
+
+  /* Are we connected to a device?  The caller should have called the wait()
+   * method first to be assured that a device is connected.
+   */
+
+  while (!priv->connected)
+    {
+      /* No, return an error */
+
+      usbhost_trace1(TRACE1_DEVDISCONN, 0);
+      return -ENODEV;
+    }
+
+  DEBUGASSERT(priv->smstate == SMSTATE_ATTACHED);
+
+  /* USB 2.0 spec says at least 50ms delay before port reset. */
+
+  nxsig_usleep(100 * 1000);
+
+  /* Reset the host port */
+
+  sam_hostreset(priv);
+
+  /* Get the current device speed */
+
+  regval = sam_getreg8(SAM_USBHOST_STATUS);
+  if ((regval & USBDEV_STATUS_SPEED_MASK) == USBDEV_STATUS_SPEED_LOW)
+      priv->rhport.hport.speed = USB_SPEED_LOW;
+  else
+      priv->rhport.hport.speed = USB_SPEED_FULL;
+
+  /* Allocate and initialize the root hub port EP0 pipes */
+
+  if (priv->pipelist[0].inuse == false)
+    {
+      struct usbhost_epdesc_s epdesc = {
+                                        .hport = hport,
+                                        .addr = 0
+                                       };
+
+      ret = sam_ctrlep_alloc(priv, &epdesc, &priv->ep0);
+      if (ret < 0)
+          uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret);
+    }
+  else
+      ret = OK;
+
+  return ret;
+}
+
+static int sam_enumerate(FAR struct usbhost_connection_s *conn,
+                         FAR struct usbhost_hubport_s *hport)
+{
+  FAR struct sam_usbhost_s *priv = &g_usbhost;
+  int ret;
+
+  uinfo("ENTRY\n");
+  DEBUGASSERT(hport);
+
+  /* If this is a connection on the root hub, then we need to go to
+   * little more effort to get the device speed.  If it is a connection
+   * on an external hub, then we already have that information.
+   */
+
+ #ifdef CONFIG_USBHOST_HUB
+  if (ROOTHUB(hport))
+ #endif
+    {
+      ret = sam_rh_enumerate(priv, conn, hport);
+      if (ret < 0)
+        {
+          return ret;
+        }
+    }
+
+  /* Then let the common usbhost_enumerate do the real enumeration. */
+
+  uinfo("Enumerate the device\n");
+  priv->smstate = SMSTATE_ENUM;
+  ret = usbhost_enumerate(hport, &hport->devclass);
+
+  /* The enumeration may fail either because of some HCD interfaces failure
+   * or because the device class is not supported.  In either case, we just
+   * need to perform the disconnection operation and make ready for a new
+   * enumeration.
+   */
+
+  if (ret < 0)
+    {
+      /* Return to the disconnected state */
+
+      uerr("ERROR: Enumeration failed: %d\n", ret);
+      sam_gint_disconnected(priv);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: sam_ep0configure
+ *
+ * Description:
+ *   Configure endpoint 0.  This method is normally used internally by the
+ *   enumerate() method but is made available at the interface to support an
+ *   external implementation of the enumeration logic.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter
+ *          from the call to the class create() method.
+ *   ep0 - The (opaque) EP0 endpoint instance
+ *   funcaddr - The USB address of the function containing the
+ *   endpoint that EP0 controls.
+ *   speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH
+ *   maxpacketsize - The maximum number of bytes that can be sent to or
+ *    received from the endpoint in a single data packet
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated
+ *   errno value isreturned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_ep0configure(FAR struct usbhost_driver_s *drvr,
+                            usbhost_ep_t ep0,
+                            uint8_t funcaddr,
+                            uint8_t speed,
+                            uint16_t maxpacketsize)
+{
+  FAR struct sam_usbhost_s *priv = (FAR struct sam_usbhost_s *)drvr;
+  FAR struct sam_pipe_s *pipe;
+
+  uinfo("funcaddr=%d speed=%d maxpacketsize=%d\n",
+                  funcaddr, speed, maxpacketsize);
+  DEBUGASSERT(drvr != NULL && funcaddr < 128 && maxpacketsize <= 64 &&
+                                (unsigned int)ep0 < SAM_USB_NENDPOINTS);
+
+  /* We must have exclusive access to the USB host
+   * hardware and state structures
+   */
+
+  sam_takesem(&priv->exclsem);
+
+  /* Configure the EP0 pipe */
+
+  pipe            = &priv->pipelist[(unsigned int)ep0];
+  pipe->funcaddr  = funcaddr;
+  pipe->speed     = speed;
+  pipe->maxpacket = maxpacketsize;
+  sam_pipe_configure(priv, pipe->idx);
+
+  sam_givesem(&priv->exclsem);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_epalloc
+ *
+ * Description:
+ *   Allocate and configure one endpoint.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a
+ *     parameter from the call to the class create() method.
+ *   epdesc - Describes the endpoint to be allocated.
+ *   ep - A memory location provided by the caller in which to receive the
+ *      allocated endpoint descriptor.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
+                       FAR const struct usbhost_epdesc_s *epdesc,
+                       FAR usbhost_ep_t *ep)
+{
+  FAR struct sam_usbhost_s *priv = (FAR struct sam_usbhost_s *)drvr;
+  int ret;
+
+  uwarn("addr=%d in=%d xfrtype=%d interval=%d mxpacketsize=%d\n",
+    epdesc->addr, epdesc->in, epdesc->xfrtype,
+    epdesc->interval, epdesc->mxpacketsize);
+
+  /* Sanity check.  NOTE that this method should only be called if a device
+   * is connected (because we need a valid low speed indication).
+   */
+
+  DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL);
+
+  /* We must have exclusive access to the USB
+   * host hardware and state structures
+   */
+
+  sam_takesem(&priv->exclsem);
+
+  /* Handler control pipes differently from other endpoint types.  This is
+   * because the normal, "transfer" endpoints are unidirectional an require
+   * only a single pipe.  Control endpoints, however, are bi-diretional
+   * and require two pipes, one for the IN and one for the OUT direction.
+   */
+
+  if (epdesc->xfrtype == USB_EP_ATTR_XFER_CONTROL)
+    {
+      ret = sam_ctrlep_alloc(priv, epdesc, ep);
+    }
+  else
+    {
+      ret = sam_xfrep_alloc(priv, epdesc, ep);
+    }
+
+  sam_givesem(&priv->exclsem);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: sam_epfree
+ *
+ * Description:
+ *   Free and endpoint previously allocated by DRVR_EPALLOC.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *    call to the class create() method.
+ *   ep - The endpoint to be freed.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
+{
+  FAR struct sam_usbhost_s *priv = (FAR struct sam_usbhost_s *)drvr;
+
+  DEBUGASSERT(priv);
+
+  /* We must have exclusive access to the
+   * USB host hardware and state structures
+   */
+
+  sam_takesem(&priv->exclsem);
+
+  /* Halt the pipe and mark the pipe available */
+
+  sam_pipe_free(priv, (intptr_t)ep);
+
+  sam_givesem(&priv->exclsem);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_alloc
+ *
+ * Description:
+ *   Some hardware supports special memory in which request and descriptor
+ *   data can be accessed more efficiently.
+ *   This method provides a mechanism to allocate
+ *   the request/descriptor memory.  If the underlying hardware does
+ *   not support such "special" memory, this functions
+ *   may simply map to kmm_malloc.
+ *   This interface was optimized under a particular assumption. It was
+ *   assumed that the driver maintains a pool of small, pre-allocated buffers
+ *   for descriptor traffic. NOTE that size is not an input, but an output:
+ *   The size of the pre-allocated buffer is returned.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter
+ *      from the call to the class create() method.
+ *   buffer - The address of a memory location provided by
+ *     the caller in which to return the allocated buffer memory address.
+ *   maxlen - The address of a memory location provided by
+ *     the caller in which to return the maximum size of the allocated
+ *     buffer memory.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   - Called from a single thread so no mutual exclusion is required.
+ *   - Never called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_alloc(FAR struct usbhost_driver_s *drvr,
+                     FAR uint8_t **buffer, FAR size_t *maxlen)
+{
+  FAR uint8_t *alloc;
+
+  uinfo("ENTRY\n");
+  DEBUGASSERT(drvr && buffer && maxlen);
+
+  /* There is no special memory requirement for the SAM. */
+
+  alloc = (FAR uint8_t *)kmm_malloc(CONFIG_SAM_DESCSIZE);
+  if (!alloc)
+    {
+      return -ENOMEM;
+    }
+
+  /* Return the allocated address and size of the descriptor buffer */
+
+  *buffer = alloc;
+  *maxlen = CONFIG_SAM_DESCSIZE;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_free
+ *
+ * Description:
+ *   Some hardware supports special memory in which request and descriptor
+ *   data can be accessed more efficiently.
+ *   This method provides a mechanism to free that
+ *   request/descriptor memory.  If the underlying hardware does not support
+ *   such "special" memory, this functions may simply map to kmm_free().
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter
+ *     from the call to the class create() method.
+ *   buffer - The address of the allocated buffer memory to be freed.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   - Never called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
+{
+  /* There is no special memory requirement */
+
+  uinfo("ENTRY\n");
+  DEBUGASSERT(drvr && buffer);
+
+  kmm_free(buffer);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_ioalloc
+ *
+ * Description:
+ *   Some hardware supports special memory in which larger IO buffers can
+ *   be accessed more efficiently.  This method provides a mechanism to
+ *   allocate the request/descriptor memory.
+ *   If the underlying hardware does not support
+ *   such "special" memory, this functions may simply map to kmm_malloc.
+ *
+ * This interface differs from DRVR_ALLOC in that the
+ * buffers are variable-sized.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *      call to the class create() method.
+ *   buffer - The address of a memory location provided by the caller
+ *     in which to return the allocated buffer memory address.
+ *   buflen - The size of the buffer required.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno
+ *   value is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_ioalloc(FAR struct usbhost_driver_s *drvr,
+                         FAR uint8_t **buffer, size_t buflen)
+{
+  FAR uint8_t *alloc;
+
+  uinfo("ENTRY\n");
+  DEBUGASSERT(drvr && buffer && buflen > 0);
+
+  /* There is no special memory requirement */
+
+  alloc = (FAR uint8_t *)kmm_malloc(buflen);
+  if (!alloc)
+    {
+      return -ENOMEM;
+    }
+
+  /* Return the allocated buffer */
+
+  *buffer = alloc;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_iofree
+ *
+ * Description:
+ *   Some hardware supports special memory in which IO data can
+ *   be accessed more efficiently.
+ *   This method provides a mechanism to free that IO buffer
+ *   memory.  If the underlying hardware does not support such
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *       call to the class create() method.
+ *   buffer - The address of the allocated buffer memory to be freed.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno
+ *   value is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
+{
+  /* There is no special memory requirement */
+
+  uinfo("ENTRY\n");
+  DEBUGASSERT(drvr && buffer);
+
+  kmm_free(buffer);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_ctrlin and sam_ctrlout
+ *
+ * Description:
+ *   Process a IN or OUT request on the control endpoint. These methods
+ *   will enqueue the request and wait for it to complete.
+ *   Only one transfer may be queued;
+ *   Neither these methods nor the transfer() method can be called again
+ *   until the control transfer functions returns.
+ *
+ *   These are blocking methods; these functions will not return until the
+ *   control transfer has completed.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *      call to the class create() method.
+ *   ep0 - The control endpoint to send/receive the control request.
+ *   req - Describes the request to be sent.  This request must lie
+ *       in memory created by DRVR_ALLOC.
+ *   buffer - A buffer used for sending the request and for returning any
+ *     responses.  This buffer must be large enough to hold the length value
+ *     in the request description.
+ *     Buffer must have been allocated using DRVR_ALLOC.
+ *
+ *   NOTE: On an IN transaction, req and buffer may refer to the same
+ *    allocated memory.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno
+ *    value is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   - Called from a single thread so no mutual exclusion is required.
+ *   - Never called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int sam_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
+                      FAR const struct usb_ctrlreq_s *req,
+                      FAR uint8_t *buffer)
+{
+  FAR struct sam_usbhost_s *priv = (FAR struct sam_usbhost_s *)drvr;
+  FAR struct sam_pipe_s *pipe;
+  uint16_t buflen;
+  clock_t start;
+  clock_t elapsed;
+  int retries;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && req != NULL &&
+                        (unsigned int)ep0 < SAM_USB_NENDPOINTS);
+  usbhost_vtrace2(SAM_VTRACE2_CTRLIN, req->type, req->req);
+
+  pipe = &priv->pipelist[(unsigned int)ep0];
+
+  /* Extract values from the request */
+
+  buflen = sam_getle16(req->len);
+  uinfo("type:0x%02x req:0x%02x value:0x%02x%02x index:0x%02x%02x len:%d\n",
+        req->type, req->req, req->value[1], req->value[0],
+        req->index[1], req->index[0], buflen);
+
+  /* We must have exclusive access to the USB
+   * host hardware and state structures
+   */
+
+  sam_takesem(&priv->exclsem);
+
+  /* Loop, retrying until the retry time expires */
+
+  for (retries = 0; retries < SAM_RETRY_COUNT; retries++)
+    {
+      /* Send the SETUP request (TXSTP) */
+
+      ret = sam_ctrl_sendsetup(priv, pipe, req);
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_SENDSETUP_FAIL2, -ret);
+          continue;
+        }
+
+      /* Get the start time.  Loop again until the timeout expires */
+
+      start = clock_systime_ticks();
+      do
+        {
+          /* Handle the IN data phase (if any) (TRCPT) */
+
+          if (buflen > 0)
+            {
+              ret = sam_ctrl_recvdata(priv, pipe, buffer, buflen);
+              if (ret < 0)
+                {
+                  usbhost_trace1(SAM_TRACE1_RECVDATA_FAIL, -ret);
+                }
+            }
+
+          /* Handle the status OUT phase */
+
+          if (ret == OK)
+            {
+              ret = sam_ctrl_senddata(priv, pipe, NULL, 0);
+              if (ret == OK)
+                {
+                  /* All success transactions exit here */
+
+                  sam_givesem(&priv->exclsem);
+                  return OK;
+                }
+
+              usbhost_trace1(SAM_TRACE1_SENDSTATUS_FAIL, ret < 0 ?
+                                                       -ret : ret);
+            }
+
+          /* Get the elapsed time (in frames) */
+
+          elapsed = clock_systime_ticks() - start;
+        }
+      while (elapsed < SAM_DATANAK_DELAY);
+    }
+
+  /* All failures exit here after all retries
+   * and timeouts have been exhausted
+   */
+
+  sam_givesem(&priv->exclsem);
+  return -ETIMEDOUT;
+}
+
+static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
+                       FAR const struct usb_ctrlreq_s *req,
+                       FAR const uint8_t *buffer)
+{
+  FAR struct sam_usbhost_s *priv = (FAR struct sam_usbhost_s *)drvr;
+  FAR struct sam_pipe_s *pipe;
+  uint16_t buflen;
+  clock_t start;
+  clock_t elapsed;
+  int retries;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && req != NULL &&
+             (unsigned int)ep0 < SAM_USB_NENDPOINTS);
+  usbhost_vtrace2(SAM_VTRACE2_CTRLOUT, req->type, req->req);
+
+  pipe = &priv->pipelist[(unsigned int)ep0];
+
+  /* Extract values from the request */
+
+  buflen = sam_getle16(req->len);
+  uinfo("type:0x%02x req:0x%02x value:0x%02x%02x index:0x%02x%02x len:%d\n",
+        req->type, req->req, req->value[1], req->value[0],
+        req->index[1], req->index[0], buflen);
+
+  /* We must have exclusive access to the
+   * USB host hardware and state structures
+   */
+
+  sam_takesem(&priv->exclsem);
+
+  /* Loop, retrying until the retry time expires */
+
+  for (retries = 0; retries < SAM_RETRY_COUNT; retries++)
+    {
+      /* Send the SETUP request */
+
+      ret = sam_ctrl_sendsetup(priv, pipe, req);
+      if (ret < 0)
+        {
+          usbhost_trace1(SAM_TRACE1_SENDSETUP_FAIL1, -ret);
+          continue;
+        }
+
+      /* Get the start time.  Loop again until the timeout expires */
+
+      start = clock_systime_ticks();
+      do
+        {
+          /* Handle the data OUT phase (if any) */
+
+          if (buflen > 0)
+            {
+              /* Start DATA out transfer (only one DATA packet) */
+
+              ret = sam_ctrl_senddata(priv, pipe,
+                                     (FAR uint8_t *)buffer, buflen);
+              if (ret < 0)
+                {
+                  usbhost_trace1(SAM_TRACE1_SENDDATA_FAIL, -ret);
+                }
+            }
+
+          /* Handle the status IN phase */
+
+          if (ret == OK)
+            {
+              ret = sam_ctrl_recvdata(priv, pipe, NULL, 0);
+              if (ret == OK)
+                {
+                  /* All success transactins exit here */
+
+                  sam_givesem(&priv->exclsem);
+                  return OK;
+                }
+
+              usbhost_trace1(SAM_TRACE1_RECVSTATUS_FAIL,
+                             ret < 0 ? -ret : ret);
+            }
+
+          /* Get the elapsed time (in frames) */
+
+          elapsed = clock_systime_ticks() - start;
+        }
+      while (elapsed < SAM_DATANAK_DELAY);
+    }
+
+  /* All failures exit here after all retries
+   * and timeouts have been exhausted
+   */
+
+  sam_givesem(&priv->exclsem);
+  return -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Name: sam_transfer
+ *
+ * Description:
+ *   Process a request to handle a transfer descriptor.  This method will
+ *   enqueue the transfer request, blocking until the transfer completes.
+ *   Only one transfer may be  queued; Neither this method nor the ctrlin
+ *   or ctrlout methods can be called again until this function returns.
+ *
+ *   This is a blocking method; this functions will not return until the
+ *   transfer has completed.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *     call to the class create() method.
+ *   ep - The IN or OUT endpoint descriptor for the device endpoint on
+ *     which to perform the transfer.
+ *   buffer - A buffer containing the data to be sent (OUT endpoint) or
+ *    received (IN endpoint). Buffer must have been allocated using
+ *    DRVR_ALLOC.
+ *   buflen - The length of the data to be sent or received.
+ *
+ * Returned Value:
+ *   On success, a non-negative value is returned that indicates the number
+ *   of bytes successfully transferred.  On a failure, a negated errno value
+ *   is returned that indicates the nature of the failure:
+ *
+ *     EAGAIN - If devices NAKs the transfer (or NYET or other error where
+ *              it may be appropriate to restart the entire transaction).
+ *     EPERM  - If the endpoint stalls
+ *     EIO    - On a TX or data toggle error
+ *     EPIPE  - Overrun errors
+ *
+ * Assumptions:
+ *   - Called from a single thread so no mutual exclusion is required.
+ *   - Never called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr,
+                            usbhost_ep_t ep,
+                            FAR uint8_t *buffer,
+                            size_t buflen)
+{
+  FAR struct sam_usbhost_s *priv  = (FAR struct sam_usbhost_s *)drvr;
+  FAR struct sam_pipe_s *pipe;
+  unsigned int idx = (unsigned int)ep;
+  ssize_t nbytes;
+
+  uwarn("pipe%d buffer:0x%p buflen:%d\n",  idx, buffer, buflen);
+
+  DEBUGASSERT(priv && buffer && idx < SAM_USB_NENDPOINTS && buflen > 0);
+  pipe = &priv->pipelist[idx];
+
+  /* We must have exclusive access to the
+   * USB host hardware and state structures
+   */
+
+  sam_takesem(&priv->exclsem);
+
+  /* Handle IN and OUT transfer slightly differently */
+
+  if (pipe->in)
+    {
+      nbytes = sam_in_transfer(priv, pipe, buffer, buflen);
+    }
+  else
+    {
+      nbytes = sam_out_transfer(priv, pipe, buffer, buflen);
+    }
+
+  sam_givesem(&priv->exclsem);
+  return nbytes;
+}
+
+/****************************************************************************
+ * Name: sam_asynch
+ *
+ * Description:
+ *   Process a request to handle a transfer descriptor.  This method will
+ *   enqueue the transfer request and return immediately.  When the transfer
+ *   completes, the callback will be invoked with the provided transfer.
+ *   This method is useful for receiving interrupt transfers which may come
+ *   infrequently.
+ *
+ *   Only one transfer may be queued; Neither this method nor the ctrlin or
+ *   ctrlout methods can be called again until the transfer completes.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *      call to the class create() method.
+ *   ep - The IN or OUT endpoint descriptor for the device endpoint on
+ *      which to perform the transfer.
+ *   buffer - A buffer containing the data to be sent (OUT endpoint)
+ *      or received (IN endpoint). Buffer must have been allocated using
+ *      DRVR_ALLOC
+ *   buflen - The length of the data to be sent or received.
+ *      callback - This function will be called when the transfer completes.
+ *   arg - The arbitrary parameter that will be passed to the callback
+ *      function when the transfer completes.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno
+ *   value is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   - Called from a single thread so no mutual exclusion is required.
+ *   - Never called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_ASYNCH
+static int sam_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
+                        FAR uint8_t *buffer, size_t buflen,
+                        usbhost_asynch_t callback, FAR void *arg)
+{
+  FAR struct sam_usbhost_s *priv  = (FAR struct sam_usbhost_s *)drvr;
+  FAR struct sam_pipe_s *pipe;
+  unsigned int idx = (unsigned int)ep;
+  int ret;
+
+  uinfo("idx: %d buflen: %d\n",  (unsigned int)ep, buflen);
+
+  DEBUGASSERT(priv && buffer && idx < SAM_USB_NENDPOINTS && buflen > 0);
+  pipe = &priv->pipelist[idx];
+
+  /* We must have exclusive access to the
+   * USB host hardware and state structures
+   */
+
+  sam_takesem(&priv->exclsem);
+
+  /* Handle IN and OUT transfer slightly differently */
+
+  if (pipe->in)
+    {
+      ret = sam_in_asynch(priv, pipe, buffer, buflen, callback, arg);
+    }
+  else
+    {
+      ret = sam_out_asynch(priv, pipe, buffer, buflen, callback, arg);
+    }
+
+  sam_givesem(&priv->exclsem);
+  return ret;
+}
+#endif /* CONFIG_USBHOST_ASYNCH */
+
+/****************************************************************************
+ * Name: sam_cancel
+ *
+ * Description:
+ *   Cancel a pending transfer on an endpoint.  Cancelled synchronous or
+ *   asynchronous transfer will complete normally with the error -ESHUTDOWN.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *      call to the class create() method.
+ *   ep - The IN or OUT endpoint descriptor for the device endpoint on
+ *      which an asynchronous transfer should be transferred.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure.
+ *
+ ****************************************************************************/
+
+static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
+{
+  FAR struct sam_usbhost_s *priv  = (FAR struct sam_usbhost_s *)drvr;
+  FAR struct sam_pipe_s *pipe;
+  unsigned int idx = (unsigned int)ep;
+  irqstate_t flags;
+
+  uinfo("idx: %u: %d\n",  idx);
+
+  DEBUGASSERT(priv && idx < SAM_USB_NENDPOINTS);
+  pipe = &priv->pipelist[idx];
+
+  /* We need to disable interrupts to avoid race conditions with the
+   * asynchronous completion of the transfer being cancelled.
+   */
+
+  flags = enter_critical_section();
+
+  /* Halt the pipe */
+
+  sam_transfer_abort(priv, pipe, CHREASON_CANCELLED);
+  pipe->result = -ESHUTDOWN;
+
+  /* Is there a thread waiting for this transfer to complete? */
+
+  if (pipe->waiter)
+    {
+#ifdef CONFIG_USBHOST_ASYNCH
+  /* Yes.. there should not also be a callback scheduled */
+
+  DEBUGASSERT(pipe->callback == NULL);
+#endif
+
+      /* Wake'em up! */
+
+      sam_givesem(&pipe->waitsem);
+      pipe->waiter = false;
+    }
+
+#ifdef CONFIG_USBHOST_ASYNCH
+  /* No.. is an asynchronous callback expected when the transfer
+   * completes?
+   */
+
+  else if (pipe->callback)
+    {
+      usbhost_asynch_t callback;
+      FAR void *arg;
+
+      /* Extract the callback information */
+
+      callback       = pipe->callback;
+      arg            = pipe->arg;
+
+      pipe->callback = NULL;
+      pipe->arg      = NULL;
+      pipe->count = 0;
+
+      /* Then perform the callback */
+
+      callback(arg, -ESHUTDOWN);
+    }
+#endif
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: sam_connect
+ *
+ * Description:
+ *   New connections may be detected by an attached hub.  This method is the
+ *   mechanism that is used by the hub class to introduce a new connection
+ *   and port description to the system.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *      call to the class create() method.
+ *   hport - The descriptor of the hub port that detected the connection
+ *      related event
+ *   connected - True: device connected; false: device disconnected
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_HUB
+static int sam_connect(FAR struct usbhost_driver_s *drvr,
+                         FAR struct usbhost_hubport_s *hport,
+                         bool connected)
+{
+  FAR struct sam_usbhost_s *priv = (FAR struct sam_usbhost_s *)drvr;
+  irqstate_t flags;
+
+  DEBUGASSERT(priv != NULL && hport != NULL);
+
+  /* Set the connected/disconnected flag */
+
+  hport->connected = connected;
+  uinfo("Hub port %d connected: %s\n",
+                                      hport->port, connected ? "YES" : "NO");
+
+  /* Report the connection event */
+
+  flags = enter_critical_section();
+  priv->hport = hport;
+  if (priv->pscwait)
+    {
+      priv->pscwait = false;
+      sam_givesem(&priv->pscsem);
+    }
+
+  leave_critical_section(flags);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_disconnect
+ *
+ * Description:
+ *   Called by the class when an error occurs and driver has been
+ *   disconnected. The USB host driver should discard the handle to the
+ *   class instance (it is stale) and not attempt any further interaction
+ *   with the class driver instance (until a new instance is received from
+ *   the create() method). The driver should not called the class
+ *   disconnected() method.
+ *
+ * Input Parameters:
+ *   drvr - The USB host driver instance obtained as a parameter from the
+ *      call to the class create() method.
+ *   hport - The port from which the device is being disconnected.
+ *      Might be a port on a hub.
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   - Only a single class bound to a single device is supported.
+ *   - Never called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static void sam_disconnect(FAR struct usbhost_driver_s *drvr,
+                           FAR struct usbhost_hubport_s *hport)
+{
+  DEBUGASSERT(hport != NULL);
+  hport->devclass = NULL;
+}
+
+/****************************************************************************
+ * Pipe Helpers
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_reset_pipes
+ *
+ * Description:
+ *   Reset pipes
+ *  \param     priv       Pointer to driver instance
+ *  \param[in] warm_reset Handles runtime USB reset
+ *
+ ****************************************************************************/
+
+static void sam_reset_pipes(struct sam_usbhost_s *priv, bool warm_reset)
+{
+  FAR struct sam_pipe_s *pipe;
+  uint8_t i;
+
+  /* Reset pipes */
+
+  for (i = 0; i < SAM_USB_NENDPOINTS; i++)
+    {
+      /* Get the pipe structure */
+
+      pipe = &priv->pipelist[i];
+
+      if (warm_reset)
+        {
+          /* Skip free pipes */
+
+          if (pipe->pipestate_general == USB_H_PIPE_S_FREE)
+            continue;
+
+          /* Restore physical pipe configurations */
+
+          sam_pipe_configure(priv, i);
+
+          /* Abort transfer (due to reset) */
+
+          if (pipe->eptype == USB_EP_ATTR_XFER_CONTROL)
+            {
+              /* Force a callback for control endpoints */
+
+              pipe->pipestate_general = USB_H_PIPE_S_SETUP;
+            }
+
+          sam_transfer_terminate(priv, pipe, USB_H_RESET);
+        }
+      else
+        pipe->pipestate_general = USB_H_PIPE_S_FREE;
+    }
+}
+
+/****************************************************************************
+ * Name: sam_pipe_reset
+ *
+ * Description:
+ *   Reset and disable one pipe.
+ *
+ ****************************************************************************/
+
+static void sam_pipe_reset(struct sam_usbhost_s *priv, uint8_t epno)
+{
+  struct sam_pipe_s *pipe = &priv->pipelist[epno];
+
+  uinfo("pipe%d\n", pipe->idx);
+
+  /* Disable pipe interrupts */
+
+  sam_putreg8(0x3f, SAM_USBHOST_PINTENCLR(epno));
+  sam_putreg8(0x3f, SAM_USBHOST_PINTFLAG(epno));
+
+  /* Reset pipe status */
+
+  pipe->pipestate = USB_H_PIPE_S_FREE;
+  pipe->stalled   = false;
+  pipe->pending   = false;
+  pipe->halted    = false;
+  pipe->zlpsent   = false;
+  pipe->txbusy    = false;
+  pipe->rxactive  = false;
+}
+
+/****************************************************************************
+ * Name: sam_pipeset_reset
+ *
+ * Description:
+ *   Reset and disable a set of pipes.
+ *
+ ****************************************************************************/
+
+static void sam_pipeset_reset(struct sam_usbhost_s *priv, uint16_t epset)
+{
+  uint32_t bit;
+  int epno;
+
+  uinfo("ENTRY\n");
+
+  /* Reset each pipe in the set */
+
+  for (epno = 0, bit = 1, epset &= SAM_EPSET_ALL;
+       epno < SAM_USB_NENDPOINTS && epset != 0;
+       epno++, bit <<= 1)
+    {
+      /* Is this pipe in the set? */
+
+      if ((epset & bit) != 0)
+        {
+           sam_pipe_reset(priv, epno);
+           epset &= ~bit;
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: sam_vbusdrive
+ *
+ * Description:
+ *   Drive the Vbus +5V.
+ *
+ * Input Parameters:
+ *   priv  - USB host driver private data structure.
+ *   state - True: Drive, False: Don't drive
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void sam_vbusdrive(FAR struct sam_usbhost_s *priv, bool state)
+{
+  /* Enable/disable the external charge pump */
+
+  sam_usbhost_vbusdrive(0, state);
+
+  up_mdelay(200);
+}
+
+/****************************************************************************
+ * Name: sam_pipe_interrupt
+ *
+ * Description:
+ *   Handle the USB pipe interrupt
+ *
+ ****************************************************************************/
+
+static void sam_pipe_interrupt(struct sam_usbhost_s *priv, int idx)
+{
+  FAR struct sam_pipe_s *pipe;
+  uint8_t pipisr;
+  uint8_t pipimr;
+
+  DEBUGASSERT((unsigned)idx < SAM_USB_NENDPOINTS);
+
+  /* Get the pipe structure */
+
+  pipe = &priv->pipelist[idx];
+
+  /* Get the pipe irq */
+
+  pipisr = sam_getreg8(SAM_USBHOST_PINTFLAG(idx));
+  pipimr = sam_getreg8(SAM_USBHOST_PINTENSET(idx));
+  uinfo("pipe%d PINTFLAG:0x%x PINTENSET:0x%x\n", idx, pipisr, pipimr);
+
+  /* Host pipe stall interrupt */
+
+  if (pipisr & USBHOST_PINTFLAG_STALL)
+    {
+      /* clear the flag */
+
+      sam_putreg8(USBHOST_PINTFLAG_STALL, SAM_USBHOST_PINTFLAG(idx));
+      uwarn("STALL =0x%x pktsize=0x%x ctrlpipe=0x%x statuspipe=0x%x\n",
+                                            pipisr,
+                                            pipe->descb[0]->pktsize,
+                                            pipe->descb[0]->ctrlpipe,
+                                            pipe->descb[0]->statuspipe);
+
+      sam_transfer_abort(priv, pipe, USB_H_STALL);
+      return;
+    }
+
+  /* Host pipe error interrupt */
+
+  if (pipisr & USBHOST_PINTFLAG_PERR)
+    {
+      /* clear the flag */
+
+      sam_putreg8(USBHOST_PINTFLAG_PERR, SAM_USBHOST_PINTFLAG(idx));
+      uwarn("PERR =0x%x pktsize=0x%x ctrlpipe=0x%x statuspipe=0x%x\n",
+              pipisr,
+              pipe->descb[0]->pktsize,
+              pipe->descb[0]->ctrlpipe,
+              pipe->descb[0]->statuspipe);
+
+      /* Get and ACK error */
+
+      switch (pipe->descb[0]->statuspipe & (USBHOST_STATUSPIPE_DTGLER |
+                                           USBHOST_STATUSPIPE_TOUTER |
+                                           USBHOST_STATUSPIPE_DAPIDER))
+        {
+          case USBHOST_STATUSPIPE_DTGLER:
+            pipe->pipestatus_general = USB_H_ERR;
+          break;
+
+          case USBHOST_STATUSPIPE_TOUTER:
+            pipe->pipestatus_general = USB_H_TIMEOUT;
+            pipe->result = -ETIMEDOUT;
+          break;
+
+          case USBHOST_STATUSPIPE_PIDER:
+
+          case USBHOST_STATUSPIPE_DAPIDER:
+          default:
+            pipe->pipestatus_general = USB_H_ERR;
+          break;
+        }
+
+      pipe->descb[0]->statuspipe = 0;
+
+      sam_transfer_abort(priv, pipe, USB_H_ERR);
+      return;
+    }
+
+  /* Host pipe transfer fail interrupt */
+
+  if (pipisr & USBHOST_PINTFLAG_TRFAIL)
+    {
+      /* clear the flag */
+
+      sam_putreg8(USBHOST_PINTFLAG_TRFAIL, SAM_USBHOST_PINTFLAG(idx));
+      uwarn("TRFAIL =0x%x pktsize=0x%x ctrlpipe=0x%x statuspipe=0x%x\n",
+                    pipisr,
+                    pipe->descb[0]->pktsize,
+                    pipe->descb[0]->ctrlpipe,
+                    pipe->descb[0]->statuspipe);
+
+      uint8_t status_bk = pipe->descb[0]->stausbk;
+      if (status_bk)
+        {
+          pipe->descb[0]->stausbk = 0;
+
+          /* Ignore ERRORFLOW and handle CRCERR */
+
+          if (pipe->eptype != USB_EP_ATTR_XFER_ISOC &&
+              status_bk == USBHOST_STATUSBK_ERRORFLOW)
+            {
+              /* Ignore ERRORFLOW on none ISO pipes */
+            }
+          else
+            {
+              pipe->pipestatus_general = USB_H_ERR;
+              sam_transfer_abort(priv, pipe, USB_H_ERR);
+            }
+        }
+
+      return;
+    }
+
+  /* TRCPT: transfer complete */
+
+  if ((pipisr & pipimr & (USBHOST_PINTFLAG_TRCPT0 |
+                          USBHOST_PINTFLAG_TRCPT1)) != 0)
+  {
+    /* clear the flag */
+
+    sam_putreg8((USBHOST_PINTFLAG_TRCPT0 |
+                 USBHOST_PINTFLAG_TRCPT1), SAM_USBHOST_PINTFLAG(idx));
+
+    if ((sam_getreg8(SAM_USBHOST_PCFG(idx)) & USBHOST_PCFG_PTOKEN_MASK) ==
+                                              USBHOST_PCFG_PTOKEN_IN)
+      {
+        uwarn("pipe%d IN TRCPT pktsize=0x%x\n",
+                                idx,
+                                pipe->descb[0]->pktsize);
+        if (idx > 0)
+          sam_recv_continue(priv, pipe);
+        pipe->result = 0;
+        sam_pipe_wakeup(priv, pipe);
+      }
+    else
+      {
+        uwarn("pipe%d OUT TRCPT pktsize=0x%x\n",
+                      idx,
+                      pipe->descb[0]->pktsize);
+        if (idx > 0)
+          sam_send_continue(priv, pipe);
+
+        pipe->result = 0;
+        sam_pipe_wakeup(priv, pipe);
+      }
+
+    return;
+  }
+
+  /* Host pipe transmitted setup interrupt */
+
+  if (pipisr & pipimr & USBHOST_PINTFLAG_TXSTP)
+    {
+      /* clear the flag */
+
+      sam_putreg8(USBHOST_PINTFLAG_TXSTP, SAM_USBHOST_PINTFLAG(idx));
+      sam_putreg8(USBHOST_PINTFLAG_TXSTP, SAM_USBHOST_PINTENCLR(idx));
+
+      /* Reset data toggle for DATA */
+
+      sam_putreg8(USBHOST_PSTATUS_DTGL, SAM_USBHOST_PSTATUSSET(idx));
+
+      /* Start DATA phase */
+
+      if (priv->ctrl_buffer[0] & 0x80) /* 1 = Device to Host */
+        {
+          /* IN */
+
+          uwarn("pipe%d IN TXSTP\n", idx);
+          pipe->pipestate = USB_H_PIPE_S_DATI; /* Pipe in data IN stage */
+
+          /* Start IN requests */
+
+          pipe->result = 0;
+          sam_pipe_wakeup(priv, pipe);
+        }
+      else
+        {
+          /* OUT */
+
+          uwarn("pipe%d OUT TXSTP\n", idx);
+            if (priv->ctrl_buffer[6] || priv->ctrl_buffer[7]) /* setup packet wLength[2] */
+            {
+              pipe->pipestate = USB_H_PIPE_S_DATO; /* Pipe in data OUT stage */
+
+              /* Start OUT */
+
+              pipe->result = 0;
+              sam_pipe_wakeup(priv, pipe);
+            }
+          else
+            {
+              /* No DATA phase */
+
+              uwarn("pipe%d OUT TXSTP ZLP\n", idx);
+              pipe->pipestate = USB_H_PIPE_S_STATI; /* Pipe in control status IN stage */
+
+              /* Start IN ZLP request */
+
+              pipe->result = 0;
+              sam_pipe_wakeup(priv, pipe);
+            }
+        }
+
+      return;
+    }
+}
+
+/****************************************************************************
+ * Name: sam_usbhost_interrupt
+ *
+ * Description:
+ *   Handle the USB interrupt.
+ *   Host Mode
+ *
+ ****************************************************************************/
+
+static int sam_usbhost_interrupt(int irq, void *context, void *arg)
+{
+  struct sam_usbhost_s *priv = (struct sam_usbhost_s *)arg;
+  uint16_t isr;
+  uint16_t imr;
+  uint16_t regval;
+  uint16_t pending;
+  uint16_t pendingpipe;
+  int i;
+
+  /* Get the set of pending device interrupts */
+
+  isr = sam_getreg16(SAM_USBHOST_INTFLAG);
+  imr = sam_getreg16(SAM_USBHOST_INTENSET);
+  pending = isr & imr;
+
+  /* Get the set of pending Pipe interrupts */
+
+  pendingpipe = sam_getreg16(SAM_USBHOST_PINTSMRY);
+
+  /* Handle all pending USB interrupts */
+
+  /* Serve Pipe Interrupts first */
+
+  if (pendingpipe)
+    {
+      usbhost_vtrace1(TRACE_INTDECODE(SAM_TRACEINTID_PENDING_PIPE),
+                      pendingpipe);
+      for (i = 0; i < SAM_USB_NENDPOINTS; i++)
+        {
+          if ((pendingpipe & USBHOST_PINTSMRY_PIPEINT(i)))
+            {
+              usbhost_vtrace1(TRACE_INTDECODE(SAM_TRACEINTID_PIPENO),
+                             (uint16_t)i);
+              sam_pipe_interrupt(priv, i);
+            }
+        }
+    }
+  else
+    {
+      /* Host SOF interrupt */
+
+      if (isr & USBHOST_INT_HSOF) /* Clear the flag */
+        sam_putreg16(USBHOST_INT_HSOF, SAM_USBHOST_INTFLAG);
+      if (isr & USBHOST_INT_RST) /* Host reset interrupt */
+        {
+          sam_putreg16(USBHOST_INT_RST, SAM_USBHOST_INTFLAG);
+          sam_reset_pipes(priv, true);
+          return OK;
+        }
+      else if (pending & USBHOST_INT_DDISC)
+        {
+          /* Host disconnect interrupt */
+
+          /* clear the flag */
+
+          sam_putreg16((USBHOST_INT_DDISC |
+                        USBHOST_INT_DCONN), SAM_USBHOST_INTFLAG);
+
+          /* Disable disconnect interrupt.
+           * Disable wakeup/resumes interrupts,
+           * in case of disconnection during suspend mode
+           */
+
+          sam_putreg16((USBHOST_INT_DDISC  |
+                        USBHOST_INT_WAKEUP |
+                        USBHOST_INT_DNRSM  |
+                        USBHOST_INT_UPRSM), SAM_USBHOST_INTENCLR);
+
+          /* Stop reset signal, in case of disconnection during reset */
+
+          regval = sam_getreg16(SAM_USBHOST_CTRLB);
+          regval &= ~USBHOST_CTRLB_BUSRESET;
+          sam_putreg16(regval, SAM_USBHOST_CTRLB);
+
+          /* Enable connection and wakeup interrupts */
+
+          sam_putreg16((USBHOST_INT_DCONN  |
+                        USBHOST_INT_WAKEUP |
+                        USBHOST_INT_DNRSM  |
+                        USBHOST_INT_UPRSM), SAM_USBHOST_INTFLAG);
+          sam_putreg16((USBHOST_INT_DCONN  |
+                        USBHOST_INT_WAKEUP |
+                        USBHOST_INT_DNRSM  |
+                        USBHOST_INT_UPRSM), SAM_USBHOST_INTENSET);
+
+          priv->suspend_start = 0;
+          priv->resume_start  = 0;
+
+          /* PORT_CONNECTION: connect status changed */
+
+          sam_gint_disconnected(priv);
+          return OK;
+        }
+      else if (pending & USBHOST_INT_DCONN)
+        {
+          /* Host connect interrupt */
+
+          /* clear the flag */
+
+          /* Reserve the CONN flag for connection check */
+
+          sam_putreg16 (USBHOST_INT_DCONN, SAM_USBHOST_INTENCLR);
+
+          /* Enable disconnection interrupt */
+
+          sam_putreg16(USBHOST_INT_DDISC, SAM_USBHOST_INTFLAG);
+          sam_putreg16(USBHOST_INT_DDISC, SAM_USBHOST_INTENSET);
+
+          /* Enable SOF */
+
+          regval  = sam_getreg16(SAM_USBHOST_CTRLB);
+          regval |= USBHOST_CTRLB_SOFE | USBHOST_CTRLB_BUSRESET;
+          sam_putreg16(regval, SAM_USBHOST_CTRLB);
+
+          priv->suspend_start = 0;
+          priv->resume_start  = 0;
+
+          /* PORT_CONNECTION: connect status changed */
+
+          sam_gint_connected(priv);
+          return OK;
+        }
+
+          /* Wake up to power */
+
+      if ((isr & USBHOST_INT_WAKEUP) && (imr & USBHOST_INT_DCONN))
+        {
+          /* clear the flag */
+
+          sam_putreg16(USBHOST_INT_WAKEUP, SAM_USBHOST_INTFLAG);
+          sam_vbusdrive(priv, true);
+        }
+
+          /* Resume */
+
+      if (pending & (USBHOST_INT_WAKEUP |
+                     USBHOST_INT_UPRSM  |
+                    USBHOST_INT_DNRSM))
+        {
+          sam_putreg16((USBHOST_INT_WAKEUP |
+                        USBHOST_INT_UPRSM  |
+                        USBHOST_INT_DNRSM), SAM_USBHOST_INTFLAG);
+
+          sam_putreg16((USBHOST_INT_WAKEUP |
+                        USBHOST_INT_UPRSM  |
+                        USBHOST_INT_DNRSM), SAM_USBHOST_INTENCLR);
+
+          sam_putreg16((USBHOST_INT_RST |
+                        USBHOST_INT_DDISC), SAM_USBHOST_INTENSET);
+
+          /* Enable SOF */
+
+          regval  = sam_getreg16(SAM_USBHOST_CTRLB);
+          regval |= USBHOST_CTRLB_RESUME | USBHOST_CTRLB_SOFE;
+          sam_putreg16(regval, SAM_USBHOST_CTRLB);
+
+          /* Wait 50ms before restarting transfer */
+
+          priv->resume_start = 50;
+          sam_add_sof_user(priv);
+          return OK;
+        }
+    }
+
+  /* Just ignore unexpected interrupts */
+
+  sam_putreg16(isr, SAM_USBHOST_INTFLAG);
+  return OK;
+}
+
+/****************************************************************************
+ * Initialization/Reset
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_hostreset
+ ****************************************************************************/
+
+static void sam_hostreset(struct sam_usbhost_s *priv)
+{
+  uint16_t regval;
+
+  uinfo("ENTRY\n");
+
+  /* Make sure that clocking is enabled to the USB peripheral. */
+
+  sam_enableclks();
+  priv->hoststate = USB_HOSTSTATE_DEFAULT;
+  regval = sam_getreg16(SAM_USBHOST_CTRLB);
+  regval &= ~USBHOST_CTRLB_BUSRESET;
+  sam_putreg16(regval, SAM_USBHOST_CTRLB);
+
+  /* Clear all pending interrupt status */
+
+  regval = USBHOST_INT_HSOF | USBHOST_INT_RST | USBHOST_INT_WAKEUP |
+           USBHOST_INT_DNRSM | USBHOST_INT_UPRSM | USBHOST_INT_RAMACER |
+           USBHOST_INT_DCONN | USBHOST_INT_DDISC;
+  sam_putreg16(regval, SAM_USBHOST_INTFLAG);
+
+  /* Enable normal operational interrupts */
+
+  regval = USBHOST_INT_WAKEUP | USBHOST_INT_DDISC;
+  sam_putreg16(regval, SAM_USBHOST_INTENSET);
+
+  sam_dumppipe(priv, EP0);
+}
+
+/****************************************************************************
+ * Name: sam_host_initialize
+ *
+ * Description:
+ *   Initialize/re-initialize hardware for host mode operation.  At present,
+ *   this function is called only from sam_hw_initialize().  But if OTG mode
+ *   were supported, this function would also be called to swtich between
+ *   host and device modes on a connector ID change interrupt.
+ *
+ * Input Parameters:
+ *   priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void sam_host_initialize(FAR struct sam_usbhost_s *priv)
+{
+  /* Drive Vbus +5V (the smoke test). Should be done elsewhere in OTG mode. */
+
+  sam_vbusdrive(priv, true);
+
+  /* Enable interrupts to detect connection */
+
+  sam_putreg16(USBHOST_INT_DCONN |
+               USBHOST_INT_RST   |
+               USBHOST_INT_WAKEUP, SAM_USBHOST_INTENSET);
+}
+
+/****************************************************************************
+ * Name: sam_sw_initialize
+ *
+ * Description:
+ *   One-time setup of the host driver state structure.
+ *
+ * Input Parameters:
+ *   priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static inline void sam_sw_initialize(FAR struct sam_usbhost_s *priv)
+{
+  FAR struct usbhost_driver_s *drvr;
+  FAR struct usbhost_hubport_s *hport;
+  int epno;
+
+  /* Initialize the device state structure.  NOTE: many fields
+   * have the initial value of zero and, hence, are not explicitly
+   * initialized here.
+   */
+
+  memset(priv, 0, sizeof(struct sam_usbhost_s));
+
+  /* Initialize the device operations */
+
+  drvr                 = &priv->drvr;
+  drvr->ep0configure   = sam_ep0configure;
+  drvr->epalloc        = sam_epalloc;
+  drvr->epfree         = sam_epfree;
+  drvr->alloc          = sam_alloc;
+  drvr->free           = sam_free;
+  drvr->ioalloc        = sam_ioalloc;
+  drvr->iofree         = sam_iofree;
+  drvr->ctrlin         = sam_ctrlin;
+  drvr->ctrlout        = sam_ctrlout;
+  drvr->transfer       = sam_transfer;
+#ifdef CONFIG_USBHOST_ASYNCH
+  drvr->asynch         = sam_asynch;
+#endif
+  drvr->cancel         = sam_cancel;
+#ifdef CONFIG_USBHOST_HUB
+  drvr->connect        = sam_connect;
+#endif
+  drvr->disconnect     = sam_disconnect;
+
+  /* Initialize the public port representation */
+
+  hport                = &priv->rhport.hport;
+  hport->drvr          = drvr;
+#ifdef CONFIG_USBHOST_HUB
+  hport->parent        = NULL;
+#endif
+  hport->ep0           = priv->ep0;
+  hport->speed         = USB_SPEED_FULL;
+
+  /* Initialize function address generation logic */
+
+  usbhost_devaddr_initialize(&priv->rhport);
+
+  /* Initialize the pipe list */
+
+  for (epno = 0; epno < SAM_USB_NENDPOINTS; epno++)
+    {
+      priv->pipelist[epno].idx = epno;
+      nxsem_init(&priv->pipelist[epno].waitsem, 0, 0);
+      sem_setprotocol(&priv->pipelist[epno].waitsem, SEM_PRIO_NONE);
+
+      sam_putreg8(USBHOST_PSTATUS_PFREEZE, SAM_USBHOST_PSTATUSSET(epno));
+
+  /* set descriptor addresses */
+
+    priv->pipelist[epno].descb[0] = &priv->pipe_descriptors[(epno << 1)];
+    priv->pipelist[epno].descb[1] = &priv->pipe_descriptors[(epno << 1) + 1];
+    }
+
+  sam_reset_pipes(priv, false);
+
+  /* Initialize semaphores */
+
+  nxsem_init(&priv->pscsem,  0, 0);
+  nxsem_init(&priv->exclsem, 0, 1);
+
+  /* The pscsem semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  sem_setprotocol(&priv->pscsem, SEM_PRIO_NONE);
+
+  /* Initialize the driver state data */
+
+  priv->smstate   = SMSTATE_DETACHED;
+  priv->connected = false;
+  priv->change    = false;
+
+  priv->irqset    = 0;
+}
+
+/****************************************************************************
+ * Name: sam_hw_initialize
+ *
+ * Description:
+ *   One-time setup of the host controller harware for normal operations.
+ *
+ * Input Parameters:
+ *   priv -- USB host driver private data structure.
+ *
+ * Returned Value:
+ *   Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static inline int sam_hw_initialize(FAR struct sam_usbhost_s *priv)
+{
+  uint16_t regval;
+  uint32_t padcalib;
+  uint8_t calib_transn;
+  uint8_t calib_transp;
+  uint8_t calib_trim;
+
+  /* Set up the USB DP/DM pins */
+
+  sam_portconfig(PORT_USB_DP | PORT_PULL_NONE);
+  sam_portconfig(PORT_USB_DM | PORT_PULL_NONE);
+
+  /* To use the USB, the programmer must first configure
+   * inputthe USB clock
+   */
+
+  sam_enableclks();
+
+  /* full reset USB */
+
+  sam_ctrla_write(USB_CTRLA_SWRST);
+
+  /* Load USB factory calibration values from NVRAM */
+
+  calib_transn = (getreg32(SAM_FUSES_USBTRANSN_ADDR) &
+                  SAM_FUSES_USBTRANSN_MASK) >> SAM_FUSES_USBTRANSN_SHIFT;
+  if (calib_transn == 0 || calib_transn == 0x1f)
+    calib_transn = 0x9;
+
+  calib_transp = (getreg32(SAM_FUSES_USBTRANSP_ADDR) &
+                  SAM_FUSES_USBTRANSP_ADDR) >> SAM_FUSES_USBTRANSP_SHIFT;
+  if (calib_transp == 0 || calib_transp == 0x1f)
+    calib_transp = 0x19;
+
+  calib_trim   = (getreg32(SAM_FUSES_USBTRIM_ADDR) &
+                  SAM_FUSES_USBTRIM_MASK) >> SAM_FUSES_USBTRIM_SHIFT;
+  if (calib_trim == 0 || calib_trim == 0x7)
+    calib_trim = 0x6;
+
+  padcalib     = USB_PADCAL_TRANSP(calib_transp) |
+                 USB_PADCAL_TRANSN(calib_transn) |
+                 USB_PADCAL_TRIM(calib_trim);
+
+  sam_putreg16(padcalib, SAM_USB_PADCAL);
+  uinfo("PADCAL: 0x%x\n", padcalib); /* 0x6259 */
+
+  sam_putreg8(USB_QOSCTRL_CQOS(3) | USB_QOSCTRL_DQOS(3), SAM_USB_QOSCTRL);
+
+  /* Enable USB core */
+
+  sam_ctrla_write(USB_CTRLA_ENABLE |
+                 USB_CTRLA_RUNSTBY |
+                 USB_CTRLA_MODE_HOST);
+
+  /* Reset and disable pipes */
+
+  sam_pipeset_reset(priv, SAM_EPSET_ALL);
+
+  /* clear all previous descriptor data so no accidental
+   * DMA transfers could happen
+   */
+
+  memset((uint8_t *)(&priv->pipe_descriptors[0]), 0,
+                    sizeof(priv->pipe_descriptors));
+
+  /* Init descriptor base address */
+
+  sam_putreg32((uint32_t)&priv->pipe_descriptors, SAM_USB_DESCADD);
+
+  regval = USBHOST_CTRLB_SOFE |
+           USBHOST_CTRLB_SPDCONF_LF |
+           USBHOST_CTRLB_VBUSOK;
+  sam_putreg16(regval, SAM_USBHOST_CTRLB);
+
+  /* Disable all interrupts */
+
+  sam_putreg16(USBHOST_INT_HSOF | USBHOST_INT_RST | USBHOST_INT_WAKEUP |
+               USBHOST_INT_DNRSM | USBHOST_INT_UPRSM | USBHOST_INT_RAMACER |
+               USBHOST_INT_DCONN | USBHOST_INT_DDISC,
+               SAM_USBHOST_INTENCLR);
+
+  /* Initialize host mode and return success */
+
+  sam_host_initialize(priv);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_usbhost_initialize
+ *
+ * Description:
+ *   Initialize USB host device controller hardware.
+ *
+ * Input Parameters:
+ *   controller -- If the device supports more than USB host controller, then
+ *     this identifies which controller is being initialized.  Normally, this
+ *     is just zero.
+ *
+ * Returned Value:
+ *   And instance of the USB host interface.  The controlling task should
+ *   use this interface to (1) call the wait() method to wait for a device
+ *   to be connected, and (2) call the enumerate() method to bind the device
+ *   to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ *   to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ *   Otherwise, there is a race condition if the device is already connected.
+ *
+ ****************************************************************************/
+
+FAR struct usbhost_connection_s *sam_usbhost_initialize(int controller)
+{
+  /* At present, there is only support for a single OTG FS host. Hence it is
+   * pre-allocated as g_usbhost.  However, in most code, the private data
+   * structure will be referenced using the 'priv' pointer (rather than the
+   * global data) in order to simplify any
+   * future support for multiple devices.
+   */
+
+  FAR struct sam_usbhost_s *priv = &g_usbhost;
+
+  /* Sanity checks */
+
+  DEBUGASSERT(controller == 0);
+
+  /* Reset the state of the host driver */
+
+  sam_sw_initialize(priv);
+
+  /* Initialize the USB core */
+
+  sam_hw_initialize(priv);
+
+  priv->suspend_start   = 0;
+  priv->resume_start    = 0;
+  priv->pipes_unfreeze  = 0;
+  priv->n_ctrl_req_user = 0;
+  priv->n_sof_user      = 0;
+
+  /* Attach USB host controller interrupt handler */
+
+  if (irq_attach(SAM_IRQ_USB, sam_usbhost_interrupt, priv) != 0)
+    usbhost_vtrace1(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                  (uint16_t)SAM_IRQ_USB);
+
+  if (irq_attach(SAM_IRQ_USBSOF, sam_usbhost_interrupt, priv) != 0)
+    usbhost_vtrace1(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                  (uint16_t)SAM_IRQ_USBSOF);
+
+  if (irq_attach(SAM_IRQ_USBTRCPT0, sam_usbhost_interrupt, priv) != 0)
+    usbhost_vtrace1(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                  (uint16_t)SAM_IRQ_USBTRCPT0);
+
+  if (irq_attach(SAM_IRQ_USBTRCPT1, sam_usbhost_interrupt, priv) != 0)
+    usbhost_vtrace1(TRACE_DEVERROR(SAM_TRACEERR_IRQREGISTRATION),
+                                  (uint16_t)SAM_IRQ_USBTRCPT1);
+
+  /* Enable interrupts at the interrupt controller */
+
+  up_enable_irq(SAM_IRQ_USB);
+  up_enable_irq(SAM_IRQ_USBSOF);
+  up_enable_irq(SAM_IRQ_USBTRCPT0);
+  up_enable_irq(SAM_IRQ_USBTRCPT1);
+
+  return &g_usbconn;
+}
+#endif /* CONFIG_USBHOST */
+
+#endif /* CONFIG_SAMD5E5_USB */
diff --git a/arch/arm/src/samd5e5/sam_usb.h b/arch/arm/src/samd5e5/sam_usb.h
index 490827d..b9bb1f4 100644
--- a/arch/arm/src/samd5e5/sam_usb.h
+++ b/arch/arm/src/samd5e5/sam_usb.h
@@ -1,4 +1,4 @@
-/******************************************************************************
+/****************************************************************************
  * arch/arm/src/samd5e5/sam_usb.h
  *
  *   Copyright (C) 2015 Filament - www.filament.com
@@ -35,12 +35,12 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- *****************************************************************************/
+ ****************************************************************************/
 
 #ifndef __ARCH_ARM_SRCSAMD5E5_SAM_USB_H
 #define __ARCH_ARM_SRCSAMD5E5_SAM_USB_H
 
-/*****************************************************************************
+/****************************************************************************
  * Included Files
  ****************************************************************************/
 
@@ -51,7 +51,7 @@
 #include "chip.h"
 #include "hardware/sam_usb.h"
 
-/*****************************************************************************
+/****************************************************************************
  * Public Function Prototypes
  ****************************************************************************/
 
@@ -66,7 +66,7 @@ extern "C"
 #define EXTERN extern
 #endif
 
-/*****************************************************************************
+/****************************************************************************
  * Name:  sam_usb_suspend
  *
  * Description:
@@ -75,17 +75,18 @@ extern "C"
  *   suspend mode.
  *
  *   When 'resume' is false, this function call provides an opportunity to
- *   perform board-specific power-saving actions so that less power is consumed
- *   while the USB is suspended.
+ *   perform board-specific power-saving actions so that less power is
+ *   consumed while the USB is suspended.
  *
  * NOTE:
  *   Certain power-saving operations are performed by the UDP driver when it
- *   enters suspend mode:  The USB device peripheral clocks are be switched off.
- *   MCK and UDPCK are switched off and the USB transceiver is disabled.
+ *   enters suspend mode:  The USB device peripheral clocks are be switched
+ *   off. MCK and UDPCK are switched off and the USB transceiver is disabled.
  *
- *   When 'resume' is true, normal clocking and operations must all be restored.
+ *   When 'resume' is true, normal clocking and operations must all be
+ *   restored.
  *
- *****************************************************************************/
+ ****************************************************************************/
 
 void sam_usb_suspend(FAR struct usbdev_s *dev, bool resume);
 
diff --git a/arch/arm/src/samd5e5/sam_usbhost.c b/arch/arm/src/samd5e5/sam_usbhost.c
new file mode 100644
index 0000000..2f4a627
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_usbhost.c
@@ -0,0 +1,378 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_usbhost.c
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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 <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include <nuttx/usb/usbhost_trace.h>
+
+#include "sam_usbhost.h"
+
+#ifdef HAVE_USBHOST_TRACE
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+#define TR_FMT1 false
+#define TR_FMT2 true
+
+#define TRENTRY(id,fmt1,string) {string}
+
+#ifndef NULL
+#  define NULL ((FAR void *)0)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct sam_usbhost_trace_s
+{
+  FAR const char *string;
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct sam_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] =
+{
+  TRENTRY(SAM_TRACE1_ALLOC_FAIL, TR_FMT1,
+        "INIT: Failed to allocate state structure: %u\n"),
+
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRENTRY(SAM_TRACE1_ASYNCHSETUP_FAIL1, TR_FMT1,
+          "OUT: Asynch setup failed: %u\n"),
+  TRENTRY(SAM_TRACE1_ASYNCHSETUP_FAIL2, TR_FMT1,
+          "IN: Asynch setup failed: %u\n"),
+#endif
+
+  TRENTRY(SAM_TRACE1_BAD_JKSTATE,       TR_FMT1,
+          "CONNECT: Bad JK state: %02x\n"),
+  TRENTRY(SAM_TRACE1_BADREVISION,       TR_FMT1,
+          "INIT: Bad revision number:  %02x\n"),
+  TRENTRY(SAM_TRACE1_PIPEALLOC_FAIL,    TR_FMT1,
+          "EPALLOC: Pipe allocation failed: %u\n"),
+  TRENTRY(SAM_TRACE1_PIPEWAIT_FAIL,     TR_FMT1,
+          "OUT: Pipe wait failure: %u\n"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN1,       TR_FMT1,
+          "OUT: Disconnected during wait: %u\n"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN2,       TR_FMT1,
+          "CTRL: Disconnected during SETUP phase: %u\n"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN3,       TR_FMT1,
+          "CTRL OUT: Disconnected during DATA phase: %u\n"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN4,       TR_FMT1,
+          "CTRL IN: Disconnected during DATA phase: %u"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN5,       TR_FMT1,
+          "IN: Disconnected during wait: %u\n"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN6,       TR_FMT1,
+          "CONNECT: Device disconnect #1: %u\n"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN7,       TR_FMT1,
+          "CONNECT: Device disconnect #2: %u\n"),
+  TRENTRY(SAM_TRACE1_DEVDISCONN8,       TR_FMT1,
+          "CONNECT: Device disconnect #3: %u\n"),
+  TRENTRY(SAM_TRACE1_ENUMERATE_FAIL,    TR_FMT1,
+          "CONNECT: Enumeration failed: %u\n"),
+  TRENTRY(SAM_TRACE1_INSETUP_FAIL1,     TR_FMT1,
+          "CTRL IN: SETUP phase failure: %u\n"),
+
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRENTRY(SAM_TRACE1_INSETUP_FAIL2,     TR_FMT1,
+          "CTRL IN: Asynch SETUP phase failure #1: %u\n"),
+  TRENTRY(SAM_TRACE1_INSETUP_FAIL3,     TR_FMT1,
+          "CTRL IN: Asynch SETUP phase failure #2: %u\n"),
+#endif
+
+  TRENTRY(SAM_TRACE1_IRQATTACH_FAIL,    TR_FMT1,
+          "INIT: Failed to attach interrupt: %u\n"),
+  TRENTRY(SAM_TRACE1_OUTSETUP_FAIL1,    TR_FMT1,
+          "CTRL OUT: SETUP phase failure: %u\n"),
+
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRENTRY(SAM_TRACE1_OUTSETUP_FAIL2,    TR_FMT1,
+          "CTRL OUT: Asynch SETUP phase failure #1: %u\n"),
+  TRENTRY(SAM_TRACE1_OUTSETUP_FAIL3,    TR_FMT1,
+          "CTRL OUT: Asynch SETUP phase failure #2: %u\n"),
+#endif
+
+  TRENTRY(SAM_TRACE1_RECVDATA_FAIL,     TR_FMT1,
+          "CTRL IN: Data phase failure: %u\n"),
+  TRENTRY(SAM_TRACE1_RECVSTATUS_FAIL,   TR_FMT1,
+          "CTRL OUT: Status phase failure: %u\n"),
+  TRENTRY(SAM_TRACE1_SENDDATA_FAIL,     TR_FMT1,
+          "CTRL OUT: Data phase failure: %u\n"),
+  TRENTRY(SAM_TRACE1_SENDSETUP_FAIL1,   TR_FMT1,
+          "CTRL OUT: SETUP phase failure: %u\n"),
+  TRENTRY(SAM_TRACE1_SENDSETUP_FAIL2,   TR_FMT1,
+          "CTRL IN: SETUP phase failure: %u\n"),
+  TRENTRY(SAM_TRACE1_SENDSTATUS_FAIL,   TR_FMT1,
+          "CTRL IN: Status phase failure: %u\n"),
+  TRENTRY(SAM_TRACE1_TRANSFER_FAILED1,  TR_FMT1,
+          "OUT: Transfer wait returned failure: %u\n"),
+  TRENTRY(SAM_TRACE1_TRANSFER_FAILED2,  TR_FMT1,
+          "CTRL: SETUP wait returned failure: %u\n"),
+  TRENTRY(SAM_TRACE1_TRANSFER_FAILED3,  TR_FMT1,
+          "IN: Transfer wait returned failure: %u\n"),
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+  TRENTRY(SAM_VTRACE1_CANCEL,           TR_FMT1,
+          "Transfer canceled: EP%u\n"),
+  TRENTRY(SAM_VTRACE1_CONNECTED1,       TR_FMT1,
+          "CONNECT: Connection event: %u\n"),
+  TRENTRY(SAM_VTRACE1_CONNECTED2,       TR_FMT1,
+          "CONNECT: Connection change detected: %u\n"),
+  TRENTRY(SAM_VTRACE1_CONNECTED3,       TR_FMT1,
+          "CONNECT: Connected: %u\n"),
+  TRENTRY(SAM_VTRACE1_DISCONNECTED1,    TR_FMT1,
+          "CONNECT: Disconnected: %u\n"),
+  TRENTRY(SAM_VTRACE1_DISCONNECTED2,    TR_FMT1,
+          "CONNECT: Disconnect detected: %u\n"),
+  TRENTRY(SAM_VTRACE1_ENUMERATE,        TR_FMT1,
+          "ENUMERATE: Start: %u\n"),
+
+#ifdef CONFIG_USBHOST_HUB
+  TRENTRY(SAM_VTRACE1_HUB_CONNECTED,    TR_FMT1,
+          "CONNECT: Hub connected: %u\n"),
+#endif
+  TRENTRY(SAM_VTRACE1_INITIALIZED,      TR_FMT1,
+          "INIT: Hardware initialized: %u\n"),
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRENTRY(SAM_VTRACE1_TRANSFER_COMPLETE, TR_FMT1,
+          "OUT: Asynch transfer complete: %u\n"),
+#endif
+#endif
+
+  TRENTRY(TRACE1_DEVDISCONN,          TR_FMT1,
+          "ERROR: RHport%d Device disconnected\n"),
+  TRENTRY(TRACE1_INTRUNRECOVERABLE,   TR_FMT1,
+          "ERROR: Unrecoverable error. pending: %06x\n"),
+  TRENTRY(TRACE1_INTRUNHANDLED,       TR_FMT1,
+          "ERROR: Unhandled interrupts pending: %06x\n"),
+  TRENTRY(TRACE1_EPLISTALLOC_FAILED,  TR_FMT1,
+          "ERROR: Failed to allocate EP list\n"),
+  TRENTRY(TRACE1_EDALLOC_FAILED,      TR_FMT1,
+          "ERROR: Failed to allocate ED\n"),
+  TRENTRY(TRACE1_TDALLOC_FAILED,      TR_FMT1,
+          "ERROR: Failed to allocate TD\n"),
+  TRENTRY(TRACE1_IRQATTACH,           TR_FMT1,
+          "ERROR: Failed to attach IRQ%d\n"),
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRENTRY(TRACE1_BADTDSTATUS,         TR_FMT1,
+        "ERROR: Bad asynch TD completion status: %d\n"),
+#endif
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+  TRENTRY(VTRACE1_PHYSED,             TR_FMT1,
+        "physed: %06x\n"),
+  TRENTRY(VTRACE1_VIRTED,             TR_FMT1,
+        "ed: %06x\n"),
+  TRENTRY(VTRACE1_CSC,                TR_FMT1,
+        "Connect Status Change, RHSTATUS: %06x\n"),
+  TRENTRY(VTRACE1_DRWE,               TR_FMT1,
+        "DRWE: Remote wake-up, RHSTATUS: %06x\n"),
+  TRENTRY(VTRACE1_ALREADYCONN,        TR_FMT1,
+        "Already connected, RHPORTST: %06x\n"),
+  TRENTRY(VTRACE1_SPEED,              TR_FMT1,
+        "Port speed: %d\n"),
+  TRENTRY(VTRACE1_ALREADYDISCONN,     TR_FMT1,
+        "Already disconnected, RHPORTST: %06x\n"),
+  TRENTRY(VTRACE1_RHSC,               TR_FMT1,
+        "Root Hub Status Change. Pending: %06x\n"),
+  TRENTRY(VTRACE1_WDHINTR,            TR_FMT1,
+        "Writeback Done Head interrupt. Pending: %06x\n"),
+  TRENTRY(VTRACE1_CLASSENUM,          TR_FMT1,
+        "Hub port %d: Enumerate device\n"),
+  TRENTRY(VTRACE1_ENUMDISCONN,        TR_FMT1,
+        "RHport%dNot connected\n"),
+  TRENTRY(VTRACE1_INITIALIZING,       TR_FMT1,
+        "Initializing Stack\n"),
+  TRENTRY(VTRACE1_INITIALIZED,        TR_FMT1,
+        "Initialized\n"),
+  TRENTRY(VTRACE1_INTRPENDING,        TR_FMT1,
+        "Interrupts pending: %06x\n"),
+#endif
+};
+
+static const struct sam_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] =
+{
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRENTRY(SAM_VTRACE2_ASYNCH,           TR_FMT2,
+      "ASYNCH: Transfer started: EP%u len=%u\n"),
+#endif
+  TRENTRY(SAM_VTRACE2_BULKIN,           TR_FMT2,
+      "BULK IN: SETUP: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_BULKOUT,          TR_FMT2,
+      "BULK OUT: SETUP: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_PIPEWAKEUP_IN,    TR_FMT2,
+      "IN: Pipe Wakeup: pipe%u, result=%u\n"),
+  TRENTRY(SAM_VTRACE2_PIPEWAKEUP_OUT,   TR_FMT2,
+      "OUT: Pipe Wakeup: pipe%u result=%u\n"),
+  TRENTRY(SAM_VTRACE2_CTRLIN,           TR_FMT2,
+      "CTRL IN: Start: type=%u req=%u\n"),
+  TRENTRY(SAM_VTRACE2_CTRLOUT,          TR_FMT2,
+      "CTRL OUT: Start: type=%u req=%u\n"),
+#ifdef CONFIG_USBHOST_HUB
+  TRENTRY(SAM_VTRACE2_HUB_CONNECTED,    TR_FMT2,
+      "CONNECT: Hub connected: port=%u, connected=%u\n"),
+#endif
+  TRENTRY(SAM_VTRACE2_INTRIN,           TR_FMT2,
+      "INTR IN: SETUP: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_INTROUT,          TR_FMT2,
+      "INTR OUT: SETUP: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_ISOCIN,           TR_FMT2,
+      "ISOC IN: SETUP: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_ISOCOUT,          TR_FMT2,
+      "ISOC OUT: SETUP: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_RECVSTATUS,       TR_FMT2,
+      "CTRL OUT: Receive status: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_SENDSTATUS,       TR_FMT2,
+      "CTRL IN: Send status: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_STARTTRANSFER1,   TR_FMT2,
+      "OUT: Send start: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_STARTTRANSFER2,   TR_FMT2,
+      "IN: Receive start: pipe%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_TRANSFER,         TR_FMT2,
+      "Transfer start: EP%u len=%u\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_CTRL_IN, TR_FMT2,
+      "Pipe%d configured (EP%d,IN ,CTRL)\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_CTRL_OUT, TR_FMT2,
+      "Pipe%d configured (EP%d,OUT,CTRL)\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_INTR_IN, TR_FMT2,
+      "Pipe%d configured (EP%d,IN ,INTR)\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_INTR_OUT, TR_FMT2,
+      "Pipe%d configured (EP%d,OUT,INTR)\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_BULK_IN, TR_FMT2,
+      "Pipe%d configured (EP%d,IN ,BULK)\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_BULK_OUT, TR_FMT2,
+      "Pipe%d configured (EP%d,OUT,BULK)\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_ISOC_IN, TR_FMT2,
+      "Pipe%d configured (EP%d,IN ,ISOC)\n"),
+  TRENTRY(SAM_VTRACE2_PIPECONF_ISOC_OUT, TR_FMT2,
+      "Pipe%d configured (EP%d,OUT,ISOC)\n"),
+
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRENTRY(SAM_VTRACE2_XFRCOMPLETE,      TR_FMT2,
+    "ASYNCH: Transfer complete: EP%u len=%u\n"),
+#endif
+#endif
+
+  TRENTRY(TRACE2_BADTDSTATUS,         TR_FMT2,
+    "ERROR: RHport%d Bad TD completion status: %d\n"),
+  TRENTRY(TRACE2_WHDTDSTATUS,         TR_FMT2,
+    "ERROR: WHD Bad TD completion status: %d xfrtype: %d\n"),
+  TRENTRY(TRACE2_EP0ENQUEUE_FAILED,   TR_FMT2,
+    "ERROR: RHport%d Failed to enqueue EP0: %d\n"),
+  TRENTRY(TRACE2_EDENQUEUE_FAILED,    TR_FMT2,
+    "ERROR: Failed to queue ED for transfer type %d: %d\n"),
+  TRENTRY(TRACE2_CLASSENUM_FAILED,    TR_FMT2,
+    "Hub port %d usbhost_enumerate() failed: %d\n"),
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+  TRENTRY(VTRACE2_EP0CONFIG,          TR_FMT2,
+    "EP0 configure speed=%d funcaddr=%d\n"),
+  TRENTRY(VTRACE2_INTERVAL,           TR_FMT2,
+    "interval: %d->%d\n"),
+  TRENTRY(VTRACE2_MININTERVAL,        TR_FMT2,
+    "MIN interval: %d offset: %d\n"),
+  TRENTRY(VTRACE2_RHPORTST,           TR_FMT2,
+    "RHPORTST%d: %04x\n"),
+  TRENTRY(VTRACE2_CONNECTED,          TR_FMT2,
+    "RHPort%d connected, rhswait: %d\n"),
+  TRENTRY(VTRACE2_DISCONNECTED,       TR_FMT2,
+    "RHPort%d disconnected, rhswait: %d\n"),
+  TRENTRY(VTRACE2_WAKEUP,             TR_FMT2,
+    "RHPort%d connected: %d\n"),
+  TRENTRY(VTRACE2_EP0CTRLED,          TR_FMT2,
+    "RHPort%d EP0 CTRL: %04x\n"),
+  TRENTRY(VTRACE2_EPALLOC,            TR_FMT2,
+    "EP%d CTRL: %04x\n"),
+  TRENTRY(VTRACE2_CTRLIN,             TR_FMT2,
+    "CTRLIN RHPort%d req: %02x\n"),
+  TRENTRY(VTRACE2_CTRLOUT,            TR_FMT2,
+    "CTRLOUT RHPort%d req: %02x\n"),
+  TRENTRY(VTRACE2_TRANSFER,           TR_FMT2,
+    "EP%d buflen: %d\n"),
+  TRENTRY(VTRACE2_INITCONNECTED,      TR_FMT2,
+    "RHPort%d Device connected: %d\n"),
+#ifdef CONFIG_USBHOST_HUB
+  TRENTRY(VTRACE2_HUBWAKEUP,          TR_FMT2,
+    "Hub Port%d connected: %d\n"),
+#endif
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_trformat1 and usbhost_trformat2
+ *
+ * Description:
+ *   This interface must be provided by platform specific logic that knows
+ *   the HCDs encoding of USB trace data.
+ *
+ *   Given an 9-bit index, return a format string suitable for use with, say,
+ *   printf.  The returned format is expected to handle two unsigned integer
+ *   values.
+ *
+ ****************************************************************************/
+
+FAR const char *usbhost_trformat1(uint16_t id)
+{
+  int ndx = TRACE1_INDEX(id);
+
+  if (ndx < TRACE1_NSTRINGS)
+    {
+      return g_trace1[ndx].string;
+    }
+
+  return NULL;
+}
+
+FAR const char *usbhost_trformat2(uint16_t id)
+{
+  int ndx = TRACE2_INDEX(id);
+
+  if (ndx < TRACE2_NSTRINGS)
+    {
+      return g_trace2[ndx].string;
+    }
+
+  return NULL;
+}
+
+#endif /* HAVE_USBHOST_TRACE */
diff --git a/arch/arm/src/samd5e5/sam_usbhost.h b/arch/arm/src/samd5e5/sam_usbhost.h
new file mode 100644
index 0000000..6061c16
--- /dev/null
+++ b/arch/arm/src/samd5e5/sam_usbhost.h
@@ -0,0 +1,293 @@
+/****************************************************************************
+ * arch/arm/src/samd5e5/sam_usbhost.h
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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_SAMD5E5_SAM_USBHOST_H
+#define __ARCH_ARM_SRC_SAMD5E5_SAM_USBHOST_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/usb/usbhost_trace.h>
+
+#ifdef CONFIG_USBHOST
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* This is the interface argument for call outs to board-specific
+ * functions which need to know which USB host interface is being used.
+ */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+#ifdef HAVE_USBHOST_TRACE
+enum usbhost_trace1codes_e
+{
+  __TRACE1_BASEVALUE = 0,           /* This will force the first value to be 1 */
+
+  SAM_TRACE1_ALLOC_FAIL,
+#ifdef CONFIG_USBHOST_ASYNCH
+  SAM_TRACE1_ASYNCHSETUP_FAIL1,
+  SAM_TRACE1_ASYNCHSETUP_FAIL2,
+#endif
+  SAM_TRACE1_BAD_JKSTATE,
+  SAM_TRACE1_BADREVISION,
+  SAM_TRACE1_PIPEALLOC_FAIL,
+  SAM_TRACE1_PIPEWAIT_FAIL,
+  SAM_TRACE1_DEVDISCONN1,
+  SAM_TRACE1_DEVDISCONN2,
+  SAM_TRACE1_DEVDISCONN3,
+  SAM_TRACE1_DEVDISCONN4,
+  SAM_TRACE1_DEVDISCONN5,
+  SAM_TRACE1_DEVDISCONN6,
+  SAM_TRACE1_DEVDISCONN7,
+  SAM_TRACE1_DEVDISCONN8,
+  SAM_TRACE1_ENUMERATE_FAIL,
+  SAM_TRACE1_INSETUP_FAIL1,
+#ifdef CONFIG_USBHOST_ASYNCH
+  SAM_TRACE1_INSETUP_FAIL2,
+  SAM_TRACE1_INSETUP_FAIL3,
+#endif
+  SAM_TRACE1_IRQATTACH_FAIL,
+  SAM_TRACE1_OUTSETUP_FAIL1,
+#ifdef CONFIG_USBHOST_ASYNCH
+  SAM_TRACE1_OUTSETUP_FAIL2,
+  SAM_TRACE1_OUTSETUP_FAIL3,
+#endif
+  SAM_TRACE1_RECVDATA_FAIL,
+  SAM_TRACE1_RECVSTATUS_FAIL,
+  SAM_TRACE1_SENDDATA_FAIL,
+  SAM_TRACE1_SENDSETUP_FAIL1,
+  SAM_TRACE1_SENDSETUP_FAIL2,
+  SAM_TRACE1_SENDSTATUS_FAIL,
+  SAM_TRACE1_TRANSFER_FAILED1,
+  SAM_TRACE1_TRANSFER_FAILED2,
+  SAM_TRACE1_TRANSFER_FAILED3,
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+  SAM_VTRACE1_CANCEL,
+  SAM_VTRACE1_CONNECTED1,
+  SAM_VTRACE1_CONNECTED2,
+  SAM_VTRACE1_CONNECTED3,
+  SAM_VTRACE1_DISCONNECTED1,
+  SAM_VTRACE1_DISCONNECTED2,
+  SAM_VTRACE1_ENUMERATE,
+#ifdef CONFIG_USBHOST_HUB
+  SAM_VTRACE1_HUB_CONNECTED,
+#endif
+  SAM_VTRACE1_INITIALIZED,
+#ifdef CONFIG_USBHOST_ASYNCH
+  SAM_VTRACE1_TRANSFER_COMPLETE,
+#endif
+#endif
+
+  TRACE1_DEVDISCONN,                /* ERROR: RHport Device disconnected */
+  TRACE1_INTRUNRECOVERABLE,         /* ERROR: Unrecoverable error */
+  TRACE1_INTRUNHANDLED,             /* ERROR: Unhandled interrupts */
+  TRACE1_EPLISTALLOC_FAILED,        /* ERROR: Failed to allocate EP list */
+  TRACE1_EDALLOC_FAILED,            /* ERROR: Failed to allocate ED */
+  TRACE1_TDALLOC_FAILED,            /* ERROR: Failed to allocate TD */
+  TRACE1_IRQATTACH,                 /* ERROR: Failed to attach IRQ */
+#ifdef CONFIG_USBHOST_ASYNCH
+  TRACE1_BADTDSTATUS,               /* ERROR: Bad asynch TD completion status */
+#endif
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+  VTRACE1_PHYSED,                   /* physed */
+  VTRACE1_VIRTED,                   /* ed */
+  VTRACE1_CSC,                      /* Connect Status Change */
+  VTRACE1_DRWE,                     /* DRWE: Remote wake-up */
+  VTRACE1_ALREADYCONN,              /* Already connected */
+  VTRACE1_SPEED,                    /* Low speed */
+  VTRACE1_ALREADYDISCONN,           /* Already disconnected */
+  VTRACE1_RHSC,                     /* Root Hub Status Change */
+  VTRACE1_WDHINTR,                  /* Writeback Done Head interrupt */
+  VTRACE1_CLASSENUM,                /* Enumerate the device */
+  VTRACE1_ENUMDISCONN,              /* RHport Not connected */
+  VTRACE1_INITIALIZING,             /* Initializing Stack */
+  VTRACE1_INITIALIZED,              /* Initialized */
+  VTRACE1_INTRPENDING,              /* Interrupts pending */
+#endif
+
+  __TRACE1_NSTRINGS,                /* Separates the format 1 from the format 2 strings */
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+#ifdef CONFIG_USBHOST_ASYNCH
+  SAM_VTRACE2_ASYNCH,
+#endif
+  SAM_VTRACE2_BULKIN,
+  SAM_VTRACE2_BULKOUT,
+  SAM_VTRACE2_PIPEWAKEUP_IN,
+  SAM_VTRACE2_PIPEWAKEUP_OUT,
+  SAM_VTRACE2_CTRLIN,
+  SAM_VTRACE2_CTRLOUT,
+#ifdef CONFIG_USBHOST_HUB
+  SAM_VTRACE2_HUB_CONNECTED,
+#endif
+  SAM_VTRACE2_INTRIN,
+  SAM_VTRACE2_INTROUT,
+  SAM_VTRACE2_ISOCIN,
+  SAM_VTRACE2_ISOCOUT,
+  SAM_VTRACE2_RECVSTATUS,
+  SAM_VTRACE2_SENDSTATUS,
+  SAM_VTRACE2_STARTTRANSFER1,
+  SAM_VTRACE2_STARTTRANSFER2,
+  SAM_VTRACE2_TRANSFER,
+  SAM_VTRACE2_PIPECONF_CTRL_IN,
+  SAM_VTRACE2_PIPECONF_CTRL_OUT,
+  SAM_VTRACE2_PIPECONF_INTR_IN,
+  SAM_VTRACE2_PIPECONF_INTR_OUT,
+  SAM_VTRACE2_PIPECONF_BULK_IN,
+  SAM_VTRACE2_PIPECONF_BULK_OUT,
+  SAM_VTRACE2_PIPECONF_ISOC_IN,
+  SAM_VTRACE2_PIPECONF_ISOC_OUT,
+#ifdef CONFIG_USBHOST_ASYNCH
+  SAM_VTRACE2_XFRCOMPLETE,
+#endif
+#endif
+
+  TRACE2_BADTDSTATUS,               /* ERROR: RHport Bad TD completion status */
+  TRACE2_WHDTDSTATUS,               /* ERROR: WDH Bad TD completion status */
+  TRACE2_EP0ENQUEUE_FAILED,         /* ERROR: RHport Failed to enqueue EP0 */
+  TRACE2_EDENQUEUE_FAILED,          /* ERROR: Failed to queue ED for transfer type */
+  TRACE2_CLASSENUM_FAILED,          /* usbhost_enumerate() failed */
+
+#ifdef HAVE_USBHOST_TRACE_VERBOSE
+  VTRACE2_EP0CONFIG,                /* EP0 configuration */
+  VTRACE2_INTERVAL,                 /* interval */
+  VTRACE2_MININTERVAL,              /* MIN interval/offset */
+  VTRACE2_RHPORTST,                 /* RHPORTST */
+  VTRACE2_CONNECTED,                /* RHPort connected */
+  VTRACE2_DISCONNECTED,             /* RHPort disconnected */
+  VTRACE2_WAKEUP,                   /* RHPort connected wakeup */
+  VTRACE2_EP0CTRLED,                /* RHPort EP0 CTRL */
+  VTRACE2_EPALLOC,                  /* EP CTRL */
+  VTRACE2_CTRLIN,                   /* CTRLIN */
+  VTRACE2_CTRLOUT,                  /* CTRLOUT */
+  VTRACE2_TRANSFER,                 /* EP buflen */
+  VTRACE2_INITCONNECTED,            /* RHPort Device connected */
+#ifdef CONFIG_USBHOST_HUB
+  VTRACE2_HUBWAKEUP,                /* Hub Port connected wakeup */
+#endif
+#endif
+
+  __TRACE2_NSTRINGS                 /* Total number of enumeration values */
+};
+
+#  define TRACE1_FIRST     ((int)__TRACE1_BASEVALUE + 1)
+#  define TRACE1_INDEX(id) ((int)(id) - TRACE1_FIRST)
+#  define TRACE1_NSTRINGS  TRACE1_INDEX(__TRACE1_NSTRINGS)
+
+#  define TRACE2_FIRST     ((int)__TRACE1_NSTRINGS + 1)
+#  define TRACE2_INDEX(id) ((int)(id) - TRACE2_FIRST)
+#  define TRACE2_NSTRINGS  TRACE2_INDEX(__TRACE2_NSTRINGS)
+
+#endif /* HAVE_USBHOST_TRACE */
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int samd_usbhost_initialize(void);
+
+/****************************************************************************
+ * Name: sam_usbhost_initialize
+ *
+ * Description:
+ *   Initialize USB host controller hardware.
+ *
+ * Input Parameters:
+ *   controller -- If the device supports more than USB host controller, then
+ *   this identifies which controller is being initialized.  Normally, this
+ *   is just zero.
+ *
+ * Returned Value:
+ *   And instance of the USB host interface.  The controlling task should
+ *   use this interface to (1) call the wait() method to wait for a device
+ *   to be connected, and (2) call the enumerate() method to bind the device
+ *   to a class driver.
+ *
+ * Assumptions:
+ * - This function should called in the initialization sequence in order
+ *   to initialize the USB device functionality.
+ * - Class drivers should be initialized prior to calling this function.
+ *   Otherwise, there is a race condition if the device is already connected.
+ *
+ ****************************************************************************/
+
+struct usbhost_connection_s;
+FAR struct usbhost_connection_s *sam_usbhost_initialize(int controller);
+
+/****************************************************************************
+ * Name: sam_usbhost_vbusdrive
+ *
+ * Description:
+ *   Enable/disable driving of VBUS 5V output.
+ *   This function must be provided by each platform that
+ *   implements the OHCI or EHCI host interface
+ *
+ * Input Parameters:
+ *   rhport - Selects root hub port to be powered host interface.
+ *            See SAM_RHPORT_* definitions above.
+ *   enable - true: enable VBUS power; false: disable VBUS power
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void sam_usbhost_vbusdrive(int rhport, bool enable);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_USBHOST */
+#endif /* __ARCH_ARM_SRC_SAMD5E5_SAM_USBHOST_H */
diff --git a/boards/arm/samd5e5/metro-m4/Kconfig b/boards/arm/samd5e5/metro-m4/Kconfig
index 0559744..06e5bbb 100644
--- a/boards/arm/samd5e5/metro-m4/Kconfig
+++ b/boards/arm/samd5e5/metro-m4/Kconfig
@@ -45,5 +45,34 @@ config METRO_M4_32KHZXTAL
 		slow clock source.  This option will select instead XOSC32 as the
 		slow clock source.
 
+if FS_AUTOMOUNTER
+config METRO_M4_USB_AUTOMOUNT
+	bool "USB automounter"
+	default n
+
+if METRO_M4_USB_AUTOMOUNT
+
+config METRO_M4_USB_AUTOMOUNT_FSTYPE
+	string "USB file system type"
+	default "vfat"
+
+config METRO_M4_USB_AUTOMOUNT_BLKDEV
+	string "USB block device"
+	default "/dev/sda"
+
+config METRO_M4_USB_AUTOMOUNT_MOUNTPOINT
+	string "USB mount point"
+	default "/mnt/usb"
+
+config METRO_M4_USB_AUTOMOUNT_DDELAY
+	int "USB debounce delay (milliseconds)"
+	default 1000
+
+config METRO_M4_USB_AUTOMOUNT_UDELAY
+	int "USB unmount retry delay (milliseconds)"
+	default 2000
+
+endif # METRO_M4_USB_AUTOMOUNT
+endif # FS_AUTOMOUNTER
 
 endif # ARCH_BOARD_METRO_M4
diff --git a/boards/arm/samd5e5/metro-m4/include/board.h b/boards/arm/samd5e5/metro-m4/include/board.h
index b7911cd..7bde7d1 100644
--- a/boards/arm/samd5e5/metro-m4/include/board.h
+++ b/boards/arm/samd5e5/metro-m4/include/board.h
@@ -253,27 +253,31 @@
 #define BOARD_GCLK11_DIV        1         /* Division factor */
 #define BOARD_GCLK11_FREQUENCY  BOARD_XOSC1_FREQUENCY
 
-/* FDLL */
+/* DFLL */
 
 #define BOARD_DFLL_ENABLE       TRUE      /* DFLL enable */
 #define BOARD_DFLL_RUNSTDBY     FALSE     /* Don't run in standby */
 #define BOARD_DFLL_ONDEMAND     FALSE     /* No n-demand control */
-#define BOARD_DFLL_MODE         FALSE     /* Open loop mode */
+#define BOARD_DFLL_MODE         FALSE     /* TRUE->48MHz! Closed mode! */
 #define BOARD_DFLL_STABLE       FALSE     /* No stable DFLL frequency */
 #define BOARD_DFLL_LLAW         FALSE     /* Don't ose lock after wake */
-#define BOARD_DFLL_USBCRM       TRUE      /* Use USB clock recovery mode */
-#define BOARD_DFLL_CCDIS        TRUE      /* Chill cycle disable */
+#define BOARD_DFLL_USBCRM       FALSE     /* Use USB clock recovery mode */
+#define BOARD_DFLL_CCDIS        FALSE     /* Chill cycle disable */
 #define BOARD_DFLL_QLDIS        FALSE     /* No Quick Lock Disable */
-#define BOARD_DFLL_BPLCKC       FALSE     /* No ypass coarse clock */
+#define BOARD_DFLL_BPLCKC       FALSE     /* No bypass coarse clock */
 #define BOARD_DFLL_WAITLOCK     TRUE      /* Wait lock */
-#define BOARD_DFLL_CALIBEN      FALSE     /* Don't verwrite factory calibration */
+#define BOARD_DFLL_CALIBEN      FALSE     /* Don't overwrite factory calibration */
 #define BOARD_DFLL_GCLKLOCK     FALSE     /* Don't lock the GCLK source */
 #define BOARD_DFLL_FCALIB       128       /* Coarse calibration value (if caliben) */
 #define BOARD_DFLL_CCALIB       (31 / 4)  /* Fine calibration value (if caliben) */
 #define BOARD_DFLL_FSTEP        1         /* Fine maximum step */
 #define BOARD_DFLL_CSTEP        1         /* Coarse maximum step */
-#define BOARD_DFLL_GCLK         3         /* GCLK source (if !usbcrm && !mode) */
-#define BOARD_DFLL_MUL          0         /* DFLL multiply factor */
+#define BOARD_DFLL_GCLK         3         /* Generic clock generator 3 output: OSCULP32K / GCLK source (if !usbcrm || !mode) */
+#if (BOARD_DFLL_MODE == TRUE) && (BOARD_DFLL_USBCRM == TRUE)
+#define BOARD_DFLL_MUL          0xBB80    /* 48MHz/1KHz DFLL multiply factor */
+#else
+#define BOARD_DFLL_MUL          1465      /* 1464(3)=48MHz/32768 4915(2) DFLL multiply factor */
+#endif
 
 /* DPLL0/1
  *
@@ -417,8 +421,8 @@
 /* SERCOM definitions *******************************************************/
 
 /* The SERCOM bus clock (CLK_SERCOMx_APB) can be enabled and disabled in the
- * Main Clock Controller.
- * The SERCOM uses two generic clocks: GCLK_SERCOMn_CORE and GCLK_SERCOM_SLOW.
+ * Main Clock Controller. The SERCOM uses two generic clocks:
+ * GCLK_SERCOMn_CORE and GCLK_SERCOM_SLOW.
  * The core clock (GCLK_SERCOMx_CORE) is required to clock the SERCOM while
  * working as a master.  The slow clock (GCLK_SERCOM_SLOW) is only  required
  * for certain functions and is common to all SERCOM modules.
@@ -461,6 +465,21 @@
 #define BOARD_SERCOM3_CORELOCK       FALSE               /* Don't lock the CORECLOCK */
 #define BOARD_SERCOM3_FREQUENCY      BOARD_GCLK1_FREQUENCY
 
+/* I2C
+ *  PB02 - SERCOM5 PAD0 SDA
+ *  PB03 - SERCOM5 PAD1 SCL
+ */
+
+#define BOARD_SERCOM5_MUXCONFIG      (0)
+#define BOARD_SERCOM5_PINMAP_PAD0    PORT_SERCOM5_PAD0_3 /* PB02: PAD0: I2C SDA */
+#define BOARD_SERCOM5_PINMAP_PAD1    PORT_SERCOM5_PAD1_3 /* PB03: PAD1: I2C SCL */
+#define BOARD_SERCOM5_PINMAP_PAD2    0                   /* PAD2: (not used) */
+#define BOARD_SERCOM5_PINMAP_PAD3    0                   /* PAD3: (not used) */
+
+#define BOARD_SERCOM5_GCLKGEN 		 1                   /* 48MHz Core clock */
+#define BOARD_SERCOM5_SLOW_GCLKGEN	 3
+#define BOARD_SERCOM5_FREQUENCY      BOARD_GCLK1_FREQUENCY
+
 /* USB */
 
 #define BOARD_USB_GCLKGEN            1                   /* GCLK1, 48MHz */
diff --git a/boards/arm/samd5e5/metro-m4/src/Makefile b/boards/arm/samd5e5/metro-m4/src/Makefile
index aead5e3..e8e7b6c 100644
--- a/boards/arm/samd5e5/metro-m4/src/Makefile
+++ b/boards/arm/samd5e5/metro-m4/src/Makefile
@@ -47,4 +47,28 @@ else
 CSRCS += sam_userleds.c
 endif
 
+ifeq ($(CONFIG_USBDEV),y)
+CSRCS += sam_usbdev.c
+endif
+
+ifeq ($(CONFIG_USBMSC),y)
+CSRCS += sam_usbmsc.c
+endif
+
+ifeq ($(CONFIG_USBDEV_COMPOSITE),y)
+CSRCS += sam_composite.c
+endif
+
+ifeq ($(CONFIG_USBHOST),y)
+CSRCS += sam_usbhost.c
+endif
+
+ifeq ($(CONFIG_FS_AUTOMOUNTER),y)
+CSRCS += sam_automount.c
+endif
+
+ifeq ($(CONFIG_SAMD5E5_SERCOM5_ISI2C),y)
+CSRCS += sam_i2c.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/arm/samd5e5/metro-m4/src/metro-m4.h b/boards/arm/samd5e5/metro-m4/src/metro-m4.h
index b46fe04..ba0cc77 100644
--- a/boards/arm/samd5e5/metro-m4/src/metro-m4.h
+++ b/boards/arm/samd5e5/metro-m4/src/metro-m4.h
@@ -82,7 +82,7 @@
 #ifndef __ASSEMBLY__
 
 /****************************************************************************
- * Public Functions
+ * Public Functions Prototype
  ****************************************************************************/
 
 /****************************************************************************
@@ -113,5 +113,15 @@ int sam_bringup(void);
 void sam_led_pminitialize(void);
 #endif
 
+#ifdef CONFIG_METRO_M4_USB_AUTOMOUNT
+void sam_automount_initialize(void);
+void sam_automount_event(bool inserted);
+#endif
+
+#ifdef CONFIG_SAMD5E5_SERCOM5_ISI2C
+FAR struct i2c_master_s *g_i2c5_dev;
+int metro_m4_i2cdev_initialize(void);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_ARM_SAMD5E5_METRO_M4_SRC_METRO_M4_H */
diff --git a/boards/arm/samd5e5/metro-m4/src/sam_automount.c b/boards/arm/samd5e5/metro-m4/src/sam_automount.c
new file mode 100644
index 0000000..5c9e7a9
--- /dev/null
+++ b/boards/arm/samd5e5/metro-m4/src/sam_automount.c
@@ -0,0 +1,331 @@
+/****************************************************************************
+ * boards/arm/samd5e5/metro-m4/src/sam_automount.c
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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>
+
+#if defined(CONFIG_FS_AUTOMOUNTER_DEBUG) && !defined(CONFIG_DEBUG_FS)
+#  define CONFIG_DEBUG_FS 1
+#endif
+
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/fs/automount.h>
+
+#include "metro-m4.h"
+
+#ifdef CONFIG_FS_AUTOMOUNTER
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef NULL
+#  define NULL (FAR void *)0
+#endif
+
+#ifndef OK
+#  define OK 0
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure represents the changeable state of the automounter */
+
+struct sam_automount_state_s
+{
+  volatile automount_handler_t handler;    /* Upper half handler */
+  FAR void *arg;                           /* Handler argument */
+  bool enable;                             /* Fake interrupt enable */
+  bool pending;                            /* Set if there an event while disabled */
+  bool inserted;
+};
+
+/* This structure represents the static configuration of an automounter */
+
+struct sam_automount_config_s
+{
+  /* This must be first thing in structure so that we can simply cast from
+   * struct automount_lower_s to struct sam_automount_config_s
+   */
+
+  struct automount_lower_s lower;          /* Publicly visible part */
+  FAR struct sam_automount_state_s *state; /* Changeable state */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int  sam_attach(FAR const struct automount_lower_s *lower,
+                       automount_handler_t isr, FAR void *arg);
+static void sam_enable(FAR const struct automount_lower_s *lower,
+                       bool enable);
+static bool sam_inserted(FAR const struct automount_lower_s *lower);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_METRO_M4_USB_AUTOMOUNT
+static struct sam_automount_state_s g_port0state;
+static const struct sam_automount_config_s g_port0config =
+{
+  .lower        =
+  {
+    .fstype     = CONFIG_METRO_M4_USB_AUTOMOUNT_FSTYPE,
+    .blockdev   = CONFIG_METRO_M4_USB_AUTOMOUNT_BLKDEV,
+    .mountpoint = CONFIG_METRO_M4_USB_AUTOMOUNT_MOUNTPOINT,
+    .ddelay     = MSEC2TICK(CONFIG_METRO_M4_USB_AUTOMOUNT_DDELAY),
+    .udelay     = MSEC2TICK(CONFIG_METRO_M4_USB_AUTOMOUNT_UDELAY),
+    .attach     = sam_attach,
+    .enable     = sam_enable,
+    .inserted   = sam_inserted
+  },
+  .state        = &g_port0state
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name:  sam_attach
+ *
+ * Description:
+ *   Attach a new port event handler
+ *
+ * Input Parameters:
+ *   lower - An instance of the auto-mounter lower half state structure
+ *   isr   - The new event handler to be attach
+ *   arg   - Client data to be provided when the event handler is invoked.
+ *
+ *  Returned Value:
+ *    Always returns OK
+ *
+ ****************************************************************************/
+
+static int sam_attach(FAR const struct automount_lower_s *lower,
+                      automount_handler_t isr, FAR void *arg)
+{
+  FAR const struct sam_automount_config_s *config;
+  FAR struct sam_automount_state_s *state;
+
+  finfo("Entry\n");
+
+  /* Recover references to our structure */
+
+  config = (FAR struct sam_automount_config_s *)lower;
+  DEBUGASSERT(config && config->state);
+
+  state = config->state;
+
+  /* Save the new handler info (clearing the handler first to eliminate
+   * race conditions).
+   */
+
+  state->handler = NULL;
+  state->pending = false;
+  state->arg     = arg;
+  state->handler = isr;
+  return OK;
+}
+
+/****************************************************************************
+ * Name:  sam_enable
+ *
+ * Description:
+ *   Enable port insertion/removal event detection
+ *
+ * Input Parameters:
+ *   lower - An instance of the auto-mounter lower half state structure
+ *   enable - True: enable event detection; False: disable
+ *
+ *  Returned Value:
+ *    None
+ *
+ ****************************************************************************/
+
+static void sam_enable(FAR const struct automount_lower_s *lower,
+                       bool enable)
+{
+  FAR const struct sam_automount_config_s *config;
+  FAR struct sam_automount_state_s *state;
+  irqstate_t flags;
+
+  finfo("Entry\n");
+
+  /* Recover references to our structure */
+
+  config = (FAR struct sam_automount_config_s *)lower;
+  DEBUGASSERT(config && config->state);
+
+  state = config->state;
+
+  /* Save the fake enable setting */
+
+  flags = enter_critical_section();
+  state->enable = enable;
+
+  /* Did an interrupt occur while interrupts were disabled? */
+
+  if (enable && state->pending)
+    {
+      /* Yes.. perform the fake interrupt if the interrutp is attached */
+
+      if (state->handler)
+        {
+          (void)state->handler(&config->lower, state->arg, true);
+        }
+
+      state->pending = false;
+    }
+
+  leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: sam_inserted
+ *
+ * Description:
+ *   Check if a card is inserted into the slot.
+ *
+ * Input Parameters:
+ *   lower - An instance of the auto-mounter lower half state structure
+ *
+ *  Returned Value:
+ *    True if the card is inserted; False otherwise
+ *
+ ****************************************************************************/
+
+static bool sam_inserted(FAR const struct automount_lower_s *lower)
+{
+  FAR const struct sam_automount_config_s *config;
+
+  config = (FAR struct sam_automount_config_s *)lower;
+  DEBUGASSERT(config && config->state);
+  finfo("inserted:%d\n", config->state->inserted);
+  return config->state->inserted;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name:  sam_automount_initialize
+ *
+ * Description:
+ *   Configure auto-mounters for each enable and so configured HSMCI
+ *
+ * Input Parameters:
+ *   None
+ *
+ *  Returned Value:
+ *    None
+ *
+ ****************************************************************************/
+
+void sam_automount_initialize(void)
+{
+  FAR void *handle;
+
+  finfo("Initializing automounter(s)\n");
+
+#ifdef CONFIG_METRO_M4_USB_AUTOMOUNT
+  /* Initialize the USB auto-mounter */
+
+  handle = automount_initialize(&g_port0config.lower);
+  if (!handle)
+    {
+      ferr("ERROR: Failed to initialize auto-mounter for USB\n");
+    }
+#endif
+}
+
+/****************************************************************************
+ * Name:  sam_automount_event
+ *
+ * Description:
+ *   It has already scheduled the MMC/SD block driver operations.
+ *   Now we need to schedule the auto-mount event which will occur with
+ *   a substantial delay to make sure that everything has settle down.
+ *
+ * Input Parameters:
+ *   inserted - True if the card is inserted in the slot.  False otherwise.
+ *
+ *  Returned Value:
+ *    None
+ *
+ *  Assumptions:
+ *    Interrupts are disabled.
+ *
+ ****************************************************************************/
+
+void sam_automount_event(bool inserted)
+{
+  FAR const struct sam_automount_config_s *config;
+  FAR struct sam_automount_state_s *state;
+
+#ifdef CONFIG_METRO_M4_USB_AUTOMOUNT
+  config = &g_port0config;
+  state  = &g_port0state;
+  state->inserted = inserted;
+#endif
+
+  finfo("event:%d\n", inserted);
+
+  /* Is the auto-mounter interrupt attached? */
+
+  if (state->handler)
+    {
+      /* Yes.. Have we been asked to hold off interrupts? */
+
+      if (!state->enable)
+        {
+          /* Yes.. just remember that there is a pending interrupt.
+           * We will deliver the interrupt when interrupts are
+           * "re-enabled."
+           */
+
+          state->pending = true;
+        }
+      else
+        {
+          /* No.. forward the event to the handler */
+
+          (void)state->handler(&config->lower, state->arg, state->inserted);
+        }
+    }
+}
+
+#endif /* CONFIG_FS_AUTOMOUNTER */
diff --git a/boards/arm/samd5e5/metro-m4/src/sam_bringup.c b/boards/arm/samd5e5/metro-m4/src/sam_bringup.c
index d5be455..409ccde 100644
--- a/boards/arm/samd5e5/metro-m4/src/sam_bringup.c
+++ b/boards/arm/samd5e5/metro-m4/src/sam_bringup.c
@@ -51,6 +51,19 @@
   #include "sam_wdt.h"
 #endif
 
+#ifdef CONFIG_SAMD5E5_SERCOM5_ISI2C
+  #include <nuttx/i2c/i2c_master.h>
+  #include "hardware/sam_i2c_master.h"
+#endif
+
+#ifdef CONFIG_USBHOST
+#  include "sam_usbhost.h"
+#endif
+
+#ifdef CONFIG_USBMONITOR
+#  include <nuttx/usb/usbmonitor.h>
+#endif
+
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
@@ -94,6 +107,42 @@ int sam_bringup(void)
   (void)sam_wdt_initialize(CONFIG_WATCHDOG_DEVPATH);
 #endif
 
+#ifdef CONFIG_SAMD5E5_SERCOM5_ISI2C
+  /* Initialize I2C bus */
+
+  ret = metro_m4_i2cdev_initialize();
+#endif 
+
+#ifdef CONFIG_USBHOST
+  /* Initialize USB host operation. samd_usbhost_initialize() starts a
+   * thread will monitor for USB connection and disconnection events.
+   */
+
+  ret = samd_usbhost_initialize();
+  if (ret != OK)
+    {
+      syslog(LOG_ERR, "samd_usbhost_initialize failed %d\n", ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_USBMONITOR
+  /* Start the USB Monitor */
+
+  ret = usbmonitor_start();
+  if (ret != OK)
+    {
+      syslog(LOG_ERR, "usbmonitor_start failed %d\n", ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_FS_AUTOMOUNTER
+  /* Initialize the auto-mounter */
+
+  sam_automount_initialize();
+#endif
+
   UNUSED(ret);
   return OK;
 }
diff --git a/boards/arm/samd5e5/metro-m4/src/sam_composite.c b/boards/arm/samd5e5/metro-m4/src/sam_composite.c
new file mode 100644
index 0000000..832f8fd
--- /dev/null
+++ b/boards/arm/samd5e5/metro-m4/src/sam_composite.c
@@ -0,0 +1,348 @@
+/****************************************************************************
+ * boards/arm/samd5e5/metro-m4/src/sam_composite.c
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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 <sys/types.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/usb/usbdev_trace.h>
+#include <nuttx/usb/cdcacm.h>
+#include <nuttx/usb/usbmsc.h>
+#include <nuttx/usb/composite.h>
+
+#include "metro-m4.h"
+
+#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_USBMSC_COMPOSITE
+static FAR void *g_mschandle;
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_mscclassobject
+ *
+ * Description:
+ *   If the mass storage class driver is part of composite device, then
+ *   its instantiation and configuration is a multi-step, board-specific,
+ *   process (See comments for usbmsc_configure below).  In this case,
+ *   board-specific logic must provide board_mscclassobject().
+ *
+ *   board_mscclassobject() is called from the composite driver.  It must
+ *   encapsulate the instantiation and configuration of the mass storage
+ *   class and the return the mass storage device's class driver instance
+ *   to the composite driver.
+ *
+ * Input Parameters:
+ *   classdev - The location to return the mass storage class' device
+ *     instance.
+ *
+ * Returned Value:
+ *   0 on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBMSC_COMPOSITE
+static int board_mscclassobject(int minor,
+                                FAR struct usbdev_devinfo_s *devinfo,
+                                FAR struct usbdevclass_driver_s **classdev)
+{
+  int ret;
+
+  DEBUGASSERT(g_mschandle == NULL);
+
+  /* Configure the mass storage device */
+
+  uinfo("Configuring with NLUNS=1\n");
+  ret = usbmsc_configure(1, &g_mschandle);
+  if (ret < 0)
+    {
+      uerr("ERROR: usbmsc_configure failed: %d\n", -ret);
+      return ret;
+    }
+
+  uinfo("MSC handle=%p\n", g_mschandle);
+
+  /* Bind the LUN(s) */
+
+  uinfo("Bind LUN=0 to /dev/mmcsd0\n");
+  ret = usbmsc_bindlun(g_mschandle, "/dev/mmcsd0", 0, 0, 0, false);
+  if (ret < 0)
+    {
+      uerr("ERROR: usbmsc_bindlun failed for LUN 1 at /dev/mmcsd0: %d\n",
+           ret);
+      usbmsc_uninitialize(g_mschandle);
+      g_mschandle = NULL;
+      return ret;
+    }
+
+  /* Get the mass storage device's class object */
+
+  ret = usbmsc_classobject(g_mschandle, devinfo, classdev);
+  if (ret < 0)
+    {
+      uerr("ERROR: usbmsc_classobject failed: %d\n", -ret);
+      usbmsc_uninitialize(g_mschandle);
+      g_mschandle = NULL;
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: board_mscuninitialize
+ *
+ * Description:
+ *   Un-initialize the USB storage class driver. This is just an application
+ *   specific wrapper aboutn usbmsc_unitialize() that is called form the
+ *   composite device logic.
+ *
+ * Input Parameters:
+ *   classdev - The class driver instrance previously give to the composite
+ *     driver by board_mscclassobject().
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBMSC_COMPOSITE
+static void board_mscuninitialize(FAR struct usbdevclass_driver_s *classdev)
+{
+  DEBUGASSERT(g_mschandle != NULL);
+  usbmsc_uninitialize(g_mschandle);
+  g_mschandle = NULL;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_composite_initialize
+ *
+ * Description:
+ *   Perform architecture specific initialization of a composite USB device.
+ *
+ ****************************************************************************/
+
+int board_composite_initialize(int port)
+{
+  return OK;
+}
+
+/****************************************************************************
+ * Name:  board_composite_connect
+ *
+ * Description:
+ *   Connect the USB composite device on the specified USB device port using
+ *   the specified configuration.  The interpretation of the configid is
+ *   board specific.
+ *
+ * Input Parameters:
+ *   port     - The USB device port.
+ *   configid - The USB composite configuration
+ *
+ * Returned Value:
+ *   A non-NULL handle value is returned on success.  NULL is returned on
+ *   any failure.
+ *
+ ****************************************************************************/
+
+FAR void *board_composite_connect(int port, int configid)
+{
+  /* Here we are composing the configuration of the usb composite device.
+   *
+   * The standard is to use one CDC/ACM and one USB mass storage device.
+   */
+
+  if (configid == 0)
+    {
+#ifdef CONFIG_USBMSC_COMPOSITE
+      struct composite_devdesc_s dev[2];
+      int ifnobase = 0;
+      int strbase  = COMPOSITE_NSTRIDS;
+
+      /* Configure the CDC/ACM device */
+
+      /* Ask the cdcacm driver to fill in the constants we didn't
+       * know here.
+       */
+
+      cdcacm_get_composite_devdesc(&dev[0]);
+
+      /* Overwrite and correct some values... */
+
+      /* The callback functions for the CDC/ACM class */
+
+      dev[0].classobject  = cdcacm_classobject;
+      dev[0].uninitialize = cdcacm_uninitialize;
+
+      /* Interfaces */
+
+      dev[0].devinfo.ifnobase = ifnobase;             /* Offset to Interface-IDs */
+      dev[0].minor = 0;                               /* The minor interface number */
+
+      /* Strings */
+
+      dev[0].devinfo.strbase = strbase;               /* Offset to String Numbers */
+
+      /* Endpoints */
+
+      dev[0].devinfo.epno[CDCACM_EP_INTIN_IDX]   = 3;
+      dev[0].devinfo.epno[CDCACM_EP_BULKIN_IDX]  = 4;
+      dev[0].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 5;
+
+      /* Count up the base numbers */
+
+      ifnobase += dev[0].devinfo.ninterfaces;
+      strbase  += dev[0].devinfo.nstrings;
+
+      /* Configure the mass storage device device */
+
+      /* Ask the usbmsc driver to fill in the constants we didn't
+       * know here.
+       */
+
+      usbmsc_get_composite_devdesc(&dev[1]);
+
+      /* Overwrite and correct some values... */
+
+      /* The callback functions for the USBMSC class */
+
+      dev[1].classobject  = board_mscclassobject;
+      dev[1].uninitialize = board_mscuninitialize;
+
+      /* Interfaces */
+
+      dev[1].devinfo.ifnobase = ifnobase;               /* Offset to Interface-IDs */
+      dev[1].minor = 0;                                 /* The minor interface number */
+
+      /* Strings */
+
+      dev[1].devinfo.strbase = strbase;                 /* Offset to String Numbers */
+
+      /* Endpoints */
+
+      dev[1].devinfo.epno[USBMSC_EP_BULKIN_IDX]  = 1;
+      dev[1].devinfo.epno[USBMSC_EP_BULKOUT_IDX] = 2;
+
+      /* Count up the base numbers */
+
+      ifnobase += dev[1].devinfo.ninterfaces;
+      strbase  += dev[1].devinfo.nstrings;
+
+      return composite_initialize(2, dev);
+#else
+      return NULL;
+#endif
+    }
+
+  /* Configuration with three CDC/ACMs
+   *
+   * This configuration can be used e.g. on a samv71-xult. The samv71 has
+   * 10 Endpoints (EPs). The EPs 0 up to 7 are DMA aware. The EPs 8 and 9
+   * are not.
+   *
+   * In a composite device we need the EP0 as an control Endpoint.  Each
+   * CDC/ACM needs one Interrupt driven and two bulk Endpoints.  This is
+   * why we configure the EPs 7, 8 and 9 to be the IRQ-EPs and the
+   * EP-Pairs 1/2, 3/4, 5/6 to be the bulk EPs for each device.
+   *
+   * This means, that
+   *
+   *   - the Composite device uses EP0 as the control-Endpoint,
+   *   - the CDC/ACM 0 uses EP7, EP1 and EP2,
+   *   - the CDC/ACM 1 uses EP8, EP3 and EP4,
+   *   - the CDC/ACM 2 uses EP9, EP5 and EP6
+   *
+   * as its EP-Configuration.
+   */
+
+  else if (configid == 1)
+    {
+      struct composite_devdesc_s dev[3];
+      int strbase = COMPOSITE_NSTRIDS;
+      int ifnobase = 0;
+      int ia;
+
+      for (ia = 0; ia < 3; ia++)
+        {
+          /* Ask the cdcacm driver to fill in the
+           * constants we didn't know here
+           */
+
+          cdcacm_get_composite_devdesc(&dev[ia]);
+
+          /* Overwrite and correct some values... */
+
+          /* The callback functions for the CDC/ACM class */
+
+          dev[ia].classobject = cdcacm_classobject;
+          dev[ia].uninitialize = cdcacm_uninitialize;
+
+          dev[ia].minor = ia;                         /* The minor interface number */
+
+          /* Interfaces */
+
+          dev[ia].devinfo.ifnobase = ifnobase;        /* Offset to Interface-IDs */
+
+          /* Strings */
+
+          dev[ia].devinfo.strbase = strbase;          /* Offset to String Numbers */
+
+          /* Endpoints */
+
+          dev[ia].devinfo.epno[CDCACM_EP_INTIN_IDX]   = 7 + ia;
+          dev[ia].devinfo.epno[CDCACM_EP_BULKIN_IDX]  = 1 + ia * 2;
+          dev[ia].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 2 + ia * 2;
+
+          ifnobase += dev[ia].devinfo.ninterfaces;
+          strbase  += dev[ia].devinfo.nstrings;
+        }
+
+      return composite_initialize(3, dev);
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
+#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */
diff --git a/boards/arm/samd5e5/metro-m4/src/sam_i2c.c b/boards/arm/samd5e5/metro-m4/src/sam_i2c.c
new file mode 100644
index 0000000..ec22bb2
--- /dev/null
+++ b/boards/arm/samd5e5/metro-m4/src/sam_i2c.c
@@ -0,0 +1,87 @@
+/****************************************************************************
+ * boards/arm/samd5e5/metro-m4/src/sam_i2c.c
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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 <stdint.h>
+#include <stdbool.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/i2c/i2c_master.h>
+
+#include "arm_arch.h"
+#include "chip.h"
+#include "metro-m4.h"
+#include "sam_config.h"
+#include "sam_i2c_master.h"
+#include <arch/board/board.h>
+
+#if defined(SAMD5E5_HAVE_I2C5_MASTER)
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: metro_m4_i2cdev_initialize
+ *
+ * Description:
+ *   Called to configure I2C
+ *
+ ****************************************************************************/
+
+int metro_m4_i2cdev_initialize(void)
+{
+    int ret = OK;
+
+  #ifdef SAMD5E5_HAVE_I2C5_MASTER
+      g_i2c5_dev = sam_i2c_master_initialize(5);
+
+      if (!g_i2c5_dev)
+        {
+          syslog(LOG_ERR, "ERROR: metro_m4_i2cdev_initialize() failed: %d\n",
+                ret);
+          ret = -ENODEV;
+        }
+      else
+        {
+          #ifdef CONFIG_I2C_DRIVER
+                ret = i2c_register(g_i2c5_dev, 5);
+          #endif
+        }
+  #endif
+
+  return ret;
+}
+
+#endif /* SAMD5E5_HAVE_I2C5_MASTER */
diff --git a/boards/arm/samd5e5/metro-m4/src/sam_usbdev.c b/boards/arm/samd5e5/metro-m4/src/sam_usbdev.c
new file mode 100644
index 0000000..b6a7aa8
--- /dev/null
+++ b/boards/arm/samd5e5/metro-m4/src/sam_usbdev.c
@@ -0,0 +1,92 @@
+/****************************************************************************
+ * boards/arm/samd5e5/metro-m4/src/sam_usbdev.c
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <debug.h>
+
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/usb/usbdev_trace.h>
+
+#include "arm_arch.h"
+#include "metro-m4.h"
+#include <arch/board/board.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_usbinitialize
+ *
+ * Description:
+ *   Called to setup USB-related GPIO pins
+ *
+ ****************************************************************************/
+
+void sam_usbinitialize(void)
+{
+  /* USB Soft Connect Pullup */
+}
+
+/****************************************************************************
+ * Name:  sam_usbpullup
+ *
+ * Description:
+ *   If USB is supported and the board supports a pullup via GPIO (for USB
+ *   software connect and disconnect), then the board software must provide
+ *   sam_pullup. See include/nuttx/usb/usbdev.h for additional description
+ *   of this method. Alternatively, if no pull-up GPIO the following EXTERN
+ *   can be redefined to be NULL.
+ *
+ ****************************************************************************/
+
+int sam_usbpullup(FAR struct usbdev_s *dev, bool enable)
+{
+  usbtrace(TRACE_DEVPULLUP, (uint16_t)enable);
+  return OK;
+}
+
+/****************************************************************************
+ * Name:  sam_usbsuspend
+ *
+ * Description:
+ *   Board logic must provide the sam_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 sam_usbsuspend(FAR struct usbdev_s *dev, bool resume)
+{
+  uinfo("resume: %d\n", resume);
+}
diff --git a/boards/arm/samd5e5/metro-m4/src/sam_usbhost.c b/boards/arm/samd5e5/metro-m4/src/sam_usbhost.c
new file mode 100644
index 0000000..033edf8
--- /dev/null
+++ b/boards/arm/samd5e5/metro-m4/src/sam_usbhost.c
@@ -0,0 +1,236 @@
+/****************************************************************************
+ * boards/arm/samd5e5/metro-m4/src/sam_usbhost.c
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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 <sys/types.h>
+#include <sys/mount.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <sched.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/kthread.h>
+#include <nuttx/usb/usbhost.h>
+#include <nuttx/usb/usbdev_trace.h>
+
+#include "chip.h"
+#include "arm_arch.h"
+#include "metro-m4.h"
+#include "sam_port.h"
+#include "sam_usbhost.h"
+#include <arch/board/board.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_USBDEV) || defined(CONFIG_USBHOST)
+#define HAVE_USB 1
+#endif
+
+#ifndef CONFIG_METRO_M4_USBHOST_PRIO
+#define CONFIG_METRO_M4_USBHOST_PRIO 100
+#endif
+
+#ifndef CONFIG_METRO_M4_USBHOST_STACKSIZE
+#define CONFIG_METRO_M4_USBHOST_STACKSIZE 1024
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST
+static struct usbhost_connection_s *g_usbconn;
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_waiter
+ *
+ * Description:
+ *   Wait for USB devices to be connected.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST
+static int usbhost_waiter(int argc, char *argv[])
+{
+  struct usbhost_hubport_s *hport;
+  uinfo("Running\n");
+
+  for (; ; )
+    {
+      /* Wait for the device to change state */
+
+      DEBUGVERIFY(CONN_WAIT(g_usbconn, &hport));
+      uinfo("%s\n", hport->connected ? "connected" : "disconnected");
+
+      /* Did we just become connected? */
+
+      if (hport->connected)
+        {
+          /* Yes.. enumerate the newly connected device */
+
+         (void)CONN_ENUMERATE(g_usbconn, hport);
+        }
+
+#ifdef CONFIG_METRO_M4_USB_AUTOMOUNT
+      /* Let the automounter know about the insertion event */
+
+      sam_automount_event(hport->connected);
+#endif
+    }
+
+  /* Keep the compiler from complaining */
+
+  return 0;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sam_usbinitialize
+ *
+ * Description:
+ *
+ ****************************************************************************/
+
+void sam_usbinitialize(void)
+{
+}
+
+/****************************************************************************
+ * Name: sam_usbhost_vbusdrive
+ *
+ * Description:
+ *   Enable/disable driving of VBUS 5V output. This function must be provided
+ *   be each platform that implements the HS host interface
+ *
+ * Input Parameters:
+ *   iface  - For future growth to handle multiple USB host interface. Should
+ *            be zero.
+ *   enable - true: enable VBUS power; false: disable VBUS power
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST
+void sam_usbhost_vbusdrive(int iface, bool enable)
+{
+  DEBUGASSERT(iface == 0);
+  if (enable)
+    {
+      /* Set your function here! */
+    }
+  else
+    {
+      /* Set your function here! */
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: samd_usbhost_initialize
+ *
+ * Description:
+ *   Called at application startup time to initialize the USB host
+ *   functionality. This function will start a thread that will monitor for
+ *   device connection/disconnection events.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST
+int samd_usbhost_initialize(void)
+{
+  int pid;
+  int ret;
+
+  /* First, register all of the class drivers needed to support the drivers
+   * that we care about:
+   */
+
+  uinfo("Register class drivers\n");
+
+#ifdef CONFIG_USBHOST_MSC
+  /* Register the USB mass storage class class */
+
+  ret = usbhost_msc_initialize();
+  if (ret != OK)
+    {
+      uerr("ERROR: Failed to register the mass storage class: %d\n", ret);
+    }
+#endif
+
+#ifdef CONFIG_USBHOST_HIDKBD
+  /* Initialize the HID keyboard class */
+
+  ret = usbhost_kbdinit();
+  if (ret != OK)
+    {
+      uerr("ERROR: Failed to register the HID keyboard class\n");
+    }
+#endif
+
+#ifdef CONFIG_USBHOST_HIDMOUSE
+  /* Initialize the HID mouse class */
+
+  ret = usbhost_mouse_init();
+  if (ret != OK)
+    {
+      uerr("ERROR: Failed to register the HID mouse class\n");
+    }
+#endif
+
+  /* Then get an instance of the USB host interface */
+
+  uinfo("Initialize USB host\n");
+  g_usbconn = sam_usbhost_initialize(0);
+  if (g_usbconn)
+    {
+      /* Start a thread to handle device connection. */
+
+      uinfo("Start usbhost_waiter\n");
+      pid =
+        kthread_create("usbhost", CONFIG_METRO_M4_USBHOST_PRIO,
+                       CONFIG_METRO_M4_USBHOST_STACKSIZE,
+                       (main_t) usbhost_waiter, (FAR char *const *)NULL);
+      return pid < 0 ? -ENOEXEC : OK;
+    }
+
+  return -ENODEV;
+}
+#endif
diff --git a/boards/arm/samd5e5/metro-m4/src/sam_usbmsc.c b/boards/arm/samd5e5/metro-m4/src/sam_usbmsc.c
new file mode 100644
index 0000000..a62162f
--- /dev/null
+++ b/boards/arm/samd5e5/metro-m4/src/sam_usbmsc.c
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * boards/arm/samd5e5/metro-m4/src/sam_usbmsc.c
+ *
+ *   Copyright 2020 Falker Automacao Agricola LTDA.
+ *   Author: Leomar Mateus Radke <le...@falker.com.br>
+ *   Author: Ricardo Wartchow <wa...@gmail.com>
+ *
+ * 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 <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+
+#include <nuttx/board.h>
+
+#include "metro-m4.h"
+#include <arch/board/board.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SYSTEM_USBMSC_DEVMINOR1
+#  define CONFIG_SYSTEM_USBMSC_DEVMINOR1 0
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: board_usbmsc_initialize
+ *
+ * Description:
+ *   Perform architecture specific initialization of the USB MSC device.
+ *
+ ****************************************************************************/
+
+int board_usbmsc_initialize(int port)
+{
+  /* If system/usbmsc is built as an NSH command
+   */
+
+#ifndef CONFIG_NSH_BUILTIN_APPS
+#else
+  return OK;
+#endif
+}


[incubator-nuttx] 01/03: arch: samd5e5 : Add watchdog timer drivers.

Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit af85c7801a21684c22115d68ad9640b3daaa1aaa
Author: leomarradke <le...@falker.com.br>
AuthorDate: Mon Aug 3 20:41:10 2020 -0300

    arch: samd5e5 : Add watchdog timer drivers.
    
    boards: metro-m4  Add support for starting the watchdog timer on the metro-m4.
    
    Testing:
    - Build check only
    
    Signed-off-by: Leomar Mateus Radke  <le...@falker.com.br>
---
 arch/arm/src/samd5e5/hardware/sam_wdt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/src/samd5e5/hardware/sam_wdt.h b/arch/arm/src/samd5e5/hardware/sam_wdt.h
index f6911b5..9d1d98b 100644
--- a/arch/arm/src/samd5e5/hardware/sam_wdt.h
+++ b/arch/arm/src/samd5e5/hardware/sam_wdt.h
@@ -143,4 +143,4 @@
  * Public Data
  ****************************************************************************/
 
-#endif /* __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_WDT_H */
+#endif /* __ARCH_ARM_SRC_SAMD5E5_HARDWARE_SAM_WDT_H */
\ No newline at end of file