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

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


The following commit(s) were added to refs/heads/master by this push:
     new ea8c913da19 boards/stm32f103-minimum: Add MAX3421E USB host support
ea8c913da19 is described below

commit ea8c913da19ffdebb4331149ee5be9673dbd335a
Author: Alan Carvalho de Assis <[email protected]>
AuthorDate: Thu Oct 22 15:23:56 2026 -0300

    boards/stm32f103-minimum: Add MAX3421E USB host support
    
    Add support for an external MAX3421E USB host controller on SPI1:
    
      SCK  PA5    MISO  PA6    MOSI  PA7    SS  PA4
      INT  PB8 (falling edge)  RES#  PB9 (optional, pulsed at boot)
    
    At boot the board checks that the chip answers (revision, register
    write/read-back and oscillator) before starting the driver, registers
    the enabled class drivers (MSC, HID keyboard, HID mouse) and starts the
    connection monitor thread.
    
    The EXTI is disabled while the driver handles an interrupt, so an INT
    edge in that window is lost; enable() dispatches the handler when INT
    is already asserted.
    
    Add the usbhost configuration (HID mouse + touchscreen example to read
    /dev/mouse0) and document the wiring and options in the board page.
    
    Also fix the nxstyle issues reported in the touched board files.
    
    Signed-off-by: Alan C. Assis <[email protected]>
    Assisted-by: Claude Code Opus 5.5
---
 .../arm/stm32f1/boards/stm32f103-minimum/index.rst |  77 ++++
 boards/arm/stm32f1/stm32f103-minimum/Kconfig       |  29 ++
 .../stm32f103-minimum/configs/usbhost/defconfig    |  81 ++++
 .../stm32f1/stm32f103-minimum/src/CMakeLists.txt   |   4 +
 boards/arm/stm32f1/stm32f103-minimum/src/Make.defs |   4 +
 .../stm32f1/stm32f103-minimum/src/stm32_bringup.c  |  29 +-
 .../stm32f1/stm32f103-minimum/src/stm32_max3421e.c | 407 +++++++++++++++++++++
 .../arm/stm32f1/stm32f103-minimum/src/stm32_spi.c  |  15 +-
 .../stm32f103-minimum/src/stm32f103_minimum.h      |  29 ++
 9 files changed, 664 insertions(+), 11 deletions(-)

diff --git 
a/Documentation/platforms/arm/stm32f1/boards/stm32f103-minimum/index.rst 
b/Documentation/platforms/arm/stm32f1/boards/stm32f103-minimum/index.rst
index eaf86e3339e..73b98cd2133 100644
--- a/Documentation/platforms/arm/stm32f1/boards/stm32f103-minimum/index.rst
+++ b/Documentation/platforms/arm/stm32f1/boards/stm32f103-minimum/index.rst
@@ -637,6 +637,65 @@ typically adds short-circuit and ESD protection so the 
chip can safely connect
 to a real vehicle or bench network. Common parts include SN65HVD230, MCP2551,
 and TJA1050.
 
