diff --git a/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h b/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h index add5479e97..94608d0997 100644 --- a/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h +++ b/arch/arm/src/imxrt/hardware/rt106x/imxrt106x_pinmux.h @@ -1004,6 +1004,22 @@ #define GPIO_USDHC2_WP_1 (GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_10_INDEX)) #define GPIO_USDHC2_WP_2 (GPIO_PERIPH | GPIO_ALT6 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_37_INDEX)) +/* USB OTG */ + +#define GPIO_USB1_OTG_ID_1 (GPIO_PERIPH | GPIO_ALT3 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_01_INDEX)) +#define GPIO_USB1_OTG_ID_2 (GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_02_INDEX)) +#define GPIO_USB1_OTG_OC_1 (GPIO_PERIPH | GPIO_ALT3 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_03_INDEX)) +#define GPIO_USB1_OTG_OC_2 (GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_03_INDEX)) +#define GPIO_USB1_OTG_PWR_1 (GPIO_PERIPH | GPIO_ALT3 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_02_INDEX)) +#define GPIO_USB1_OTG_PWR_2 (GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_01_INDEX)) + +#define GPIO_USB2_OTG_ID_1 (GPIO_PERIPH | GPIO_ALT3 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_00_INDEX)) +#define GPIO_USB2_OTG_ID_2 (GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B1_00_INDEX)) +#define GPIO_USB2_OTG_OC_1 (GPIO_PERIPH | GPIO_ALT3 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_40_INDEX)) +#define GPIO_USB2_OTG_OC_2 (GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_14_INDEX)) +#define GPIO_USB2_OTG_PWR_1 (GPIO_PERIPH | GPIO_ALT3 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_EMC_41_INDEX)) +#define GPIO_USB2_OTG_PWR_2 (GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_AD_B0_15_INDEX)) + /* Watchdog Timer (WDOG1-2) */ #define GPIO_WDOG1_1 (GPIO_PERIPH | GPIO_ALT0 | GPIO_PADMUX(IMXRT_PADMUX_GPIO_B1_13_INDEX)) diff --git a/arch/arm/src/imxrt/imxrt_clockconfig.c b/arch/arm/src/imxrt/imxrt_clockconfig.c index c533a92131..ec29f10725 100644 --- a/arch/arm/src/imxrt/imxrt_clockconfig.c +++ b/arch/arm/src/imxrt/imxrt_clockconfig.c @@ -232,8 +232,8 @@ static void imxrt_pllsetup(void) { #ifdef CONFIG_ARCH_FAMILY_IMXRT102x uint32_t pll2reg; - uint32_t pll3reg; #endif + uint32_t pll3reg; uint32_t reg; #if (defined(CONFIG_ARCH_FAMILY_IMXRT105x) || defined (CONFIG_ARCH_FAMILY_IMXRT106x)) @@ -255,6 +255,31 @@ static void imxrt_pllsetup(void) { } + /* Init USB PLL3 */ + + /* capture it's original value */ + + pll3reg = getreg32(IMXRT_CCM_ANALOG_PFD_480); + putreg32(pll3reg | + CCM_ANALOG_PFD_480_PFD0_CLKGATE | + CCM_ANALOG_PFD_480_PFD1_CLKGATE | + CCM_ANALOG_PFD_480_PFD2_CLKGATE | + CCM_ANALOG_PFD_480_PFD3_CLKGATE, + IMXRT_CCM_ANALOG_PFD_480); + + reg = IMXRT_USB1_PLL_DIV_SELECT | + CCM_ANALOG_PLL_USB1_ENABLE | + CCM_ANALOG_PLL_USB1_EN_USB_CLKS | + CCM_ANALOG_PLL_USB1_POWER; + putreg32(reg, IMXRT_CCM_ANALOG_PLL_USB1); + + while ((getreg32(IMXRT_CCM_ANALOG_PLL_USB1) & + CCM_ANALOG_PLL_USB1_LOCK) == 0) + { + } + + putreg32(pll3reg, IMXRT_CCM_ANALOG_PFD_480); + #ifdef CONFIG_IMXRT_LCD /* Init Video PLL5 */ diff --git a/boards/arm/imxrt/imxrt1060-evk/include/board.h b/boards/arm/imxrt/imxrt1060-evk/include/board.h index 7f9a5ac217..3cc8accdba 100644 --- a/boards/arm/imxrt/imxrt1060-evk/include/board.h +++ b/boards/arm/imxrt/imxrt1060-evk/include/board.h @@ -125,6 +125,8 @@ #define IMXRT_SYS_PLL_SELECT CCM_ANALOG_PLL_SYS_DIV_SELECT_22 +#define IMXRT_USB1_PLL_DIV_SELECT CCM_ANALOG_PLL_USB1_DIV_SELECT_20 + #define BOARD_CPU_FREQUENCY \ (BOARD_XTAL_FREQUENCY * (IMXRT_ARM_PLL_DIV_SELECT / 2)) / IMXRT_ARM_PODF_DIVIDER diff --git a/boards/arm/imxrt/imxrt1060-evk/src/Makefile b/boards/arm/imxrt/imxrt1060-evk/src/Makefile index 498bd11f50..0a3ad3b706 100644 --- a/boards/arm/imxrt/imxrt1060-evk/src/Makefile +++ b/boards/arm/imxrt/imxrt1060-evk/src/Makefile @@ -82,4 +82,8 @@ ifeq ($(CONFIG_IMXRT_LCD),y) CSRCS += imxrt_lcd.c endif +ifeq ($(CONFIG_IMXRT_USBOTG),y) +CSRCS += imxrt_usbhost.c +endif + include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h b/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h index c1267ad992..87ddbb999b 100644 --- a/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h +++ b/boards/arm/imxrt/imxrt1060-evk/src/imxrt1060-evk.h @@ -177,7 +177,6 @@ #define GPIO_FT5X06_CTRSTn (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | \ GPIO_PORT1 | GPIO_PIN2 | IOMUX_FT5X06_RST) /* AD_B0_02 */ - /* Test Pins **************************************************************/ #define BOARD_NGPIOIN 0 /* Amount of GPIO Input pins */ @@ -196,6 +195,10 @@ #define GPIO_GOUT4 (GPIO_OUTPUT | GPIO_OUTPUT_ZERO | IOMUX_GOUT_DEFAULT | \ GPIO_PIN9 | GPIO_PORT1) +/* USB OTG ID Pin: GPIO_AD_B1_02 */ + +#define GPIO_USBOTG_ID (GPIO_USB_OTG1_ID_1 | IOMUX_USBOTG_ID_DEFAULT) /* AD_B1_02 */ + /**************************************************************************** * Public Types ****************************************************************************/ @@ -298,5 +301,9 @@ int imxrt_ft5x06_register(void); void imxrt_lcd_initialize(void); #endif +#if defined(CONFIG_IMXRT_USBOTG) || defined(CONFIG_USBHOST) +int imxrt_usbhost_initialize(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_ARM_IMXRT1060_EVK_SRC_IMXRT1060_EVK_H */ diff --git a/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c index c737608730..eecc1a67e1 100644 --- a/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c +++ b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_bringup.c @@ -54,6 +54,10 @@ # include "imxrt_usdhc.h" #endif +#ifdef CONFIG_USBMONITOR +# include +#endif + #include "imxrt1060-evk.h" #include /* Must always be included last */ @@ -184,6 +188,25 @@ int imxrt_bringup(void) } #endif +#if defined(CONFIG_IMXRT_USBOTG) || defined(CONFIG_USBHOST) + ret = imxrt_usbhost_initialize(); + if (ret != OK) + { + syslog(LOG_ERR, "ERROR: Failed to start USB host services: %d\n", ret); + return ret; + } +#endif + +#ifdef CONFIG_USBMONITOR + /* Start the USB Monitor */ + + ret = usbmonitor_start(); + if (ret != OK) + { + syslog(LOG_ERR, "ERROR: Failed to start USB monitor: %d\n", ret); + } +#endif + #ifdef CONFIG_DEV_GPIO /* Initialize the GPIO driver */ diff --git a/boards/arm/imxrt/imxrt1060-evk/src/imxrt_usbhost.c b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_usbhost.c new file mode 100644 index 0000000000..94e6996abd --- /dev/null +++ b/boards/arm/imxrt/imxrt1060-evk/src/imxrt_usbhost.c @@ -0,0 +1,314 @@ +/***************************************************************************** + * boards/arm/imxrt/imxrt1060-evk/src/imxrt_usbhost.c + * + * Copyright (C) 2013, 2015-2017 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "hardware/imxrt_pinmux.h" +#include "hardware/imxrt_usbotg.h" +#include "imxrt_periphclks.h" +#include "imxrt1060-evk.h" + +#include /* Must always be included last */ + +#if defined(CONFIG_IMXRT_USBOTG) || defined(CONFIG_USBHOST) + +/***************************************************************************** + * Pre-processor Definitions + *****************************************************************************/ + +#ifndef CONFIG_USBHOST_DEFPRIO +# define CONFIG_USBHOST_DEFPRIO 50 +#endif + +#ifndef CONFIG_USBHOST_STACKSIZE +# ifdef CONFIG_USBHOST_HUB +# define CONFIG_USBHOST_STACKSIZE 1536 +# else +# define CONFIG_USBHOST_STACKSIZE 1024 +# endif +#endif + +/***************************************************************************** + * Private Data + *****************************************************************************/ + +/* Retained device driver handle */ + +static struct usbhost_connection_s *g_ehciconn; + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: ehci_waiter + * + * Description: + * Wait for USB devices to be connected to the EHCI root hub. + * + *****************************************************************************/ + +static int ehci_waiter(int argc, char *argv[]) +{ + FAR struct usbhost_hubport_s *hport; + + uinfo("ehci_waiter: Running\n"); + for (; ; ) + { + /* Wait for the device to change state */ + + DEBUGVERIFY(CONN_WAIT(g_ehciconn, &hport)); + syslog(LOG_INFO, "ehci_waiter: %s\n", + hport->connected ? "connected" : "disconnected"); + + /* Did we just become connected? */ + + if (hport->connected) + { + /* Yes.. enumerate the newly connected device */ + + CONN_ENUMERATE(g_ehciconn, hport); + } + } + + /* Keep the compiler from complaining */ + + return 0; +} + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: imxrt_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. + * + *****************************************************************************/ + +int imxrt_usbhost_initialize(void) +{ + pid_t pid; + int ret; + + imxrt_clockall_usboh3(); + + /* Make sure we don't accidentially switch on USB bus power */ + + *((uint32_t *)IMXRT_USBNC_USB_OTG1_CTRL) = USBNC_PWR_POL; + *((uint32_t *)0x400d9030) = (1 << 21); + *((uint32_t *)0x400d9000) = 0; + + /* Setup pins, with power initially off */ + + imxrt_config_gpio(GPIO_USBOTG_ID); + + /* First, register all of the class drivers needed to support the drivers + * that we care about + */ + +#ifdef CONFIG_USBHOST_HUB + /* Initialize USB hub support */ + + ret = usbhost_hub_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: usbhost_hub_initialize failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_MSC + /* Register the USB host Mass Storage Class */ + + ret = usbhost_msc_initialize(); + if (ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to register the mass storage class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_CDCACM + /* Register the CDC/ACM serial class */ + + ret = usbhost_cdcacm_initialize(); + if (ret != OK) + { + uerr("ERROR: Failed to register the CDC/ACM serial class\n"); + } +#endif + +#ifdef CONFIG_USBHOST_HIDKBD + /* Register the USB host HID keyboard class driver */ + + ret = usbhost_kbdinit(); + if (ret != OK) + { + uerr("ERROR: Failed to register the KBD class\n"); + } +#endif + + /* Then get an instance of the USB EHCI interface. */ + + g_ehciconn = imxrt_ehci_initialize(0); + + if (!g_ehciconn) + { + uerr("ERROR: imxrt_ehci_initialize failed\n"); + return -ENODEV; + } + + /* Start a thread to handle device connection. */ + + pid = kthread_create("EHCI Monitor", CONFIG_USBHOST_DEFPRIO, + CONFIG_USBHOST_STACKSIZE, + (main_t)ehci_waiter, (FAR char * const *)NULL); + if (pid < 0) + { + uerr("ERROR: Failed to create ehci_waiter task: %d\n", ret); + return -ENODEV; + } + + return OK; +} + +/***************************************************************************** + * Name: imxrt_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. + * Since the IMXRT has only a downstream port, zero is + * the only possible value for this parameter. + * enable - true: enable VBUS power; false: disable VBUS power + * + * Returned Value: + * None + * + *****************************************************************************/ + +#define HCOR ((volatile struct ehci_hcor_s *)IMXRT_USBOTG_HCOR_BASE) + +void imxrt_usbhost_vbusdrive(int rhport, bool enable) +{ + uint32_t regval; + + uinfo("RHPort%d: enable=%d\n", rhport + 1, enable); + + /* The IMXRT has only a single root hub port */ + + if (rhport == 0) + { + /* Then enable or disable VBUS power */ + + regval = HCOR->portsc[rhport]; + regval &= ~EHCI_PORTSC_PP; + if (enable) + { + regval |= EHCI_PORTSC_PP; + } + + HCOR->portsc[rhport] = regval; + } +} + +/**************************************************************************** + * Name: imxrt_setup_overcurrent + * + * Description: + * Setup to receive an interrupt-level callback if an overcurrent condition + * is detected. + * + * Input Parameters: + * handler - New overcurrent interrupt handler + * arg - The argument that will accompany the interrupt + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * failure. + * + ****************************************************************************/ + +#if 0 /* Not ready yet */ +int imxrt_setup_overcurrent(xcpt_t handler, void *arg) +{ + irqstate_t flags; + + /* Disable interrupts until we are done. This guarantees that the + * following operations are atomic. + */ + + flags = enter_critical_section(); + + /* Configure the interrupt */ + +#warning Missing logic + + leave_critical_section(flags); + return OK; +} +#endif /* 0 */ + +#endif /* CONFIG_IMXRT_USBOTG || CONFIG_USBHOST */ diff --git a/drivers/usbhost/usbhost_cdcacm.c b/drivers/usbhost/usbhost_cdcacm.c index 7b195e7614..f23c599ace 100644 --- a/drivers/usbhost/usbhost_cdcacm.c +++ b/drivers/usbhost/usbhost_cdcacm.c @@ -394,7 +394,7 @@ static bool usbhost_txempty(FAR struct uart_dev_s *uartdev); * device. */ -static const struct usbhost_id_s g_id[2] = +static const struct usbhost_id_s g_id[4] = { { USB_CLASS_CDC, /* base */ @@ -409,6 +409,20 @@ static const struct usbhost_id_s g_id[2] = CDC_PROTO_ATM, /* proto */ 0, /* vid */ 0 /* pid */ + }, + { + USB_CLASS_VENDOR_SPEC, /* base */ + CDC_SUBCLASS_NONE, /* subclass */ + CDC_PROTO_NONE, /* proto */ + 0x2c7c, /* vid */ + 0x0125 /* pid */ + }, + { + USB_CLASS_VENDOR_SPEC, /* base */ + CDC_SUBCLASS_ACM, /* subclass */ + CDC_PROTO_NONE, /* proto */ + 0x2c7c, /* vid */ + 0x0125 /* pid */ } }; @@ -418,7 +432,7 @@ static struct usbhost_registry_s g_cdcacm = { NULL, /* flink */ usbhost_create, /* create */ - 2, /* nids */ + 4, /* nids */ &g_id[0] /* id[] */ }; @@ -1380,7 +1394,8 @@ static int usbhost_cfgdesc(FAR struct usbhost_cdcacm_s *priv, /* Check for the CDC/ACM data interface */ - if (ifdesc->classid == USB_CLASS_CDC_DATA && + if ((ifdesc->classid == USB_CLASS_CDC_DATA || + ifdesc->classid == USB_CLASS_VENDOR_SPEC) && (found & USBHOST_DATAIF_FOUND) == 0) { /* Save the data interface number and mark that the data @@ -1494,7 +1509,8 @@ static int usbhost_cfgdesc(FAR struct usbhost_cdcacm_s *priv, /* Check for an interrupt IN endpoint. */ else if (currif == USBHOST_CTRLIF_FOUND && - (epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_INT) + (epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == + USB_EP_ATTR_XFER_INT) { /* Yes.. it is a interrupt endpoint. IN or OUT? */ @@ -1690,7 +1706,7 @@ static void usbhost_putle32(FAR uint8_t *dest, uint32_t val) /* Little endian means LS halfword first in byte stream */ usbhost_putle16(dest, (uint16_t)(val & 0xffff)); - usbhost_putle16(dest+2, (uint16_t)(val >> 16)); + usbhost_putle16(dest + 2, (uint16_t)(val >> 16)); } #endif @@ -1890,7 +1906,7 @@ usbhost_create(FAR struct usbhost_hubport_s *hport, if (usbhost_devno_alloc(priv) == OK) { - /* Initialize class method function pointers */ + /* Initialize class method function pointers */ priv->usbclass.hport = hport; priv->usbclass.connect = usbhost_connect; @@ -2199,6 +2215,7 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass) /**************************************************************************** * Serial Lower-Half Interfaces ****************************************************************************/ + /**************************************************************************** * Name: usbhost_setup * @@ -2608,7 +2625,6 @@ static void usbhost_rxint(FAR struct uart_dev_s *uartdev, bool enable) static bool usbhost_rxavailable(FAR struct uart_dev_s *uartdev) { - FAR struct usbhost_cdcacm_s *priv; DEBUGASSERT(uartdev && uartdev->priv);