+MAX3421E USB Host
+=================
+
+The STM32F103C8 only has a USB device controller.  USB host support can be
+added with an external MAX3421E USB host controller on SPI1, for example
+the low cost "USB Host Mini" (HW-244) module.  See
+:doc:`/os/drivers/special/usbhost/max3421e` for the driver and for the
+VBUS modification that the module needs (the USB-A socket must get 5V
+while the MAX3421E itself runs at 3.3V).
+
+Connect the module this way:
+
+=================  ===================  =====================================
+MAX3421E module    STM32F103 Minimum    Notes
+=================  ===================  =====================================
+SCK                PA5                  SPI1 SCK
+MISO               PA6                  SPI1 MISO
+MOSI               PA7                  SPI1 MOSI
+SS                 PA4                  SPI1 chip select (shared with the
+                                        other SPI1 devices of this board)
+INT                PB8                  Falling edge interrupt (EXTI8)
+Reset              PB9                  Active low, pulsed at boot
+VCC                3.3V
+GND                GND
+VBUS pad           5V                   Only after cutting the VBUS trace
+=================  ===================  =====================================
+
+PB8 and PB9 are not used by any other function of this board.  PA4 is the
+common SPI1 chip select of this board, so do not enable another SPI1 device
+in the same configuration.
+
+Board options (``Board Selection`` menu, visible when
+``CONFIG_USBHOST_MAX3421E`` is enabled):
+
+``CONFIG_STM32F103MINIMUM_MAX3421E_FREQUENCY``
+   SPI clock (default 4.5MHz).  SPI1 divides PCLK2 (72MHz) by a power of
+   two, so the real clock is the nearest lower value.
+
+``CONFIG_STM32F103MINIMUM_MAX3421E_RST``
+   Drive the MAX3421E ``RES#`` pin from PB9 (default y).  Disable it if
+   ``RES#`` is tied to 3.3V; PB9 is then left untouched.
+
+``CONFIG_STM32F103MINIMUM_MAX3421E_CONNMON_STACKSIZE``
+   Stack size of the thread that waits for USB devices to be connected and
+   enumerates them.
+
+``CONFIG_STM32F103MINIMUM_MAX3421E_CONNMON_PRIORITY``
+   Priority of that thread.
+
+At boot the board checks that the MAX3421E answers before starting the
+driver (revision register, a register write/read-back test and the 12MHz
+oscillator).  The result is printed on the console::
+
+  MAX3421E: REVISION=0x13 GPINPOL rd=0x55/0xaa USBIRQ=0x01
+  MAX3421E: USB host initialized
+
+If the chip does not answer, the driver is not started and an error is
+printed instead.
+
 STM32F103 Minimum - specific Configuration Options
 ==================================================
 
@@ -933,3 +992,21 @@ See the 'CAN support' section above for pins, 
transceivers, and limitations.
 
 A UART adapter on USART1 (PA9/PA10) is required for the NSH console on a
 host PC.
+
+usbhost
+-------
+
+USB host on a MAX3421E module (see the `MAX3421E USB Host`_ section for the
+wiring) with the HID mouse class driver.  When a mouse is connected it is
+registered as ``/dev/mouse0`` and can be tested with the ``tc`` (touchscreen
+example) application, which prints the mouse reports::
+
+    nsh> ls /dev
+    /dev:
+     console
+     mouse0
+     ttyS0
+    nsh> tc 10
+
+The image is larger than 64KiB, so it relies on the 128KiB of flash that
+most STM32F103C8 chips have (see `Using 128KiB of Flash instead of 64KiB`_).
diff --git a/boards/arm/stm32f1/stm32f103-minimum/Kconfig 
b/boards/arm/stm32f1/stm32f103-minimum/Kconfig
index d9ced283ea0..8321066e242 100644
--- a/boards/arm/stm32f1/stm32f103-minimum/Kconfig
+++ b/boards/arm/stm32f1/stm32f103-minimum/Kconfig
@@ -110,4 +110,33 @@ config STM32F103MINIMUM_QETIMER
        default 4
        depends on SENSORS_QENCODER
 
+if USBHOST_MAX3421E
+
+config STM32F103MINIMUM_MAX3421E_FREQUENCY
+       int "MAX3421E SPI frequency"
+       default 4500000
+       range 400000 26000000
+       ---help---
+               SPI1 clock used to talk to the MAX3421E.  The STM32 SPI1 divides
+               PCLK2 (72MHz) by a power of two, so the real clock is the 
nearest
+               lower value (e.g. 4.5MHz, 9MHz, 18MHz).
+
+config STM32F103MINIMUM_MAX3421E_RST
+       bool "MAX3421E reset pin driven by PB9"
+       default y
+       ---help---
+               Drive the MAX3421E RES# pin from PB9.  Disable this if RES# is 
tied
+               to 3.3V; PB9 is then left untouched.
+
+config STM32F103MINIMUM_MAX3421E_CONNMON_STACKSIZE
+       int "MAX3421E USB connection monitor stack size"
+       default DEFAULT_TASK_STACKSIZE
+
+config STM32F103MINIMUM_MAX3421E_CONNMON_PRIORITY
+       int "MAX3421E USB connection monitor priority"
+       default 100
+       range 1 255
+
+endif # USBHOST_MAX3421E
+
 endif
diff --git a/boards/arm/stm32f1/stm32f103-minimum/configs/usbhost/defconfig 
b/boards/arm/stm32f1/stm32f103-minimum/configs/usbhost/defconfig
new file mode 100644
index 00000000000..0eebdeac7e4
--- /dev/null
+++ b/boards/arm/stm32f1/stm32f103-minimum/configs/usbhost/defconfig
@@ -0,0 +1,81 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed 
.config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that 
includes your
+# modifications.
+#
+# CONFIG_DISABLE_DIRECTORY_OPERATIONS is not set
+# CONFIG_DISABLE_OS_API is not set
+# CONFIG_DISABLE_PSEUDOFS_OPERATIONS is not set
+# CONFIG_FS_PROCFS_EXCLUDE_MEMINFO is not set
+# CONFIG_FS_PROCFS_EXCLUDE_PROCESS is not set
+# CONFIG_NSH_DISABLESCRIPT is not set
+# CONFIG_NSH_DISABLE_CAT is not set
+# CONFIG_NSH_DISABLE_CD is not set
+# CONFIG_NSH_DISABLE_CP is not set
+# CONFIG_NSH_DISABLE_ECHO is not set
+# CONFIG_NSH_DISABLE_EXEC is not set
+# CONFIG_NSH_DISABLE_EXIT is not set
+# CONFIG_NSH_DISABLE_FREE is not set
+# CONFIG_NSH_DISABLE_GET is not set
+# CONFIG_NSH_DISABLE_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_LS is not set
+# CONFIG_NSH_DISABLE_MKDIR is not set
+# CONFIG_NSH_DISABLE_MOUNT is not set
+# CONFIG_NSH_DISABLE_PS is not set
+# CONFIG_NSH_DISABLE_PUT is not set
+# CONFIG_NSH_DISABLE_PWD is not set
+# CONFIG_NSH_DISABLE_RM is not set
+# CONFIG_NSH_DISABLE_SLEEP is not set
+# CONFIG_NSH_DISABLE_TEST is not set
+# CONFIG_NSH_DISABLE_UMOUNT is not set
+# CONFIG_NSH_DISABLE_UNAME is not set
+# CONFIG_NSH_DISABLE_WGET is not set
+# CONFIG_NSH_DISABLE_XD is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="stm32f103-minimum"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_STM32F103_MINIMUM=y
+CONFIG_ARCH_CHIP="stm32f1"
+CONFIG_ARCH_CHIP_STM32=y
+CONFIG_ARCH_CHIP_STM32F103C8=y
+CONFIG_ARCH_CHIP_STM32F1=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARD_LOOPSPERMSEC=5483
+CONFIG_BUILTIN=y
+CONFIG_DEFAULT_SMALL=y
+CONFIG_DEFAULT_TASK_STACKSIZE=1536
+CONFIG_EXAMPLES_TOUCHSCREEN=y
+CONFIG_EXAMPLES_TOUCHSCREEN_DEVPATH="/dev/mouse0"
+CONFIG_EXAMPLES_TOUCHSCREEN_MOUSE=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_FILE_STREAM=y
+CONFIG_FS_PROCFS=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_LINE_MAX=80
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=1024
+CONFIG_RAM_SIZE=20480
+CONFIG_RAM_START=0x20000000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HPWORK=y
+CONFIG_SCHED_HPWORKPRIORITY=192
+CONFIG_SCHED_HPWORKSTACKSIZE=1024
+CONFIG_SCHED_WAITPID=y
+CONFIG_SERIAL_TERMIOS=y
+CONFIG_START_DAY=5
+CONFIG_START_MONTH=7
+CONFIG_START_YEAR=2011
+CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y
+CONFIG_STM32_JTAG_FULL_ENABLE=y
+CONFIG_STM32_SPI1=y
+CONFIG_STM32_USART1=y
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=0
+CONFIG_USART1_SERIAL_CONSOLE=y
+CONFIG_USBHOST=y
+CONFIG_USBHOST_HIDMOUSE=y
+CONFIG_USBHOST_MAX3421E=y
diff --git a/boards/arm/stm32f1/stm32f103-minimum/src/CMakeLists.txt 
b/boards/arm/stm32f1/stm32f103-minimum/src/CMakeLists.txt
index 4b1f029a536..8bf405b901d 100644
--- a/boards/arm/stm32f1/stm32f103-minimum/src/CMakeLists.txt
+++ b/boards/arm/stm32f1/stm32f103-minimum/src/CMakeLists.txt
@@ -94,6 +94,10 @@ if(CONFIG_USBDEV)
   list(APPEND SRCS stm32_usbdev.c)
 endif()
 
+if(CONFIG_USBHOST_MAX3421E)
+  list(APPEND SRCS stm32_max3421e.c)
+endif()
+
 if(CONFIG_USBMSC)
   list(APPEND SRCS stm32_usbmsc.c)
 endif()
diff --git a/boards/arm/stm32f1/stm32f103-minimum/src/Make.defs 
b/boards/arm/stm32f1/stm32f103-minimum/src/Make.defs
index fb3dd5177c1..53fb66bd91e 100644
--- a/boards/arm/stm32f1/stm32f103-minimum/src/Make.defs
+++ b/boards/arm/stm32f1/stm32f103-minimum/src/Make.defs
@@ -94,6 +94,10 @@ ifeq ($(CONFIG_USBDEV),y)
   CSRCS += stm32_usbdev.c
 endif
 
+ifeq ($(CONFIG_USBHOST_MAX3421E),y)
+  CSRCS += stm32_max3421e.c
+endif
+
 ifeq ($(CONFIG_USBMSC),y)
 CSRCS += stm32_usbmsc.c
 endif
diff --git a/boards/arm/stm32f1/stm32f103-minimum/src/stm32_bringup.c 
b/boards/arm/stm32f1/stm32f103-minimum/src/stm32_bringup.c
index 90273d10732..aef2bef98f7 100644
--- a/boards/arm/stm32f1/stm32f103-minimum/src/stm32_bringup.c
+++ b/boards/arm/stm32f1/stm32f103-minimum/src/stm32_bringup.c
@@ -265,15 +265,16 @@ int stm32_bringup(void)
 
 #ifdef CONFIG_I2C_DRIVER
   /* Register I2C drivers on behalf of the I2C tool */
-  #ifdef CONFIG_STM32_I2C1
-    stm32_i2c_register(1);
-  #endif
-  #ifdef CONFIG_STM32_I2C2
-    stm32_i2c_register(2);
-  #endif
-  #ifdef CONFIG_STM32_I2C3
-    stm32_i2c_register(3);
-  #endif
+
+#  ifdef CONFIG_STM32_I2C1
+  stm32_i2c_register(1);
+#  endif
+#  ifdef CONFIG_STM32_I2C2
+  stm32_i2c_register(2);
+#  endif
+#  ifdef CONFIG_STM32_I2C3
+  stm32_i2c_register(3);
+#  endif
 #endif
 
 #ifdef CONFIG_LCD_BACKPACK
@@ -468,6 +469,16 @@ int stm32_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_USBHOST_MAX3421E
+  /* Initialize the MAX3421E USB host controller */
+
+  ret = stm32_max3421e_setup();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: stm32_max3421e_setup() failed: %d\n", ret);
+    }
+#endif
+
 #ifdef CONFIG_CL_MFRC522
   ret = stm32_mfrc522initialize("/dev/rfid0");
   if (ret < 0)
diff --git a/boards/arm/stm32f1/stm32f103-minimum/src/stm32_max3421e.c 
b/boards/arm/stm32f1/stm32f103-minimum/src/stm32_max3421e.c
new file mode 100644
index 00000000000..12cfb328e99
--- /dev/null
+++ b/boards/arm/stm32f1/stm32f103-minimum/src/stm32_max3421e.c
@@ -0,0 +1,407 @@
+/****************************************************************************
+ * boards/arm/stm32f1/stm32f103-minimum/src/stm32_max3421e.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 <syslog.h>
+#include <errno.h>
+
+#include <nuttx/debug.h>
+#include <nuttx/irq.h>
+#include <nuttx/kthread.h>
+#include <nuttx/signal.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/usb/usbhost.h>
+#include <nuttx/usb/max3421e.h>
+
+#include "stm32_gpio.h"
+#include "stm32_spi.h"
+
+#include "stm32f103_minimum.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MAX3421E_SPIBUS   1
+
+/* SPI command byte:  register number in bits 7-3, bit 1 = write */
+
+#define MAX3421E_DIR_WRITE 0x02
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_max3421elower_s
+{
+  /* Standard MAX3421E interface */
+
+  struct max3421e_lowerhalf_s config;
+
+  /* Extensions for the stm32f103-minimum board */
+
+  xcpt_t handler;
+  void *arg;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int max3421e_attach(const struct max3421e_lowerhalf_s *lower,
+                           xcpt_t isr, void *arg);
+static void max3421e_enable(const struct max3421e_lowerhalf_s *lower,
+                            bool enable);
+static void max3421e_acknowledge(const struct max3421e_lowerhalf_s *lower);
+static void max3421e_power(const struct max3421e_lowerhalf_s *lower,
+                           bool enable);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct stm32_max3421elower_s g_max3421e_lower =
+{
+  .config =
+  {
+    .spi         = NULL,
+    .frequency   = CONFIG_STM32F103MINIMUM_MAX3421E_FREQUENCY,
+    .mode        = SPIDEV_MODE0,
+    .devid       = 0,
+    .intconfig   = 0,                /* Push-pull, falling edge-sensitive */
+
+    .attach      = max3421e_attach,
+    .enable      = max3421e_enable,
+    .acknowledge = max3421e_acknowledge,
+    .power       = max3421e_power,
+  },
+};
+
+static struct usbhost_connection_s *g_usbconn;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int max3421e_attach(const struct max3421e_lowerhalf_s *lower,
+                           xcpt_t isr, void *arg)
+{
+  struct stm32_max3421elower_s *priv =
+    (struct stm32_max3421elower_s *)lower;
+
+  if (isr != NULL)
+    {
+      /* Save the handler; it is attached when the interrupt is enabled */
+
+      priv->handler = isr;
+      priv->arg     = arg;
+    }
+  else
+    {
+      max3421e_enable(lower, false);
+      priv->handler = NULL;
+      priv->arg     = NULL;
+    }
+
+  return OK;
+}
+
+static void max3421e_enable(const struct max3421e_lowerhalf_s *lower,
+                            bool enable)
+{
+  struct stm32_max3421elower_s *priv =
+    (struct stm32_max3421elower_s *)lower;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+  if (enable && priv->handler != NULL)
+    {
+      /* Interrupt on the falling edge of INT */
+
+      stm32_gpiosetevent(GPIO_MAX3421E_INT, false, true, true,
+                         priv->handler, priv->arg);
+
+      /* The EXTI is disabled while the driver processes an interrupt, so a
+       * falling edge in that window is lost and INT just stays low.  If INT
+       * is already asserted, dispatch the handler now.
+       */
+
+      if (!stm32_gpioread(GPIO_MAX3421E_INT))
+        {
+          priv->handler(0, NULL, priv->arg);
+        }
+    }
+  else
+    {
+      stm32_gpiosetevent(GPIO_MAX3421E_INT, false, false, false,
+                         NULL, NULL);
+    }
+
+  leave_critical_section(flags);
+}
+
+static void max3421e_acknowledge(const struct max3421e_lowerhalf_s *lower)
+{
+  /* Nothing to do:  the EXTI pending bit is cleared by the STM32 logic */
+}
+
+static void max3421e_power(const struct max3421e_lowerhalf_s *lower,
+                           bool enable)
+{
+  /* VBUS is wired directly to 5V; there is no power switch */
+}
+
+/****************************************************************************
+ * Name: max3421e_probe_xfer
+ *
+ * Description:
+ *   Perform one 2-byte register access and return the second byte read.
+ *
+ ****************************************************************************/
+
+static uint8_t max3421e_probe_xfer(struct spi_dev_s *spi, uint8_t cmd,
+                                   uint8_t data)
+{
+  uint8_t txbuf[2];
+  uint8_t rxbuf[2];
+
+  txbuf[0] = cmd;
+  txbuf[1] = data;
+
+  SPI_SELECT(spi, SPIDEV_USBHOST(0), true);
+  SPI_EXCHANGE(spi, txbuf, rxbuf, 2);
+  SPI_SELECT(spi, SPIDEV_USBHOST(0), false);
+
+  return rxbuf[1];
+}
+
+/****************************************************************************
+ * Name: max3421e_probe
+ *
+ * Description:
+ *   Check that the MAX3421E answers on the SPI bus before handing it to the
+ *   USB host driver (the driver waits forever for the oscillator if the
+ *   chip is missing).
+ *
+ ****************************************************************************/
+
+static int max3421e_probe(struct spi_dev_s *spi)
+{
+  uint8_t revision;
+  uint8_t usbirq;
+  uint8_t rdback1;
+  uint8_t rdback2;
+  int i;
+
+  SPI_LOCK(spi, true);
+  SPI_SETMODE(spi, SPIDEV_MODE0);
+  SPI_SETBITS(spi, 8);
+  SPI_SETFREQUENCY(spi, CONFIG_STM32F103MINIMUM_MAX3421E_FREQUENCY);
+
+  /* Switch to full-duplex SPI so that the chip drives MISO */
+
+  max3421e_probe_xfer(spi, MAX3421E_USBHOST_PINCTL | MAX3421E_DIR_WRITE,
+                      USBHOST_PINCTL_FDUPSPI);
+
+  /* Wait up to 100 ms for the 12MHz oscillator to be stable.  Register
+   * writes are clocked by the oscillator and are lost until it runs.
+   */
+
+  for (i = 0; i < 100; i++)
+    {
+      usbirq = max3421e_probe_xfer(spi, MAX3421E_USBHOST_USBIRQ, 0);
+      if ((usbirq & USBHOST_USBIRQ_OSCOKIRQ) != 0)
+        {
+          break;
+        }
+
+      nxsig_usleep(1000);
+    }
+
+  revision = max3421e_probe_xfer(spi, MAX3421E_USBHOST_REVISION, 0);
+
+  /* Write/read-back test using the GPINPOL register (it exists in both
+   * peripheral and host modes; the chip is in peripheral mode after reset)
+   */
+
+  max3421e_probe_xfer(spi, MAX3421E_USBHOST_GPINPOL | MAX3421E_DIR_WRITE,
+                      0x55);
+  rdback1 = max3421e_probe_xfer(spi, MAX3421E_USBHOST_GPINPOL, 0);
+  max3421e_probe_xfer(spi, MAX3421E_USBHOST_GPINPOL | MAX3421E_DIR_WRITE,
+                      0xaa);
+  rdback2 = max3421e_probe_xfer(spi, MAX3421E_USBHOST_GPINPOL, 0);
+  max3421e_probe_xfer(spi, MAX3421E_USBHOST_GPINPOL | MAX3421E_DIR_WRITE,
+                      0);
+
+  SPI_LOCK(spi, false);
+
+  syslog(LOG_INFO, "MAX3421E: REVISION=0x%02x GPINPOL rd=0x%02x/0x%02x "
+         "USBIRQ=0x%02x\n", revision, rdback1, rdback2, usbirq);
+
+  if (revision != USBHOST_REVISION)
+    {
+      syslog(LOG_ERR, "MAX3421E: not responding (bad revision)\n");
+      return -ENODEV;
+    }
+
+  if (rdback1 != 0x55 || rdback2 != 0xaa)
+    {
+      syslog(LOG_ERR, "MAX3421E: register read-back failed\n");
+      return -EIO;
+    }
+
+  if ((usbirq & USBHOST_USBIRQ_OSCOKIRQ) == 0)
+    {
+      syslog(LOG_ERR, "MAX3421E: oscillator not running\n");
+      return -ETIMEDOUT;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: usbhost_detect
+ *
+ * Description:
+ *   Wait for USB devices to be connected.
+ *
+ ****************************************************************************/
+
+static int usbhost_detect(int argc, char *argv[])
+{
+  struct usbhost_hubport_s *hport;
+
+  for (; ; )
+    {
+      CONN_WAIT(g_usbconn, &hport);
+
+      if (hport->connected)
+        {
+          CONN_ENUMERATE(g_usbconn, hport);
+        }
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32_max3421e_setup
+ *
+ * Description:
+ *   Initialize the MAX3421E USB host controller on SPI1 and start the
+ *   USB connection monitor thread.
+ *
+ ****************************************************************************/
+
+int stm32_max3421e_setup(void)
+{
+  struct spi_dev_s *spi;
+  int ret;
+
+  /* INT is an input, RES# starts low (chip held in reset) */
+
+  stm32_configgpio(GPIO_MAX3421E_INT);
+#ifdef CONFIG_STM32F103MINIMUM_MAX3421E_RST
+  stm32_configgpio(GPIO_MAX3421E_RST);
+#endif
+
+  spi = stm32_spibus_initialize(MAX3421E_SPIBUS);
+  if (spi == NULL)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize SPI%d\n",
+             MAX3421E_SPIBUS);
+      return -ENODEV;
+    }
+
+  /* Pulse reset and give the chip time to come out of it */
+
+  nxsig_usleep(10000);
+#ifdef CONFIG_STM32F103MINIMUM_MAX3421E_RST
+  stm32_gpiowrite(GPIO_MAX3421E_RST, true);
+#endif
+  nxsig_usleep(10000);
+
+  ret = max3421e_probe(spi);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+#ifdef CONFIG_USBHOST_MSC
+  ret = usbhost_msc_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to register MSC class: %d\n", ret);
+    }
+#endif
+
+#ifdef CONFIG_USBHOST_HIDKBD
+  ret = usbhost_kbdinit();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to register KBD class: %d\n", ret);
+    }
+#endif
+
+#ifdef CONFIG_USBHOST_HIDMOUSE
+  ret = usbhost_mouse_init();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to register mouse class: %d\n", ret);
+    }
+#endif
+
+  g_max3421e_lower.config.spi = spi;
+
+  g_usbconn = max3421e_usbhost_initialize(&g_max3421e_lower.config);
+  if (g_usbconn == NULL)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize MAX3421E USB host\n");
+      return -ENODEV;
+    }
+
+  ret = kthread_create("max3421e_conn",
+                       CONFIG_STM32F103MINIMUM_MAX3421E_CONNMON_PRIORITY,
+                       CONFIG_STM32F103MINIMUM_MAX3421E_CONNMON_STACKSIZE,
+                       usbhost_detect, NULL);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to start connection monitor: %d\n",
+             ret);
+      return ret;
+    }
+
+  syslog(LOG_INFO, "MAX3421E: USB host initialized\n");
+  return OK;
+}
diff --git a/boards/arm/stm32f1/stm32f103-minimum/src/stm32_spi.c 
b/boards/arm/stm32f1/stm32f103-minimum/src/stm32_spi.c
index 46f22b8038b..6c80f510cad 100644
--- a/boards/arm/stm32f1/stm32f103-minimum/src/stm32_spi.c
+++ b/boards/arm/stm32f1/stm32f103-minimum/src/stm32_spi.c
@@ -96,6 +96,10 @@ void stm32_spidev_initialize(void)
 #ifdef CONFIG_MMCSD_SPI
   stm32_configgpio(GPIO_SDCARD_CS);           /* SD/MMC Card chip select */
 #endif
+
+#ifdef CONFIG_USBHOST_MAX3421E
+  stm32_configgpio(GPIO_MAX3421E_CS);         /* MAX3421E chip select */
+#endif
 }
 
 /****************************************************************************
@@ -184,6 +188,13 @@ void stm32_spi1select(struct spi_dev_s *dev, uint32_t 
devid,
     }
 #endif
 
+#ifdef CONFIG_USBHOST_MAX3421E
+  if (devid == SPIDEV_USBHOST(0))
+    {
+      stm32_gpiowrite(GPIO_MAX3421E_CS, !selected);
+    }
+#endif
+
 #ifdef CONFIG_MTD_W25
   stm32_gpiowrite(FLASH_SPI1_CS, !selected);
 #endif
@@ -196,14 +207,14 @@ uint8_t stm32_spi1status(struct spi_dev_s *dev, uint32_t 
devid)
 #ifdef CONFIG_WL_NRF24L01
   if (devid == SPIDEV_WIRELESS(0))
     {
-       status |= SPI_STATUS_PRESENT;
+      status |= SPI_STATUS_PRESENT;
     }
 #endif
 
 #ifdef CONFIG_MMCSD_SPI
   if (devid == SPIDEV_MMCSD(0))
     {
-       status |= SPI_STATUS_PRESENT;
+      status |= SPI_STATUS_PRESENT;
     }
 #endif
 
diff --git a/boards/arm/stm32f1/stm32f103-minimum/src/stm32f103_minimum.h 
b/boards/arm/stm32f1/stm32f103-minimum/src/stm32f103_minimum.h
index 5270b996e1c..c77d4a61f60 100644
--- a/boards/arm/stm32f1/stm32f103-minimum/src/stm32f103_minimum.h
+++ b/boards/arm/stm32f1/stm32f103-minimum/src/stm32f103_minimum.h
@@ -167,6 +167,22 @@
 
 #define GPIO_MCP2515_IRQ (GPIO_INPUT|GPIO_CNF_INFLOAT|GPIO_PORTB|GPIO_PIN0)
 
+/* MAX3421E USB Host (SPI1):
+ *
+ *   SS   -> PA4 (shared SPI1 chip select)
+ *   INT  -> PB8 (falling edge, push-pull)
+ *   RES# -> PB9 (active low)
+ */
+
+#define GPIO_MAX3421E_CS  (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|\
+                           GPIO_OUTPUT_SET|GPIO_PORTA|GPIO_PIN4)
+
+#define GPIO_MAX3421E_INT (GPIO_INPUT|GPIO_CNF_INPULLUP|GPIO_MODE_INPUT|\
+                           GPIO_EXTI|GPIO_PORTB|GPIO_PIN8)
+
+#define GPIO_MAX3421E_RST (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|\
+                           GPIO_OUTPUT_CLEAR|GPIO_PORTB|GPIO_PIN9)
+
 /* USB Soft Connect Pullup: PC.13 */
 
 #define GPIO_USB_PULLUP   (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|\
@@ -333,6 +349,19 @@ void stm32_usbinitialize(void);
 int stm32_pwm_setup(void);
 #endif
 
+/****************************************************************************
+ * Name: stm32_max3421e_setup
+ *
+ * Description:
+ *   Initialize the MAX3421E USB host controller on SPI1 and start the
+ *   USB connection monitor thread.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_USBHOST_MAX3421E
+int stm32_max3421e_setup(void);
+#endif
+
 /****************************************************************************
  * Name: stm32_hyt271initialize
  *

Reply via email to