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

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


The following commit(s) were added to refs/heads/master by this push:
     new bf54a5ae50 driver/net/lan9250: Add LAN9250 driver(SPI and QSPI mode)
bf54a5ae50 is described below

commit bf54a5ae50d01b875d4d2a6ba2364282e2dcc4f3
Author: Dong Heng <[email protected]>
AuthorDate: Thu Oct 26 16:42:51 2023 +0800

    driver/net/lan9250: Add LAN9250 driver(SPI and QSPI mode)
---
 boards/xtensa/esp32s3/common/src/Make.defs         |    4 +
 boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c |  245 ++
 .../esp32s3-devkit/configs/eth_lan9250/defconfig   |   75 +
 .../xtensa/esp32s3/esp32s3-devkit/include/board.h  |   15 +
 .../esp32s3/esp32s3-devkit/src/esp32s3-devkit.h    |   21 +
 .../esp32s3/esp32s3-devkit/src/esp32s3_bringup.c   |    9 +
 drivers/net/CMakeLists.txt                         |    4 +
 drivers/net/Kconfig                                |   63 +
 drivers/net/Make.defs                              |    4 +
 drivers/net/lan9250.c                              | 2452 ++++++++++++++++++++
 drivers/net/lan9250.h                              |  628 +++++
 include/nuttx/net/lan9250.h                        |  125 +
 12 files changed, 3645 insertions(+)

diff --git a/boards/xtensa/esp32s3/common/src/Make.defs 
b/boards/xtensa/esp32s3/common/src/Make.defs
index 47196bf462..dbb2b82ca5 100644
--- a/boards/xtensa/esp32s3/common/src/Make.defs
+++ b/boards/xtensa/esp32s3/common/src/Make.defs
@@ -56,6 +56,10 @@ ifeq ($(CONFIG_ESP32S3_OTG),y)
   CSRCS += esp32s3_board_usb.c
 endif
 
+ifeq ($(CONFIG_NET_LAN9250),y)
+  CSRCS += esp32s3_lan9250.c
+endif
+
 DEPPATH += --dep-path src
 VPATH += :src
 CFLAGS += 
${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
diff --git a/boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c 
b/boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c
new file mode 100644
index 0000000000..8981a24b98
--- /dev/null
+++ b/boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c
@@ -0,0 +1,245 @@
+/****************************************************************************
+ * boards/xtensa/esp32s3/common/src/esp32s3_lan9250.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <debug.h>
+#include <errno.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/board.h>
+#include <nuttx/irq.h>
+#include <nuttx/net/lan9250.h>
+#include <arch/board/board.h>
+
+#include "xtensa.h"
+#include "esp32s3_gpio.h"
+#ifdef CONFIG_LAN9250_SPI
+#include "esp32s3_spi.h"
+#else
+#include "esp32s3_qspi.h"
+#endif
+#include "hardware/esp32s3_efuse.h"
+#include "hardware/esp32s3_gpio_sigmap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Function Protototypes
+ ****************************************************************************/
+
+static int lan9250_attach(const struct lan9250_lower_s *lower,
+                          xcpt_t handler, void *arg);
+static void lan9250_enable(const struct lan9250_lower_s *lower);
+static void lan9250_disable(const struct lan9250_lower_s *lower);
+static void lan9250_getmac(const struct lan9250_lower_s *lower,
+                           uint8_t *mac);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct lan9250_lower_s g_lan9250_lower =
+{
+  .attach  = lan9250_attach,
+  .enable  = lan9250_enable,
+  .disable = lan9250_disable,
+  .getmac  = lan9250_getmac
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_attach
+ *
+ * Description:
+ *   Attach LAN9250 interrupt.
+ *
+ * Input Parameters:
+ *   lower   - A reference to the LAN9250 low-level object data.
+ *   handler - Interrupt handle
+ *   arg     - Interrupt private argument
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_attach(const struct lan9250_lower_s *lower,
+                          xcpt_t handler, void *arg)
+{
+  int ret;
+  int irq = ESP32S3_PIN2IRQ(LAN9250_IRQ);
+
+  ret = irq_attach(irq, handler, arg);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: irq_attach() failed: %d\n", ret);
+      return ret;
+    }
+
+  ninfo("Attach the interrupt\n");
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: lan9250_enable
+ *
+ * Description:
+ *   Enable LAN9250 interrupt.
+ *
+ * Input Parameters:
+ *   lower - A reference to the LAN9250 low-level object data.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_enable(const struct lan9250_lower_s *lower)
+{
+  int irq = ESP32S3_PIN2IRQ(LAN9250_IRQ);
+
+  /* Configure the interrupt for rising and falling edges */
+
+  esp32s3_gpioirqenable(irq, GPIO_INTR_LOW_LEVEL);
+  ninfo("Enable the interrupt\n");
+}
+
+/****************************************************************************
+ * Name: lan9250_disable
+ *
+ * Description:
+ *   Disable LAN9250 interrupt.
+ *
+ * Input Parameters:
+ *   lower - A reference to the LAN9250 low-level object data.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_disable(const struct lan9250_lower_s *lower)
+{
+  int irq = ESP32S3_PIN2IRQ(LAN9250_IRQ);
+
+  ninfo("Disable the interrupt\n");
+  esp32s3_gpioirqdisable(irq);
+}
+
+/****************************************************************************
+ * Name: lan9250_getmac
+ *
+ * Description:
+ *   Retrieves the ESP32-S3 MAC address to be set in the LAN9250 driver.
+ *
+ * Input Parameters:
+ *   lower - A reference to the LAN9250 low-level object data.
+ *   mac   - A pointer to a buffer where the MAC address will be stored.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_getmac(const struct lan9250_lower_s *lower, uint8_t *mac)
+{
+  uint32_t regval[2];
+  uint8_t *data = (uint8_t *)regval;
+
+  regval[0] = getreg32(EFUSE_RD_MAC_SPI_SYS_0_REG);
+  regval[1] = getreg32(EFUSE_RD_MAC_SPI_SYS_1_REG);
+
+  for (int i = 0; i < 6; i++)
+    {
+      mac[i] = data[i];
+    }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp32s3_lan9250_initialize
+ *
+ * Description:
+ *   This function is called by platform-specific setup logic to initialize
+ *   the LAN9250 device. This function will register the driver
+ *   as a network device.
+ *
+ * Input Parameters:
+ *   port - The SPI port used for the device
+ *
+ * Returned Value:
+ *   Zero is returned on success. Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+int esp32s3_lan9250_initialize(int port)
+{
+  int ret;
+#ifdef CONFIG_LAN9250_SPI
+  struct spi_dev_s *dev;
+#else
+  struct qspi_dev_s *dev;
+#endif
+
+  esp32s3_configgpio(LAN9250_IRQ, INPUT_FUNCTION_2 | PULLUP);
+  esp32s3_configgpio(LAN9250_RST, OUTPUT_FUNCTION_2 | PULLUP);
+
+#ifdef CONFIG_LAN9250_SPI
+  dev = esp32s3_spibus_initialize(port);
+  if (!dev)
+    {
+      nerr("ERROR: Failed to initialize SPI port %d\n", port);
+      return -ENODEV;
+    }
+#else
+  dev = esp32s3_qspibus_initialize(port);
+  if (!dev)
+    {
+      nerr("ERROR: Failed to initialize QSPI port %d\n", port);
+      return -ENODEV;
+    }
+#endif
+
+  ret = lan9250_initialize(dev, &g_lan9250_lower);
+  if (ret != 0)
+    {
+      nerr("ERROR: Failed to initialize LAN9250 ret=%d\n", ret);
+      return ret;
+    }
+
+  return 0;
+}
+
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/configs/eth_lan9250/defconfig 
b/boards/xtensa/esp32s3/esp32s3-devkit/configs/eth_lan9250/defconfig
new file mode 100644
index 0000000000..798c4c7d4e
--- /dev/null
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/configs/eth_lan9250/defconfig
@@ -0,0 +1,75 @@
+#
+# 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_ARCH_LEDS is not set
+# CONFIG_ESP32S3_RTC is not set
+# CONFIG_NDEBUG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_SPI_EXCHANGE is not set
+CONFIG_ALLOW_BSD_COMPONENTS=y
+CONFIG_ARCH="xtensa"
+CONFIG_ARCH_BOARD="esp32s3-devkit"
+CONFIG_ARCH_BOARD_COMMON=y
+CONFIG_ARCH_BOARD_ESP32S3_DEVKIT=y
+CONFIG_ARCH_CHIP="esp32s3"
+CONFIG_ARCH_CHIP_ESP32S3=y
+CONFIG_ARCH_CHIP_ESP32S3WROOM1=y
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_XTENSA=y
+CONFIG_BOARD_LOOPSPERMSEC=16717
+CONFIG_BUILTIN=y
+CONFIG_DEFAULT_TASK_STACKSIZE=4096
+CONFIG_ESP32S3_GPIO_IRQ=y
+CONFIG_ESP32S3_SPI2=y
+CONFIG_ESP32S3_SPI_SWCS=y
+CONFIG_ESP32S3_UART0=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_INIT_STACKSIZE=8192
+CONFIG_INTELHEX_BINARY=y
+CONFIG_IOB_BUFSIZE=1514
+CONFIG_IOB_NBUFFERS=5
+CONFIG_LAN9250_FREQUENCY=40000000
+CONFIG_LAN9250_SPI_EXCLUSIVE=y
+CONFIG_NAME_MAX=48
+CONFIG_NET=y
+CONFIG_NETDB_DNSCLIENT=y
+CONFIG_NETDEV_LATEINIT=y
+CONFIG_NETUTILS_IPERF=y
+CONFIG_NET_ARP_SEND=y
+CONFIG_NET_ETH_PKTSIZE=1518
+CONFIG_NET_ICMP=y
+CONFIG_NET_ICMP_SOCKET=y
+CONFIG_NET_LAN9250=y
+CONFIG_NET_TCP=y
+CONFIG_NET_UDP=y
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_LINELEN=64
+CONFIG_NSH_READLINE=y
+CONFIG_POSIX_SPAWN_DEFAULT_STACKSIZE=2048
+CONFIG_PREALLOC_TIMERS=4
+CONFIG_PTHREAD_MUTEX_TYPES=y
+CONFIG_RAM_SIZE=114688
+CONFIG_RAM_START=0x20000000
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_SIG_DEFAULT=y
+CONFIG_START_DAY=6
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2011
+CONFIG_SYSLOG_BUFFER=y
+CONFIG_SYSTEM_DHCPC_RENEW=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_PING=y
+CONFIG_UART0_BAUD=2000000
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h 
b/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h
index 54e89c98f5..9c2690cece 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/include/board.h
@@ -49,4 +49,19 @@
 #define BOARD_NGPIOIN     1 /* Amount of GPIO Input without Interruption */
 #define BOARD_NGPIOINT    1 /* Amount of GPIO Input w/ Interruption pins */
 
+/* LAN9250 SPI and GPIO pins configuration */
+
+#ifdef CONFIG_NET_LAN9250
+
+#  define LAN9250_SPI     2 
+
+/* LAN9250 IRQ pin */
+
+#  define LAN9250_IRQ     38
+
+/* LAN9250 reset pin */
+
+#  define LAN9250_RST     17
+#endif
+
 #endif /* __BOARDS_XTENSA_ESP32S3_ESP32S3_DEVKIT_INCLUDE_BOARD_H */
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h 
b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h
index 62b9acfc5f..215a69468a 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3-devkit.h
@@ -210,5 +210,26 @@ int esp32s3_pwm_setup(void);
 int esp32s3_twai_setup(void);
 #endif
 
+/****************************************************************************
+ * Name: esp32s3_lan9250_initialize
+ *
+ * Description:
+ *   This function is called by platform-specific setup logic to initialize
+ *   the LAN9250 device. This function will register the driver
+ *   as a network device.
+ *
+ * Input Parameters:
+ *   port - The SPI port used for the device
+ *
+ * Returned Value:
+ *   Zero is returned on success. Otherwise, a negated errno value is
+ *   returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_LAN9250
+int esp32s3_lan9250_initialize(int port);
+#endif
+
 #endif /* __ASSEMBLY__ */
 #endif /* __BOARDS_XTENSA_ESP32S3_ESP32S3_DEVKIT_SRC_ESP32S3_DEVKIT_H */
diff --git a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c 
b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
index 23e8ed687f..51e8c8442c 100644
--- a/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
+++ b/boards/xtensa/esp32s3/esp32s3-devkit/src/esp32s3_bringup.c
@@ -38,6 +38,7 @@
 #include <errno.h>
 #include <nuttx/fs/fs.h>
 #include <nuttx/himem/himem.h>
+#include <arch/board/board.h>
 
 #ifdef CONFIG_ESP32S3_TIMER
 #  include "esp32s3_board_tim.h"
@@ -388,6 +389,14 @@ int esp32s3_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_NET_LAN9250
+  ret = esp32s3_lan9250_initialize(LAN9250_SPI);
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "ERROR: Failed to initialize SPI ethernet LAN9250.\n");
+    }
+#endif
+
   /* If we got here then perhaps not all initialization was successful, but
    * at least enough succeeded to bring-up NSH with perhaps reduced
    * capabilities.
diff --git a/drivers/net/CMakeLists.txt b/drivers/net/CMakeLists.txt
index f399251949..9d5492d249 100644
--- a/drivers/net/CMakeLists.txt
+++ b/drivers/net/CMakeLists.txt
@@ -75,6 +75,10 @@ if(CONFIG_NET)
     list(APPEND SRCS w5500.c)
   endif()
 
+  if(CONFIG_NET_LAN9250)
+    list(APPEND SRCS lan9250.c)
+  endif()
+
   if(CONFIG_ARCH_PHY_INTERRUPT)
     list(APPEND SRCS phy_notify.c)
   endif()
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d1f87797ab..c34bc9263a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -428,6 +428,69 @@ config NET_W5500_NINTERFACES
 
 endif # W5500
 
+menuconfig NET_LAN9250
+       bool "Microchip LAN9250 support"
+       default n
+       select SPI
+       select ARCH_HAVE_NETDEV_STATISTICS
+       ---help---
+               Enable LAN9250 SPI Ethernet driver.
+
+if NET_LAN9250
+
+choice LAN9250_INTERFACE
+       prompt "Select interface"
+       default LAN9250_SPI
+       ---help---
+               Select LAN9250 interface: SPI(4-line) or SQI(6-line).
+
+config LAN9250_SPI
+       bool "SPI"
+
+config LAN9250_SQI
+       bool "SQI"
+endchoice
+
+config LAN9250_SPI_EXCLUSIVE
+       bool "SPI Exclusive"
+       default n
+       ---help---
+               The SPI is exclusive for LAN9250.
+
+config LAN9250_SPIMODE
+       int "SPI mode"
+       default 0
+       ---help---
+               Controls the SPI mode.
+
+config LAN9250_FREQUENCY
+       int "SPI frequency"
+       default 10000000
+       ---help---
+               Define to use a different bus frequency.
+
+config LAN9250_HALFDUPPLEX
+       bool "Enable half duplex"
+       default n
+       ---help---
+               Default is full duplex.
+
+config LAN9250_DUMPPACKET
+       bool "Dump Packets"
+       default n
+       ---help---
+               If selected, the LAN9250 driver will dump the contents of each
+               packet to the console.
+
+config LAN9250_REGDEBUG
+       bool "Register-Level Debug"
+       default n
+       depends on DEBUG_FEATURES && DEBUG_NET
+       ---help---
+               Enable very low-level register access debug.
+
+endif # NET_LAN9250
+
 if ARCH_HAVE_PHY
 
 comment "External Ethernet PHY Device Support"
diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs
index 070df18e55..c1f65a214d 100644
--- a/drivers/net/Make.defs
+++ b/drivers/net/Make.defs
@@ -76,6 +76,10 @@ ifeq ($(CONFIG_NET_W5500),y)
   CSRCS += w5500.c
 endif
 
+ifeq ($(CONFIG_NET_LAN9250),y)
+  CSRCS += lan9250.c
+endif
+
 ifeq ($(CONFIG_ARCH_PHY_INTERRUPT),y)
   CSRCS += phy_notify.c
 endif
diff --git a/drivers/net/lan9250.c b/drivers/net/lan9250.c
new file mode 100644
index 0000000000..e2bba33954
--- /dev/null
+++ b/drivers/net/lan9250.c
@@ -0,0 +1,2452 @@
+/****************************************************************************
+ * drivers/net/lan9250.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <time.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/wdog.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/clock.h>
+#include <nuttx/net/net.h>
+#include <nuttx/net/ip.h>
+#include <nuttx/net/netdev.h>
+#include <nuttx/net/lan9250.h>
+
+#ifdef CONFIG_NET_PKT
+#  include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_LAN9250_SPI
+#  include <nuttx/spi/spi.h>
+#else
+#  include <nuttx/spi/qspi.h>
+#endif
+
+#include "lan9250.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* LAN9250 SPI clock */
+
+#define LAN9250_FREQUENCY           CONFIG_LAN9250_FREQUENCY
+
+/* LAN9250 read and write command */
+
+#ifdef CONFIG_LAN9250_SPI
+#  if LAN9250_FREQUENCY > (30 * 1000 * 1000)
+#    define LAN9250_SPI_READ        LAN9250_SPI_CMD_FREAD
+#  else
+#    define LAN9250_SPI_READ        LAN9250_SPI_CMD_READ
+#  endif
+
+#  define LAN9250_SPI_WRITE         LAN9250_SPI_CMD_WRITE
+#else
+#  define LAN9250_SPI_READ          LAN9250_QSPI_CMD_READ
+#  define LAN9250_SPI_WRITE         LAN9250_QSPI_CMD_WRITE
+
+#  define LAN9250_SPI_ENABLE_SQI    LAN9250_SPI_CMD_ENABLE_SQI
+#endif
+
+/**
+ * LAN9250 interrupt trigger source:
+ *
+ *   - PHY for checking link up or down
+ *   - TX data FIFO available
+ *   - RX data FIFO reaches programmed level
+ */
+
+#define LAN9250_INT_SOURCE          (IER_PHY | IER_TDFA | IER_RSFL)
+
+/* The low-priority work queue is preferred. If it is not enabled, LPWORK
+ * will be the same as HPWORK.
+ *
+ * NOTE: However, the network should NEVER run on the high priority work
+ * queue! That queue is intended only to service short back end interrupt
+ * processing that never suspends. Suspending the high priority work queue
+ * may bring the system to its knees!
+ */
+
+#define LAN9250_WORK                LPWORK
+
+/* Timing *******************************************************************/
+
+/* Reset timeout in second */
+
+#define LAN9250_RESET_TIMEOUT       (5)
+
+/* TX timeout = 1 minute */
+
+#define LAN9250_TX_TIMEOUT          (60 * CLK_TCK)
+
+/* Poll timeout */
+
+#define LAN9250_POLL_TIMEOUT        MSEC2TICK(50)
+
+/* Read/Write MAC register timeout in second */
+
+#define LAN9250_MAC_TIMEOUT         2
+
+/* Read/Write PHY register timeout in second */
+
+#define LAN9250_PHY_TIMEOUT         2
+
+/* Read/Write PHY register timeout in millisecond */
+
+#define LAN9250_SQI_TIMEOUT         20
+
+/* Packet Memory ************************************************************/
+
+/* Misc. Helper Macros ******************************************************/
+
+#define LAN9250_ALIGN(v)            (((v) + 3) & (~3))
+
+/* Packet buffer size with 4-CRC */
+
+#define LAN9250_PKTBUF_SIZE         LAN9250_ALIGN(MAX_NETDEV_PKTSIZE +   \
+                                                  CONFIG_NET_GUARDSIZE + \
+                                                  4)
+
+/* This is a helper pointer for accessing the contents of Ethernet header */
+
+#define BUF                         ((struct eth_hdr_s *)priv->dev.d_buf)
+
+/* Debug ********************************************************************/
+
+#ifdef CONFIG_LAN9250_REGDEBUG
+#  define lan9250_setreg_dump(a, v)    \
+   syslog(LOG_DEBUG, "LAN9250 REG: 0x%04x<-0x%08x\n", a, v)
+#  define lan9250_getreg_dump(a, v)    \
+   syslog(LOG_DEBUG, "LAN9250 REG: 0x%04x->0x%08x\n", a, v)
+#  define lan9250_setmacreg_dump(a, v) \
+   syslog(LOG_DEBUG, "LAN9250 MAC: 0x%02x<-0x%08x\n", a, v)
+#  define lan9250_getmacreg_dump(a, v) \
+   syslog(LOG_DEBUG, "LAN9250 MAC: 0x%02x->0x%08x\n", a, v)
+#  define lan9250_setphyreg_dump(a, v) \
+   syslog(LOG_DEBUG, "LAN9250 PHY: 0x%02x<-0x%08x\n", a, v)
+#  define lan9250_getphyreg_dump(a, v) \
+   syslog(LOG_DEBUG, "LAN9250 PHY: 0x%02x->0x%08x\n", a, v)
+#  define lan9250_buffer_dump(c, b, s) \
+   syslog(LOG_DEBUG, "LAN9250 BUF: cmd: %04x buffer: %p length: %d\n", c, b, s)
+#else
+#  define lan9250_setreg_dump(a, v)
+#  define lan9250_getreg_dump(a, v)
+#  define lan9250_setmacreg_dump(a, v)
+#  define lan9250_getmacreg_dump(a, v)
+#  define lan9250_setphyreg_dump(a, v)
+#  define lan9250_getphyreg_dump(a, v)
+#  define lan9250_buffer_dump(c, b, s)
+#endif
+
+/* CONFIG_LAN9250_DUMPPACKET will dump the contents of each packet. */
+
+#ifdef CONFIG_LAN9250_DUMPPACKET
+#  define lan9250_dump_buf(m, a, n) lib_dumpbuffer(m, a, n)
+#else
+#  define lan9250_dump_buf(m, a, n)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The lan9250_driver_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct lan9250_driver_s
+{
+  /* Low-level MCU-specific support */
+
+  const struct lan9250_lower_s *lower;
+
+  /* This is the contained (Q)SPI driver instance */
+
+#ifdef CONFIG_LAN9250_SPI
+  struct spi_dev_s    *spi;
+#else
+  bool                 sqi_mode;
+  struct qspi_dev_s   *qspi;
+#endif
+
+  bool                tx_available;   /* TX is available */
+
+  /* Read/Write buffer for SPI transmission */
+
+  uint32_t            pktbuf[LAN9250_PKTBUF_SIZE / 4];
+
+  struct wdog_s       txtout_timer;   /* TX timeout timer */
+  struct work_s       txtout_work;    /* Tx timeout work */
+  struct work_s       txpoll_work;    /* TX poll work */
+  struct work_s       irq_work;       /* Interrupt work */
+
+  /* This holds the information visible to the NuttX network */
+
+  struct net_driver_s dev;            /* Interface understood by the network */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Driver status structure */
+
+static struct lan9250_driver_s g_lan9250;
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Low-level SPI helpers */
+
+static inline void lan9250_config_spi(FAR struct lan9250_driver_s *priv);
+static void lan9250_lock_spi(FAR struct lan9250_driver_s *priv);
+static inline void lan9250_unlock_spi(FAR struct lan9250_driver_s *priv);
+
+/* SPI control register access */
+
+static uint32_t lan9250_get_reg(FAR struct lan9250_driver_s *priv,
+                                uint16_t address);
+static void lan9250_set_reg(FAR struct lan9250_driver_s *priv,
+                            uint16_t address, uint32_t data);
+static void lan9250_wait_ready(FAR struct lan9250_driver_s *priv,
+                               uint16_t address, uint32_t mask,
+                               uint32_t expected, uint32_t timeout);
+
+/* MAC register access */
+
+static uint32_t lan9250_get_macreg(FAR struct lan9250_driver_s *priv,
+                                   uint8_t address);
+static void lan9250_set_macreg(FAR struct lan9250_driver_s *priv,
+                               uint8_t address, uint32_t data);
+static void lan9250_wait_mac_ready(FAR struct lan9250_driver_s *priv,
+                                   uint8_t address, uint32_t mask,
+                                   uint32_t expected, uint32_t timeout);
+
+/* PHY register access */
+
+static uint16_t lan9250_get_phyreg(FAR struct lan9250_driver_s *priv,
+                                   uint8_t phyaddr);
+static void lan9250_set_phyreg(FAR struct lan9250_driver_s *priv,
+                               uint8_t phyaddr, uint16_t phydata);
+
+/* SPI buffer transfers */
+
+static void lan9250_recv_buffer(FAR struct lan9250_driver_s *priv,
+                                FAR uint8_t *buffer, size_t buflen);
+static inline void lan9250_send_buffer(FAR struct lan9250_driver_s *priv,
+                                       FAR const uint8_t *buffer,
+                                       size_t buflen);
+
+/* Misc handling */
+
+#ifdef CONFIG_LAN9250_SQI
+static void lan9250_enable_sqi(FAR struct lan9250_driver_s *priv);
+#endif
+static inline void lan9250_sw_reset(FAR struct lan9250_driver_s *priv);
+static void lan9250_set_txavailabe(FAR struct lan9250_driver_s *priv,
+                                   bool enable);
+static int lan9250_reset(FAR struct lan9250_driver_s *priv);
+static void lan9250_set_macaddr(FAR struct lan9250_driver_s *priv);
+
+/* Common TX logic */
+
+static int lan9250_transmit(FAR struct lan9250_driver_s *priv);
+static int lan9250_txpoll(FAR struct net_driver_s *dev);
+
+/* Interrupt handling */
+
+static void lan9250_netdev_rx(FAR struct lan9250_driver_s *priv);
+static void lan9250_phy_isr(FAR struct lan9250_driver_s *priv);
+static void lan9250_txavailable_isr(FAR struct lan9250_driver_s *priv);
+static void lan9250_rxdone_isr(FAR struct lan9250_driver_s *priv);
+static int  lan9250_interrupt(int irq, FAR void *context, FAR void *arg);
+
+/* Watchdog timer expirations */
+
+static void lan9250_txtout_timercb(wdparm_t arg);
+
+/* Driver worker */
+
+static void lan9250_txavail_work(FAR void *arg);
+static void lan9250_txtout_worker(FAR void *arg);
+static void lan9250_int_worker(FAR void *arg);
+
+/* NuttX callback functions */
+
+static int lan9250_ifup(FAR struct net_driver_s *dev);
+static int lan9250_ifdown(FAR struct net_driver_s *dev);
+static int lan9250_txavail(FAR struct net_driver_s *dev);
+#ifdef CONFIG_NET_MCASTGROUP
+static int lan9250_addmac(FAR struct net_driver_s *dev,
+                          FAR const uint8_t *mac);
+static int lan9250_rmmac(FAR struct net_driver_s *dev,
+                         FAR const uint8_t *mac);
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_config_spi
+ *
+ * Description:
+ *   Configure the SPI for use with the LAN9250
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_config_spi(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_LAN9250_SPI
+  FAR struct spi_dev_s *spi = priv->spi;
+
+  /* Configure SPI for the LAN9250. */
+
+  SPI_SETMODE(spi, CONFIG_LAN9250_SPIMODE);
+  SPI_SETBITS(spi, 8);
+  SPI_HWFEATURES(spi, 0);
+  SPI_SETFREQUENCY(spi, LAN9250_FREQUENCY);
+#else
+  FAR struct qspi_dev_s *qspi = priv->qspi;
+
+  /* Configure QSPI for the LAN9250. */
+
+  QSPI_SETMODE(qspi, CONFIG_LAN9250_SPIMODE);
+  QSPI_SETBITS(qspi, 8);
+  QSPI_HWFEATURES(qspi, 0);
+  QSPI_SETFREQUENCY(qspi, LAN9250_FREQUENCY);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_lock_spi
+ *
+ * Description:
+ *   Select the SPI, locking it and re-configuring it if necessary.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_lock_spi(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_LAN9250_SPI
+
+  /* Lock the SPI bus in case there are multiple devices or tasks competing
+   * for the SPI bus.
+   */
+
+  SPI_LOCK(priv->spi, true);
+#else
+
+  /* Lock the QSPI bus in case there are multiple devices or tasks competing
+   * for the QSPI bus.
+   */
+
+  QSPI_LOCK(priv->qspi, true);
+#endif
+
+  /* Now make sure that the (Q)SPI bus is configured for the LAN9250 (it
+   * might have gotten configured for a different device while unlocked)
+   */
+
+#ifndef CONFIG_LAN9250_SPI_EXCLUSIVE
+  lan9250_config_spi(priv);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_unlock_spi
+ *
+ * Description:
+ *   De-select the SPI
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_unlock_spi(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_LAN9250_SPI
+
+  /* Relinquish the lock on the bus. */
+
+  SPI_LOCK(priv->spi, false);
+#else
+
+  /* Relinquish the lock on the bus. */
+
+  QSPI_LOCK(priv->qspi, false);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_get_reg
+ *
+ * Description:
+ *   Read a global register value.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the driver state structure
+ *   address - Register address
+ *
+ * Returned Value:
+ *   The value read from the register.
+ *
+ ****************************************************************************/
+
+static uint32_t lan9250_get_reg(FAR struct lan9250_driver_s *priv,
+                                uint16_t address)
+{
+#ifdef CONFIG_LAN9250_SPI
+#  if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+  uint8_t cmd_buffer[4];
+#  else
+  uint8_t cmd_buffer[3];
+#  endif
+  uint32_t regval;
+
+  cmd_buffer[0] = LAN9250_SPI_READ;
+  cmd_buffer[1] = (uint8_t)(address >> 8);
+  cmd_buffer[2] = (uint8_t)(address >> 0);
+#  if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+  cmd_buffer[3] = 0xff; /* SPI read dummy */
+#  endif
+
+  /* Select LAN9250 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+  /* Send the read command and register address */
+
+  SPI_SNDBLOCK(priv->spi, cmd_buffer, sizeof(cmd_buffer));
+
+  /* Receive register value, total 4 bytes */
+
+  SPI_RECVBLOCK(priv->spi, &regval, 4);
+
+  /* De-select LAN9250 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+  struct qspi_cmdinfo_s cmdinfo;
+  uint32_t regval;
+  uint32_t buffer[2];
+  int ret;
+
+  cmdinfo.cmd     = LAN9250_SPI_READ;
+  cmdinfo.addr    = address;
+  cmdinfo.addrlen = sizeof(address);
+  cmdinfo.buffer  = buffer;
+  cmdinfo.buflen  = sizeof(buffer); /* 4 dummy bytes */
+  cmdinfo.flags   = QSPICMD_ADDRESS | QSPICMD_READDATA;
+  if (priv->sqi_mode)
+    {
+      cmdinfo.flags |= QSPICMD_IQUAD;
+    }
+
+  ret = QSPI_COMMAND(priv->qspi, &cmdinfo);
+  DEBUGASSERT(ret == 0);
+
+  regval = buffer[1];
+#endif
+
+  lan9250_getreg_dump(address, regval);
+  return regval;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_reg
+ *
+ * Description:
+ *   Write to a global register.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the driver state structure
+ *   address - Register address
+ *   data    - The data to send
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_reg(FAR struct lan9250_driver_s *priv,
+                            uint16_t address,
+                            uint32_t data)
+{
+#ifdef CONFIG_LAN9250_SPI
+  uint8_t cmd_buffer[3];
+
+  DEBUGASSERT(priv && priv->spi);
+
+  cmd_buffer[0] = LAN9250_SPI_WRITE;
+  cmd_buffer[1] = (uint8_t)(address >> 8);
+  cmd_buffer[2] = (uint8_t)(address >> 0);
+
+  /* Select LAN9250 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+  /* Send the read command and register address */
+
+  SPI_SNDBLOCK(priv->spi, cmd_buffer, sizeof(cmd_buffer));
+
+  /* Receive register value, total 4 bytes */
+
+  SPI_SNDBLOCK(priv->spi, &data, 4);
+
+  /* De-select LAN9250 chip. */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+  struct qspi_cmdinfo_s cmdinfo;
+  int ret;
+
+  cmdinfo.cmd     = LAN9250_SPI_WRITE;
+  cmdinfo.addr    = address;
+  cmdinfo.addrlen = sizeof(address);
+  cmdinfo.buffer  = &data;
+  cmdinfo.buflen  = sizeof(data);
+  cmdinfo.flags   = QSPICMD_ADDRESS | QSPICMD_WRITEDATA;
+  if (priv->sqi_mode)
+    {
+      cmdinfo.flags |= QSPICMD_IQUAD;
+    }
+
+  ret = QSPI_COMMAND(priv->qspi, &cmdinfo);
+  DEBUGASSERT(ret == 0);
+#endif
+
+  lan9250_setreg_dump(address, data);
+}
+
+/****************************************************************************
+ * Name: lan9250_wait_ready
+ *
+ * Description:
+ *   Wait until LAN9250 is ready.
+ *
+ * Input Parameters:
+ *   priv     - Reference to the driver state structure
+ *   address  - Register address
+ *   mask     - Register value mask
+ *   expected - Expected register value
+ *   second   - Wait timeout in second
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_wait_ready(FAR struct lan9250_driver_s *priv,
+                               uint16_t address, uint32_t mask,
+                               uint32_t expected, uint32_t second)
+{
+  clock_t tout_ticks = clock_systime_ticks() + SEC2TICK(second);
+  bool timeout = false;
+
+  while (1)
+    {
+      if ((lan9250_get_reg(priv, address) & mask) == expected)
+        {
+          break;
+        }
+      else if (clock_systime_ticks() > tout_ticks)
+        {
+          timeout = true;
+          break;
+        }
+    }
+
+  if (timeout)
+    {
+      nerr("ERROR: wait register:0x%02x, mask:0x%08x, expected:0x%08x\n",
+            address, mask, expected);
+    }
+}
+
+/****************************************************************************
+ * Name: lan9250_get_macreg
+ *
+ * Description:
+ *   Read a MAC register value.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the driver state structure
+ *   address - MAC register address
+ *
+ * Returned Value:
+ *   The value read from the MAC register.
+ *
+ ****************************************************************************/
+
+static uint32_t lan9250_get_macreg(FAR struct lan9250_driver_s *priv,
+                                   uint8_t address)
+{
+  uint32_t regval = address | HMCSRICR_CSRB | HMCSRICR_RNW;
+
+  /* Wait for MAC to be ready and send reading register command */
+
+  lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+                     LAN9250_MAC_TIMEOUT);
+  lan9250_set_reg(priv, LAN9250_HMCSRICR, regval);
+
+  /* Wait for MAC to be ready and read register value */
+
+  lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+                     LAN9250_MAC_TIMEOUT);
+  regval = lan9250_get_reg(priv, LAN9250_HMCSRIDR);
+
+  lan9250_getmacreg_dump(address, regval);
+  return regval;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_macreg
+ *
+ * Description:
+ *   Write to a MAC register.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *   cmd  - MAC register address
+ *   data - The data to send
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_macreg(FAR struct lan9250_driver_s *priv,
+                               uint8_t address, uint32_t data)
+{
+  uint32_t regval = address | HMCSRICR_CSRB;
+
+  lan9250_setmacreg_dump(address, data);
+
+  /* Wait for MAC to be ready and send writing register command and data */
+
+  lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+                     LAN9250_MAC_TIMEOUT);
+  lan9250_set_reg(priv, LAN9250_HMCSRIDR, data);
+  lan9250_set_reg(priv, LAN9250_HMCSRICR, regval);
+
+  /* Wait until writing MAC is done */
+
+  lan9250_wait_ready(priv, LAN9250_HMCSRICR, HMCSRICR_CSRB, 0,
+                     LAN9250_MAC_TIMEOUT);
+}
+
+/****************************************************************************
+ * Name: lan9250_wait_mac_ready
+ *
+ * Description:
+ *   Wait until LAN9250 MAC is ready
+ *
+ * Input Parameters:
+ *   priv     - Reference to the driver state structure
+ *   address  - MAC register address
+ *   mask     - MAC register value mask
+ *   expected - Expected MAC register value
+ *   timeout  - Wait timeout in second
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_wait_mac_ready(FAR struct lan9250_driver_s *priv,
+                                   uint8_t address, uint32_t mask,
+                                   uint32_t expected, uint32_t second)
+{
+  clock_t tout_ticks = clock_systime_ticks() + SEC2TICK(second);
+  bool timeout = false;
+
+  while (1)
+    {
+      if ((lan9250_get_macreg(priv, address) & mask) == expected)
+        {
+          break;
+        }
+      else if (clock_systime_ticks() > tout_ticks)
+        {
+          timeout = true;
+          break;
+        }
+    }
+
+  if (timeout)
+    {
+      nerr("ERROR: wait MAC register:0x%02x, mask:0x%08x, expected:0x%08x\n",
+            address, mask, expected);
+    }
+}
+
+/****************************************************************************
+ * Name: lan9250_get_phyreg
+ *
+ * Description:
+ *   Read 16-bits of PHY data.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the driver state structure
+ *   address - The PHY register address
+ *
+ * Returned Value:
+ *   16-bit value read from the PHY
+ *
+ ****************************************************************************/
+
+static uint16_t lan9250_get_phyreg(FAR struct lan9250_driver_s *priv,
+                                   uint8_t address)
+{
+  uint32_t regval = (1 << HMACMIIAR_PHYA_S) |
+                    (address << HMACMIIAR_MIIRX_S);
+
+  /* Wait PHY to be ready and send reading register command */
+
+  lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+                         LAN9250_PHY_TIMEOUT);
+  lan9250_set_macreg(priv, LAN9250_HMACMIIAR, regval);
+
+  /* Wait PHY to be ready and read register value */
+
+  lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+                         LAN9250_PHY_TIMEOUT);
+  regval = lan9250_get_macreg(priv, LAN9250_HMACMIIDR);
+
+  lan9250_getphyreg_dump(address, regval);
+
+  return regval;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_phyreg
+ *
+ * Description:
+ *   Write 16-bits of PHY data.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the driver state structure
+ *   address - The PHY register address
+ *   data    - 16-bit data to write to the PHY
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_phyreg(FAR struct lan9250_driver_s *priv,
+                               uint8_t address,
+                               uint16_t data)
+{
+  uint32_t regval = (1 << HMACMIIAR_PHYA_S) |
+                    (address << HMACMIIAR_MIIRX_S) |
+                    HMACMIIAR_MIIW;
+
+  DEBUGASSERT((address & (HMACMIIAR_MIIRX_M >> HMACMIIAR_MIIRX_S))
+              == address);
+
+  lan9250_setphyreg_dump(address, data);
+
+  /* Wait PHY to be ready and send writing register command and data */
+
+  lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+                         LAN9250_PHY_TIMEOUT);
+  lan9250_set_macreg(priv, LAN9250_HMACMIIDR, data);
+  lan9250_set_macreg(priv, LAN9250_HMACMIIAR, regval);
+
+  /* Wait PHY until writing is done */
+
+  lan9250_wait_mac_ready(priv, LAN9250_HMACMIIAR, HMACMIIAR_MIIB, 0,
+                         LAN9250_PHY_TIMEOUT);
+}
+
+/****************************************************************************
+ * Name: lan9250_recv_buffer
+ *
+ * Description:
+ *   Read a buffer of data.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the driver state structure
+ *   buffer  - A pointer to the buffer to read into
+ *   buflen  - The number of bytes to read
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_recv_buffer(FAR struct lan9250_driver_s *priv,
+                                FAR uint8_t *buffer,
+                                size_t buflen)
+{
+#ifdef CONFIG_LAN9250_SPI
+#  if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+  uint8_t cmd_buffer[4];
+#  else
+  uint8_t cmd_buffer[3];
+#  endif
+
+  DEBUGASSERT(priv && priv->spi);
+  DEBUGASSERT(buflen <= sizeof(priv->pktbuf));
+
+  /* Read dummy data */
+
+  lan9250_get_reg(priv, LAN9250_RXDFR);
+
+  /* Read valid buffer data */
+
+  cmd_buffer[0] = LAN9250_SPI_READ;
+  cmd_buffer[1] = (uint8_t)(LAN9250_RXDFR >> 8);
+  cmd_buffer[2] = (uint8_t)(LAN9250_RXDFR >> 0);
+#  if LAN9250_SPI_READ == LAN9250_SPI_CMD_FREAD
+  cmd_buffer[3] = 0xff; /* SPI read dummy */
+#  endif
+
+  /* Select LAN9250 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+  /* Send the read command and register address */
+
+  SPI_SNDBLOCK(priv->spi, cmd_buffer, sizeof(cmd_buffer));
+  SPI_RECVBLOCK(priv->spi, buffer, buflen);
+
+  /* De-select LAN9250 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+  struct qspi_meminfo_s meminfo;
+  int ret;
+
+  meminfo.cmd     = LAN9250_SPI_READ;
+  meminfo.addr    = LAN9250_RXDFR;
+  meminfo.addrlen = sizeof(uint16_t);
+  meminfo.buffer  = buffer;
+  meminfo.buflen  = buflen;
+  meminfo.dummies = 16; /* 8 SPI dummy clock and 4 dummy RX bytes  */
+  meminfo.flags   = QSPIMEM_READ;
+  if (priv->sqi_mode)
+    {
+      meminfo.flags |= QSPIMEM_IQUAD;
+    }
+
+  ret = QSPI_MEMORY(priv->qspi, &meminfo);
+  DEBUGASSERT(ret == 0);
+#endif /* CONFIG_LAN9250_SPI */
+
+  lan9250_buffer_dump(LAN9250_RXDFR, buffer, buflen);
+}
+
+/****************************************************************************
+ * Name: lan9250_send_buffer
+ *
+ * Description:
+ *   Write a buffer of data.
+ *
+ * Input Parameters:
+ *   priv    - Reference to the driver state structure
+ *   buffer  - A pointer to the buffer to write from
+ *   buflen  - The number of bytes to write
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_send_buffer(FAR struct lan9250_driver_s *priv,
+                                       FAR const uint8_t *buffer,
+                                       size_t buflen)
+{
+#ifdef CONFIG_LAN9250_SPI
+  uint8_t cmd_buffer[3];
+  uint32_t regval;
+#else
+  struct qspi_meminfo_s meminfo;
+  uint32_t regval;
+  int ret;
+#endif
+
+  lan9250_buffer_dump(LAN9250_TXDFR, buffer, buflen);
+
+  /**
+   * LAN9250 SPI write command A fields:
+   *
+   *   - TX packet length 4 bytes align
+   *   - First frame
+   *   - Last frame
+   */
+
+  regval = SPI_CMD_WRITE_A_4BA | SPI_CMD_WRITE_A_FS |
+           SPI_CMD_WRITE_A_LS  | buflen;
+  lan9250_set_reg(priv, LAN9250_TXDFR, regval);
+
+  /**
+   * LAN9250 SPI write command B fields:
+   *
+   *   - Packet TAG
+   */
+
+  regval = SPI_CMD_WRITE_B_PT | buflen;
+  lan9250_set_reg(priv, LAN9250_TXDFR, regval);
+
+#ifdef CONFIG_LAN9250_SPI
+
+  /* Read valid buffer data */
+
+  cmd_buffer[0] = LAN9250_SPI_WRITE;
+  cmd_buffer[1] = (uint8_t)(LAN9250_TXDFR >> 8);
+  cmd_buffer[2] = (uint8_t)(LAN9250_TXDFR >> 0);
+
+  /* Select LAN9250 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), true);
+
+  /* Send the read command and register address, total 3 bytes */
+
+  SPI_SNDBLOCK(priv->spi, cmd_buffer, 3);
+
+  /* Write data into FIFO with 4-byte align */
+
+  SPI_SNDBLOCK(priv->spi, buffer, LAN9250_ALIGN(buflen));
+
+  /* De-select LAN9250 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET(0), false);
+#else
+  meminfo.cmd     = LAN9250_SPI_WRITE;
+  meminfo.addr    = LAN9250_TXDFR;
+  meminfo.addrlen = sizeof(uint16_t);
+  meminfo.buffer  = (void *)buffer;
+  meminfo.buflen  = LAN9250_ALIGN(buflen);
+  meminfo.dummies = 0;
+  meminfo.flags   = QSPIMEM_WRITE;
+  if (priv->sqi_mode)
+    {
+      meminfo.flags |= QSPIMEM_IQUAD;
+    }
+
+  ret = QSPI_MEMORY(priv->qspi, &meminfo);
+  DEBUGASSERT(ret == 0);
+#endif /* CONFIG_LAN9250_SPI */
+}
+
+/****************************************************************************
+ * Name: lan9250_enable_sqi
+ *
+ * Description:
+ *   Send a command to LAN9250 to enable SQI mode.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_LAN9250_SQI
+static void lan9250_enable_sqi(FAR struct lan9250_driver_s *priv)
+{
+  clock_t tout_ticks = clock_systime_ticks() +
+      MSEC2TICK(LAN9250_SQI_TIMEOUT);
+  struct qspi_cmdinfo_s cmdinfo;
+  int ret;
+
+  cmdinfo.cmd     = LAN9250_SPI_ENABLE_SQI;
+  cmdinfo.addrlen = 0;
+  cmdinfo.buflen  = 0;
+  cmdinfo.flags   = 0;
+
+  ret = QSPI_COMMAND(priv->qspi, &cmdinfo);
+  DEBUGASSERT(ret == 0);
+
+  /* USE SQI mode interface */
+
+  priv->sqi_mode = true;
+
+  /* Check read register value in SQI mode */
+
+  while (1)
+    {
+      if ((lan9250_get_reg(priv, LAN9250_BOTR) & BOTR_MASK) == BOTR_VAL)
+        {
+          break;
+        }
+      else if (clock_systime_ticks() > tout_ticks)
+        {
+          /* Check timeout and continue to use SPI mode */
+
+          priv->sqi_mode = false;
+          break;
+        }
+    }
+}
+#endif
+
+/****************************************************************************
+ * Name: lan9250_sw_reset
+ *
+ * Description:
+ *   Send a command to reset LAN9250.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void lan9250_sw_reset(FAR struct lan9250_driver_s *priv)
+{
+  /* Wait until LAN9250 SPI bus is ready */
+
+  lan9250_wait_ready(priv, LAN9250_BOTR, BOTR_MASK,
+                     BOTR_VAL, LAN9250_RESET_TIMEOUT);
+
+  /**
+   * Send a command to reset:
+   *
+   *   - Digital controller
+   *   - HMAC
+   *   - PHY
+   */
+
+  lan9250_set_reg(priv, LAN9250_RSTCR, RSTCR_DR | RSTCR_PHYR | RSTCR_HMACR);
+
+  /* Wait some time for hardware ready */
+
+  lan9250_wait_ready(priv, LAN9250_HWCFGR, HWCFGR_READY,
+                     HWCFGR_READY, LAN9250_RESET_TIMEOUT);
+
+#ifdef CONFIG_LAN9250_SQI
+
+  /* Enable SQI mode */
+
+  lan9250_enable_sqi(priv);
+#endif
+}
+
+/****************************************************************************
+ * Name: lan9250_set_txavailabe
+ *
+ * Description:
+ *   Enable or disable TX data FIFO available interrupt.
+ *
+ * Input Parameters:
+ *   priv   - Reference to the driver state structure
+ *   enable - true: enable this interrupt, false: disable this interrupt
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_txavailabe(FAR struct lan9250_driver_s *priv,
+                                   bool enable)
+{
+  uint32_t regval;
+
+  if (enable)
+    {
+      /**
+       * Configure FIFO level interrupt:
+       *
+       *   - TX data available level: Ethernet maximum packet size, transform
+       *     this value to be block number with 64-byte align
+       *   - TX status level: 255, use maximum value so that this will not be
+       *     actually used by this driver
+       *   - RX status level: 0, so that RX interrupt can trigger once
+       *     receiving one packet
+       */
+
+      regval = (((LAN9250_PKTBUF_SIZE + 63) / 64) << FLIR_FITXDAL_S) |
+               FLIR_FITXSL_M;
+
+      /* Mark TX data FIFO is unavailable */
+
+      priv->tx_available = false;
+    }
+  else
+    {
+      /**
+       * Configure FIFO level interrupt:
+       *
+       *   - TX data available level: 255, so that no interrupt triggers
+       *   - TX status level: 255, use maximum value so that this will not be
+       *     actually used by this driver
+       *   - RX status level: 0, so that RX interrupt can trigger once
+       *     receiving one packet
+       */
+
+      regval = FLIR_FITXDAL_M | FLIR_FITXSL_M;
+
+      /* Mark TX data FIFO is available */
+
+      priv->tx_available = true;
+    }
+
+  lan9250_set_reg(priv, LAN9250_FLIR, regval);
+}
+
+/****************************************************************************
+ * Name: lan9250_reset
+ *
+ * Description:
+ *   Stop, reset, re-initialize, and restart the LAN9250.  This is done
+ *   initially, on ifup, and after a TX timeout.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_reset(FAR struct lan9250_driver_s *priv)
+{
+  uint32_t regval;
+
+  nwarn("WARNING: Reset\n");
+
+  /* Configure SPI for the LAN9250 */
+
+  lan9250_config_spi(priv);
+
+  /* reset the LAN9250 by sending command */
+
+  lan9250_sw_reset(priv);
+
+  /* Read LAN9250 hardware ID */
+
+  regval = lan9250_get_reg(priv, LAN9250_CIARR);
+  if ((regval & CIARR_CID_M) != CIARR_CID_V)
+    {
+      nerr("ERROR: Bad Rev ID: %08x\n", regval);
+      return -ENODEV;
+    }
+
+  ninfo("Rev ID: %08x\n", regval & CIARR_CREV_M);
+
+  /**
+   * Configure TX FIFO size mode to be 8:
+   *
+   *   - TX data FIFO size:   7680
+   *   - RX data FIFO size:   7680
+   *   - TX status FIFO size: 512
+   *   - RX status FIFO size: 512
+   */
+
+  regval = HWCFGR_MBO | (8 << HWCFGR_TXFS_S);
+  lan9250_set_reg(priv, LAN9250_HWCFGR,  regval);
+
+  /**
+   * Configure MAC automatic flow control:
+   *
+   *   - Automatic flow control high level: 110
+   *   - Automatic flow control low level: 55
+   *   - Backpressure duration: 4
+   *   - Flow control on any frame
+   */
+
+  regval = (110 << HMAFCCFGR_AFCHL_S) |
+           (55  << HMAFCCFGR_AFCLL_S) |
+           (4   << HMAFCCFGR_BPD_S) |
+           HMAFCCFGR_FCOAF;
+  lan9250_set_reg(priv, LAN9250_HMAFCCFGR, regval);
+
+  /**
+   * Configure host MAC flow control:
+   *
+   *   - Pause time: 15
+   *   - Flow control
+   */
+
+  regval = (0xf << HMACFCR_PT_S) | HMACFCR_FLE;
+  lan9250_set_macreg(priv, LAN9250_HMACFCR, regval);
+
+  /**
+   * Configure interrupt:
+   *
+   *   - Interrupt De-assertion interval: 10
+   *   - Interrupt output to pin
+   *   - Interrupt pin active output low
+   *   - Interrupt pin push-pull driver
+   */
+
+  regval = (10 << ICFGR_IDAI_S) |
+           ICFGR_IRQE | ICFGR_IRQBT;
+  lan9250_set_reg(priv, LAN9250_ICFGR, regval);
+
+  /**
+   * Configure interrupt trigger source, please refer to macro
+   * LAN9250_INT_SOURCE.
+   */
+
+  lan9250_set_reg(priv, LAN9250_IER, LAN9250_INT_SOURCE);
+
+  /* Disable TX data FIFO available interrupt */
+
+  lan9250_set_txavailabe(priv, false);
+
+  /**
+   * Configure RX:
+   *
+   *   - RX DMA counter: Ethernet maximum packet size
+   *   - RX data offset: 4, so that need read dummy before reading data
+   */
+
+  regval = (LAN9250_PKTBUF_SIZE << RXCFGR_RXDMAC_S) | (4 << RXCFGR_RXDO_S);
+  lan9250_set_reg(priv, LAN9250_RXCFGR, regval);
+
+  /**
+   * Configure remote power management:
+   *
+   *   - Auto wakeup
+   *   - Disable 1588 clock
+   *   - Disable 1588 timestamp unit clock
+   *   - Energy-detect
+   *   - Wake on
+   *   - PME pin push-pull driver
+   *   - Clear wakeon
+   *   - PME active high
+   *   - PME pin
+   */
+
+  regval = PMCR_PMWU | PMCR_1588CLKD | PMCR_1588TSUCLKD |
+           PMCR_EDE  | PMCR_WOE      | PMCR_PMEBT       |
+           PMCR_WOLS | PMCR_PMEP     | PMCR_PMEE;
+  lan9250_set_reg(priv, LAN9250_PMCR, regval);
+
+  /**
+   * Configure PHY basic control:
+   *
+   *   - Auto-Negotiation for speed(10 or 100Mbsp) and direction
+   *     (half or full duplex)
+   */
+
+  lan9250_set_phyreg(priv, LAN9250_PHYBCR, PHYBCR_ANE);
+
+  /**
+   * Configure PHY auto-negotiation advertisement capability:
+   *
+   *   - Asymmetric pause
+   *   - Symmetric pause
+   *   - 100Base-X full deplex if !CONFIG_LAN9250_HALFDUPPLEX
+   *   - 100Base-X half deplex
+   *   - 10Base-X full deplex if !CONFIG_LAN9250_HALFDUPPLEX
+   *   - 10Base-X half deplex
+   *   - Select IEEE802.3
+   */
+
+  regval  = PHYANAR_AP     | PHYANAR_SP | PHYANAR_100BXHD |
+            PHYANAR_10BXHD | PHYANAR_SF;
+#ifndef CONFIG_LAN9250_HALFDUPPLEX
+  regval |= PHYANAR_100BXFD | PHYANAR_10BXFD;
+#endif
+  lan9250_set_phyreg(priv, LAN9250_PHYANAR, regval);
+
+  /**
+   * Configure PHY special mode:
+   *
+   *   - PHY mode = 111b, enable all capable and auto-nagotiation
+   *   - PHY address = 1, default value is fixed to 1 by manufacturer
+   */
+
+  regval = PHYSMR_PM_M | 1;
+  lan9250_set_phyreg(priv, LAN9250_PHYSMR, regval);
+
+  /**
+   * Configure PHY special control or status indication:
+   *
+   *   - Port auto-MDIX determined by bits 14 and 13
+   *   - Auto-MDIX
+   *   - Disable SQE tests
+   */
+
+  regval = PHYSCOSIR_AMDIXC | PHYSCOSIR_AMDIXE | PHYSCOSIR_SQETD;
+  lan9250_set_phyreg(priv, LAN9250_PHYSCOSIR, regval);
+
+  /**
+   * Configure PHY interrupt source:
+   *
+   *   - Link up
+   *   - Link down
+   */
+
+  regval = PHYIER_LU | PHYIER_LD;
+  lan9250_set_phyreg(priv, LAN9250_PHYIER, regval);
+
+  /**
+   * Configure special control or status:
+   *
+   *   - Fixed to write 0000010b to reserved filed
+   */
+
+  lan9250_set_phyreg(priv, LAN9250_PHYSCOSR, PHYSCOSR_RD);
+
+  /* Clear interrupt status */
+
+  lan9250_set_reg(priv, LAN9250_ISR, UINT32_MAX);
+
+  /**
+   * Configure HMAC control:
+   *
+   *   - Automaticaly strip the pad field on incoming packets
+   *   - TX enable
+   *   - RX enable
+   *   - Full duplex mode if !CONFIG_LAN9250_HALFDUPPLEX
+   */
+
+  regval  = HMACCR_APS | HMACCR_TXE | HMACCR_RXE;
+#ifndef CONFIG_LAN9250_HALFDUPPLEX
+  regval |= HMACCR_FDM;
+#endif
+  lan9250_set_macreg(priv, LAN9250_HMACCR, regval);
+
+  /** Configure TX:
+   *
+   *   - TX enable
+   */
+
+  lan9250_set_reg(priv, LAN9250_TXCFGR, TXCFGR_TXE);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_set_macaddr
+ *
+ * Description:
+ *   Set the MAC address to the configured value.  This is done after ifup
+ *   or after a TX timeout.  Note that this means that the interface must
+ *   be down before configuring the MAC addr.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_set_macaddr(FAR struct lan9250_driver_s *priv)
+{
+  uint32_t high_addr;
+  uint32_t low_addr;
+  FAR uint8_t *mac = priv->dev.d_mac.ether.ether_addr_octet;
+
+  high_addr = (((uint32_t)mac[5] <<  8) | ((uint32_t)mac[4] <<  0));
+  low_addr  = (((uint32_t)mac[3] << 24) | ((uint32_t)mac[2] << 16) |
+               ((uint32_t)mac[1] <<  8) | ((uint32_t)mac[0] <<  0));
+
+  lan9250_set_macreg(priv, LAN9250_HMACAHR, high_addr);
+  lan9250_set_macreg(priv, LAN9250_HMACALR, low_addr);
+}
+
+/****************************************************************************
+ * Name: lan9250_transmit
+ *
+ * Description:
+ *   Start hardware transmission. Called either from:
+ *
+ *   -  pkif interrupt when an application responds to the receipt of data
+ *      by trying to send something, or
+ *   -  From watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int lan9250_transmit(FAR struct lan9250_driver_s *priv)
+{
+  uint32_t regval;
+  uint16_t free_size;
+  uint8_t status_size;
+
+  regval = lan9250_get_reg(priv, LAN9250_TXFIR);
+  status_size = (regval & TXFIR_TXSFUS_M) >> TXFIR_TXSFUS_S;
+  free_size = regval & TXFIR_TXDFFS_M;
+
+  ninfo("availabe status size:%d, free space size:%d\n",
+        status_size, free_size);
+
+  /* Clear TX status FIFO if it is no empty by reading data */
+
+  for (int i = 0; i < status_size; i++)
+    {
+       lan9250_get_reg(priv, LAN9250_TXSFR);
+    }
+
+  if (free_size > priv->dev.d_len)
+    {
+      /* Increment statistics */
+
+      ninfo("Sending packet, pktlen: %d\n", priv->dev.d_len);
+      NETDEV_TXPACKETS(&priv->dev);
+
+      /* Send the packet: address=priv->dev.d_buf, length=priv->dev.d_len */
+
+      lan9250_dump_buf("Transmit Packet", priv->dev.d_buf,
+                       priv->dev.d_len);
+
+      lan9250_send_buffer(priv, priv->dev.d_buf, priv->dev.d_len);
+
+      if ((free_size - priv->dev.d_len) < LAN9250_PKTBUF_SIZE)
+        {
+          /* Enable TX data FIFO available interrupt */
+
+          lan9250_set_txavailabe(priv, true);
+
+          /**
+           * Enable the TX timeout watchdog (perhaps restarting the timer)
+           * when free data space is not enough.
+           */
+
+          wd_start(&priv->txtout_timer, LAN9250_TX_TIMEOUT,
+                  lan9250_txtout_timercb, (wdparm_t)priv);
+        }
+    }
+  else
+    {
+      /* This condition is not supported. */
+
+      DEBUGASSERT(0);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send timesout and the interface is
+ *      reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static int lan9250_txpoll(FAR struct net_driver_s *dev)
+{
+  FAR struct lan9250_driver_s *priv =
+        (FAR struct lan9250_driver_s *)dev->d_private;
+
+  /* Send the packet */
+
+  lan9250_transmit(priv);
+
+  /* Stop the poll now if free FIFO buffer is not enough */
+
+  return priv->tx_available ? OK : -EBUSY;
+}
+
+/****************************************************************************
+ * Name: lan9250_txavail_work
+ *
+ * Description:
+ *   Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ *   dev - The reference to the driver structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_txavail_work(FAR void *arg)
+{
+  FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+  FAR struct net_driver_s *dev = &priv->dev;
+
+  /* Lock the network and serialize driver operations if necessary.
+   * NOTE: Serialization is only required in the case where the driver work
+   * is performed on an LP worker thread and where more than one LP worker
+   * thread has been configured.
+   */
+
+  net_lock();
+  lan9250_lock_spi(priv);
+
+  /* Ignore the notification if the interface is not yet up */
+
+  if (IFF_IS_UP(dev->d_flags))
+    {
+      /* Check if there is room in the hardware to hold another outgoing
+       * packet.
+       */
+
+      /* If so, then poll the network for new XMIT data */
+
+      devif_poll(dev, lan9250_txpoll);
+    }
+
+  /* Release lock on the SPI bus and the network */
+
+  lan9250_unlock_spi(priv);
+  net_unlock();
+}
+
+/****************************************************************************
+ * Name: lan9250_phy_isr
+ *
+ * Description:
+ *   Process LAN9250 PHY interrupt.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_phy_isr(FAR struct lan9250_driver_s *priv)
+{
+  uint16_t regval;
+
+  regval = lan9250_get_phyreg(priv, LAN9250_PHYISFR);
+  if (regval & PHYISFR_LU)
+    {
+      ninfo("Link up\n");
+
+      IFF_SET_UP(priv->dev.d_flags);
+    }
+  else if (regval & PHYISFR_LD)
+    {
+      ninfo("Link down\n");
+
+      IFF_CLR_UP(priv->dev.d_flags);
+    }
+}
+
+/****************************************************************************
+ * Name: lan9250_txavailable_isr
+ *
+ * Description:
+ *   TX data FIFO available interrupt function.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_txavailable_isr(FAR struct lan9250_driver_s *priv)
+{
+  /* Update statistics */
+
+  NETDEV_TXDONE(&priv->dev);
+
+  /* Disable TX data FIFO available interrupt */
+
+  lan9250_set_txavailabe(priv, false);
+
+  /* If no further xmits are pending, then cancel the TX timeout */
+
+  wd_cancel(&priv->txtout_timer);
+
+  /* Then poll the network for new XMIT data */
+
+  devif_poll(&priv->dev, lan9250_txpoll);
+}
+
+/****************************************************************************
+ * Name: lan9250_netdev_rx
+ *
+ * Description:
+ *   Give the newly received packet to the network.
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_netdev_rx(FAR struct lan9250_driver_s *priv)
+{
+#ifdef CONFIG_NET_PKT
+  /* When packet sockets are enabled, feed the frame into the tap */
+
+  pkt_input(&priv->dev);
+#endif
+
+  /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+  if (BUF->type == HTONS(ETHTYPE_IP))
+    {
+      ninfo("IPv4 frame\n");
+      NETDEV_RXIPV4(&priv->dev);
+
+      /* Receive an IPv4 packet from the network device */
+
+      ipv4_input(&priv->dev);
+
+      /* If the above function invocation resulted in data that should be
+       * sent out on the network, d_len field will set to a value > 0.
+       */
+
+      if (priv->dev.d_len > 0)
+        {
+          /* And send the packet */
+
+          lan9250_transmit(priv);
+        }
+    }
+  else
+#endif /* CONFIG_NET_IPv4 */
+#ifdef CONFIG_NET_IPv6
+  if (BUF->type == HTONS(ETHTYPE_IP6))
+    {
+      ninfo("IPv6 frame\n");
+      NETDEV_RXIPV6(&priv->dev);
+
+      /* Give the IPv6 packet to the network layer */
+
+      ipv6_input(&priv->dev);
+
+      /* If the above function invocation resulted in data that should be
+       * sent out on the network, d_len field will set to a value > 0.
+       */
+
+      if (priv->dev.d_len > 0)
+        {
+          /* And send the packet */
+
+          lan9250_transmit(priv);
+        }
+    }
+  else
+#endif /* CONFIG_NET_IPv6 */
+#ifdef CONFIG_NET_ARP
+  if (BUF->type == HTONS(ETHTYPE_ARP))
+    {
+      ninfo("ARP packet received (%02x)\n", BUF->type);
+      NETDEV_RXARP(&priv->dev);
+
+      arp_input(&priv->dev);
+
+      /* If the above function invocation resulted in data that should be
+       * sent out on the network, d_len field will set to a value > 0.
+       */
+
+      if (priv->dev.d_len > 0)
+        {
+          lan9250_transmit(priv);
+        }
+    }
+  else
+#endif /* CONFIG_NET_ARP */
+    {
+      nwarn("WARNING: Unsupported packet type dropped (%02x)\n",
+            HTONS(BUF->type));
+      NETDEV_RXDROPPED(&priv->dev);
+    }
+}
+
+/****************************************************************************
+ * Name: lan9250_rxdone_isr
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_rxdone_isr(FAR struct lan9250_driver_s *priv)
+{
+  uint8_t pktcnt;
+  uint16_t pktlen;
+  uint32_t regval;
+
+  /* Update statistics */
+
+  NETDEV_RXPACKETS(&priv->dev);
+
+  /* Check valiad packet count */
+
+  regval = lan9250_get_reg(priv, LAN9250_RXFIR);
+  pktcnt = (regval & RXFIR_RXSFUS_M) >> RXFIR_RXSFUS_S;
+
+  ninfo("pktcnt:%d\n", pktcnt);
+
+  while (pktcnt--)
+    {
+      /* Check valiad packet data size */
+
+      regval = lan9250_get_reg(priv, LAN9250_RXSFR);
+      pktlen = (regval & RXSFF_PL_M) >> RXSFF_PL_S;
+
+      ninfo("pktlen:%d\n", pktlen);
+
+      if (pktlen)
+        {
+          /**
+           * Copy the data from the receive buffer to priv->dev.d_buf.
+           * ERDPT should be correctly positioned from the last call to
+           * end_rdbuffer (above).
+           */
+
+          lan9250_recv_buffer(priv, priv->dev.d_buf, pktlen);
+
+          /**
+           * Save the packet length (without the 4 byte CRC)
+           * in priv->dev.d_len.
+           */
+
+          priv->dev.d_len = pktlen - 4;
+
+          lan9250_dump_buf("Received Packet", priv->dev.d_buf,
+                           priv->dev.d_len);
+
+          /* Dispatch the packet to the network */
+
+          lan9250_netdev_rx(priv);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: lan9250_int_worker
+ *
+ * Description:
+ *   Perform interrupt handling logic outside of the interrupt handler (on
+ *   the work queue thread).
+ *
+ * Input Parameters:
+ *   arg - The reference to the driver structure (case to void*)
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_int_worker(FAR void *arg)
+{
+  FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+  uint32_t regval;
+
+  DEBUGASSERT(priv);
+
+  /* Get exclusive access to both the network and the SPI bus. */
+
+  net_lock();
+  lan9250_lock_spi(priv);
+
+  /**
+   * There is no infinite loop check... if there are always pending
+   * interrupts, we are just broken.
+   */
+
+  regval = lan9250_get_reg(priv, LAN9250_ISR);
+  if ((regval & LAN9250_INT_SOURCE) != 0)
+    {
+      /* Handle interrupts according to interrupt resource bit
+       * settings.
+       */
+
+      ninfo("Interrupt status: %08x\n", regval);
+
+#if LAN9250_INT_SOURCE & IER_SW
+      if ((regval & ISR_SW) != 0)
+        {
+          ninfo("\tSoftware\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RAEDY
+      if ((regval & ISR_READY) != 0)
+        {
+          ninfo("\tDevice ready\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_1588
+      if ((regval & ISR_1588) != 0)
+        {
+          ninfo("\t1588\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_PHY
+      if ((regval & ISR_PHY) != 0)
+        {
+          ninfo("\tPHY\n");
+
+          lan9250_phy_isr(priv);
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXSTOP
+      if ((regval & ISR_TXS) != 0)
+        {
+          ninfo("\tTX stop\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXSTOP
+      if ((regval & ISR_RXS) != 0)
+        {
+          ninfo("\tRX stop\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXDFH
+      if ((regval & ISR_RXDFH) != 0)
+        {
+          ninfo("\tRX dropped frame count halfway\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXIOC
+      if ((regval & ISR_TXIOC) != 0)
+        {
+          ninfo("\tTX IOC\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXD
+      if ((regval & ISR_RXD) != 0)
+        {
+          ninfo("\tRX DMA\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_GPT
+      if ((regval & ISR_GPT) != 0)
+        {
+          ninfo("\tGP-timer\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_PME
+      if ((regval & ISR_PME) != 0)
+        {
+          ninfo("\tPower management\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXSO
+      if ((regval & ISR_TXSO) != 0)
+        {
+          ninfo("\tTX FIFO status overflow\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RWT
+      if ((regval & ISR_RWT) != 0)
+        {
+          ninfo("\tRX watchdog timeout\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXE
+      if ((regval & ISR_RXE) != 0)
+        {
+          ninfo("\tRX error\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TXE
+      if ((regval & ISR_TXE) != 0)
+        {
+          ninfo("\tTX error\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_GPIO
+      if ((regval & ISR_GPIO) != 0)
+        {
+          ninfo("\tISR_GPIO event\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TDFO
+      if ((regval & ISR_TDFO) != 0)
+        {
+          ninfo("\tTX data FIFO overrun\n");
+        }
+#endif
+
+      if ((regval & ISR_TDFA) != 0)
+        {
+          ninfo("\tTX data FIFO available\n");
+
+          lan9250_txavailable_isr(priv);
+        }
+
+#if LAN9250_INT_SOURCE & IER_TSFF
+      if ((regval & ISR_TSFF) != 0)
+        {
+          ninfo("\tTX status FIFO full\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_TSFL
+      if ((regval & ISR_TSFL) != 0)
+        {
+          ninfo("\tTX status FIFO level\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RXDF
+      if ((regval & ISR_RXDF) != 0)
+        {
+          ninfo("\tRX dropped frame\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RSFF
+      if ((regval & ISR_RSFF) != 0)
+        {
+          ninfo("\tRX status FIFO full\n");
+        }
+#endif
+
+#if LAN9250_INT_SOURCE & IER_RSFL
+      if ((regval & ISR_RSFL) != 0)
+        {
+          ninfo("\tRX status FIFO level\n");
+
+          lan9250_rxdone_isr(priv);
+        }
+#endif
+
+      lan9250_set_reg(priv, LAN9250_ISR, regval);
+    }
+
+  /* Release lock on the SPI bus and the network */
+
+  lan9250_unlock_spi(priv);
+  net_unlock();
+
+  /**
+   * Enable ISR_GPIO interrupts after unlocking net so that application
+   * could have chance to process Ethernet packet and free iob.
+   */
+
+  priv->lower->enable(priv->lower);
+}
+
+/****************************************************************************
+ * Name: lan9250_interrupt
+ *
+ * Description:
+ *   Hardware interrupt handler
+ *
+ * Input Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info (architecture-specific)
+ *   arg     - Interrupt private data
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ ****************************************************************************/
+
+static int lan9250_interrupt(int irq, FAR void *context, FAR void *arg)
+{
+  FAR struct lan9250_driver_s *priv;
+
+  DEBUGASSERT(arg != NULL);
+  priv = (FAR struct lan9250_driver_s *)arg;
+
+  /* In complex environments, we cannot do SPI transfers from the interrupt
+   * handler because semaphores are probably used to lock the SPI bus.  In
+   * this case, we will defer processing to the worker thread.  This is also
+   * much kinder in the use of system resources and is, therefore, probably
+   * a good thing to do in any event.
+   */
+
+  DEBUGASSERT(work_available(&priv->irq_work));
+
+  /* Notice that further ISR_GPIO interrupts are disabled until the work is
+   * actually performed.  This is to prevent overrun of the worker thread.
+   * Interrupts are re-enabled in lan9250_int_worker() when the work is done.
+   */
+
+  priv->lower->disable(priv->lower);
+  return work_queue(LAN9250_WORK, &priv->irq_work, lan9250_int_worker,
+                    (void *)priv, 0);
+}
+
+/****************************************************************************
+ * Name: lan9250_txtout_worker
+ *
+ * Description:
+ *   Our TX watchdog timed out.  This is the worker thread continuation of
+ *   the watchdog timer interrupt.  Reset the hardware and start again.
+ *
+ * Input Parameters:
+ *   arg     - The reference to the driver structure (case to void*)
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_txtout_worker(FAR void *arg)
+{
+  FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+  int ret;
+
+  nerr("ERROR: Tx timeout\n");
+  DEBUGASSERT(priv);
+
+  /* Get exclusive access to the network */
+
+  net_lock();
+
+  /* Increment statistics and dump debug info */
+
+  NETDEV_TXTIMEOUTS(&priv->dev);
+
+  /* Then reset the hardware: Take the interface down, then bring it
+   * back up
+   */
+
+  ret = lan9250_ifdown(&priv->dev);
+  DEBUGASSERT(ret == OK);
+  ret = lan9250_ifup(&priv->dev);
+  DEBUGASSERT(ret == OK);
+  UNUSED(ret);
+
+  /* Then poll the network for new XMIT data */
+
+  devif_poll(&priv->dev, lan9250_txpoll);
+
+  /* Release lock on the network */
+
+  net_unlock();
+}
+
+/****************************************************************************
+ * Name: lan9250_txtout_timercb
+ *
+ * Description:
+ *   Our TX watchdog timed out.  Called from the timer interrupt handler.
+ *   The last TX never completed.  Perform work on the worker thread.
+ *
+ * Input Parameters:
+ *   arg  - The argument
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void lan9250_txtout_timercb(wdparm_t arg)
+{
+  FAR struct lan9250_driver_s *priv = (FAR struct lan9250_driver_s *)arg;
+  int ret;
+
+  /* In complex environments, we cannot do SPI transfers from the timeout
+   * handler because semaphores are probably used to lock the SPI bus.  In
+   * this case, we will defer processing to the worker thread.  This is also
+   * much kinder in the use of system resources and is, therefore, probably
+   * a good thing to do in any event.
+   */
+
+  DEBUGASSERT(priv && work_available(&priv->txtout_work));
+
+  /* Notice that Tx timeout watchdog is not active so further Tx timeouts
+   * can occur until we restart the Tx timeout watchdog.
+   */
+
+  ret = work_queue(LAN9250_WORK, &priv->txtout_work,
+                   lan9250_txtout_worker, priv, 0);
+  DEBUGASSERT(ret == OK);
+  UNUSED(ret);
+}
+
+/****************************************************************************
+ * Name: lan9250_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the Ethernet interface when an IP address is
+ *   provided
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_ifup(FAR struct net_driver_s *dev)
+{
+  FAR struct lan9250_driver_s *priv =
+        (FAR struct lan9250_driver_s *)dev->d_private;
+  int ret;
+#ifdef CONFIG_LAN9250_REGDEBUG
+  uint32_t mac_addr[2];
+#endif
+
+  ninfo("Bringing up: %u.%u.%u.%u\n",
+        ip4_addr1(dev->d_ipaddr), ip4_addr2(dev->d_ipaddr),
+        ip4_addr3(dev->d_ipaddr), ip4_addr4(dev->d_ipaddr));
+
+  /* Lock the SPI bus so that we have exclusive access */
+
+  lan9250_lock_spi(priv);
+
+  /* Initialize Ethernet interface, set the MAC address, and make sure that
+   * the LAN9250 is not in power save mode.
+   */
+
+  ret = lan9250_reset(priv);
+  if (ret == OK)
+    {
+      lan9250_set_macaddr(priv);
+
+      /* Enable interrupts at the LAN9250.  Interrupts are still disabled
+       * at the interrupt controller.
+       */
+
+      /* Enable the receiver */
+
+      /* Mark the interface up and enable the Ethernet interrupt at the
+       * controller
+       */
+
+      priv->lower->enable(priv->lower);
+
+      /* Read MAC address here in debug mode */
+
+#ifdef CONFIG_LAN9250_REGDEBUG
+      mac_addr[0] = lan9250_get_macreg(priv, LAN9250_HMACALR);
+      mac_addr[1] = lan9250_get_macreg(priv, LAN9250_HMACAHR);
+
+      ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+            (uint8_t)(mac_addr[1] >>  0), (uint8_t)(mac_addr[1] >>  8),
+            (uint8_t)(mac_addr[0] >> 24), (uint8_t)(mac_addr[0] >> 16),
+            (uint8_t)(mac_addr[0] >>  8), (uint8_t)(mac_addr[0] >>  0));
+#endif
+    }
+
+  /* Un-lock the SPI bus */
+
+  lan9250_unlock_spi(priv);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: lan9250_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_ifdown(FAR struct net_driver_s *dev)
+{
+  FAR struct lan9250_driver_s *priv =
+        (FAR struct lan9250_driver_s *)dev->d_private;
+  irqstate_t flags;
+
+  ninfo("Taking down: %u.%u.%u.%u\n",
+        ip4_addr1(dev->d_ipaddr), ip4_addr2(dev->d_ipaddr),
+        ip4_addr3(dev->d_ipaddr), ip4_addr4(dev->d_ipaddr));
+
+  /* Lock the SPI bus so that we have exclusive access */
+
+  lan9250_lock_spi(priv);
+
+  /* Reset the device and leave in the power save state */
+
+  lan9250_sw_reset(priv);
+
+  /* Disable the Ethernet interrupt */
+
+  flags = enter_critical_section();
+  priv->lower->disable(priv->lower);
+
+  /* Cancel the TX timeout timers */
+
+  wd_cancel(&priv->txtout_timer);
+
+  IFF_CLR_UP(priv->dev.d_flags);
+  leave_critical_section(flags);
+
+  /* Un-lock the SPI bus */
+
+  lan9250_unlock_spi(priv);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_txavail
+ *
+ * Description:
+ *   Driver callback invoked when new TX data is available.  This is a
+ *   stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ *   latency.
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static int lan9250_txavail(FAR struct net_driver_s *dev)
+{
+  FAR struct lan9250_driver_s *priv =
+        (FAR struct lan9250_driver_s *)dev->d_private;
+  irqstate_t flags;
+
+  /**
+   * Lock the SPI bus so that we have exclusive access for but SPI and
+   * LAN9250 SPI private data.
+   */
+
+  lan9250_lock_spi(priv);
+
+  flags = enter_critical_section();
+
+  /**
+   * Since SPI is locked, so interrupt work must not really process when
+   * CPU run here, so:
+   *
+   *   - priv->tx_available = true, TX data FIFO is available and its related
+   *     interrupt is disable.
+   *   - priv->tx_available = false, TX data FIFO is unavailable and its
+   *     related interrupt is enable, so when this interrupt triggers,
+   *     function "devif_poll" will poll the network for new XMIT data.
+   */
+
+  if (IFF_IS_UP(dev->d_flags) &&
+      priv->tx_available &&
+      work_available(&priv->txpoll_work))
+    {
+      /* Schedule to serialize the poll on the worker thread. */
+
+      work_queue(LAN9250_WORK, &priv->txpoll_work,
+                 lan9250_txavail_work, priv, 0);
+    }
+
+  /* Un-lock the SPI bus */
+
+  leave_critical_section(flags);
+  lan9250_unlock_spi(priv);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lan9250_addmac
+ *
+ * Description:
+ *   NuttX Callback: Add the specified MAC address to the hardware multicast
+ *   address filtering
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be added
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int lan9250_addmac(FAR struct net_driver_s *dev,
+                          FAR const uint8_t *mac)
+{
+  /* #warning "Multicast MAC support not implemented" */
+
+  return -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Name: lan9250_rmmac
+ *
+ * Description:
+ *   NuttX Callback: Remove the specified MAC address from the hardware
+ *   multicast address filtering
+ *
+ * Input Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be removed
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_MCASTGROUP
+static int lan9250_rmmac(FAR struct net_driver_s *dev,
+                         FAR const uint8_t *mac)
+{
+  /* #warning "Multicast MAC support not implemented" */
+
+  return -ENOSYS;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_initialize
+ *
+ * Description:
+ *   Initialize the LAN9250 Ethernet driver.
+ *
+ * Input Parameters:
+ *   spi   - A reference to the platform's SPI driver for the LAN9250 when
+ *           enable CONFIG_LAN9250_SPI
+ *   qspi  - A reference to the platform's SQI driver for the LAN9250 when
+ *           enable CONFIG_LAN9250_SQI
+ *   lower - The MCU-specific interrupt used to control low-level MCU
+ *           functions (i.e., LAN9250 GPIO interrupts).
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+int lan9250_initialize(
+#ifdef CONFIG_LAN9250_SPI
+                       FAR struct spi_dev_s *spi,
+#else
+                       FAR struct qspi_dev_s *qspi,
+#endif
+                       FAR const struct lan9250_lower_s *lower)
+{
+  FAR struct lan9250_driver_s *priv = &g_lan9250;
+  FAR struct net_driver_s *dev = &priv->dev;
+
+  /* Initialize the driver structure */
+
+  memset(priv, 0, sizeof(struct lan9250_driver_s));
+
+  dev->d_buf     = (uint8_t *)priv->pktbuf;
+  dev->d_ifup    = lan9250_ifup;
+  dev->d_ifdown  = lan9250_ifdown;
+  dev->d_txavail = lan9250_txavail;
+#ifdef CONFIG_NET_MCASTGROUP
+  dev->d_addmac  = lan9250_addmac;
+  dev->d_rmmac   = lan9250_rmmac;
+#endif
+  dev->d_private = priv;
+
+#ifdef CONFIG_LAN9250_SPI
+  priv->spi      = spi;
+#else
+  priv->qspi     = qspi;
+#endif
+
+  priv->lower    = lower;
+
+  /* Attach the interrupt to the driver (but don't enable it yet) */
+
+  if (lower->attach(lower, lan9250_interrupt, priv) < 0)
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      return -EAGAIN;
+    }
+
+  /* Try to read MAC address from low-level function. */
+
+  if (lower->getmac)
+    {
+      lower->getmac(lower, priv->dev.d_mac.ether.ether_addr_octet);
+    }
+
+  /* Register the device with the OS so that socket IOCTLs can be performed */
+
+  return netdev_register(dev, NET_LL_ETHERNET);
+}
diff --git a/drivers/net/lan9250.h b/drivers/net/lan9250.h
new file mode 100644
index 0000000000..6eff7e758e
--- /dev/null
+++ b/drivers/net/lan9250.h
@@ -0,0 +1,628 @@
+/****************************************************************************
+ * drivers/net/lan9250.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing software
+ * distributed under the License is distributed on an "AS IS" BASIS WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_NET_LAN9250_H
+#define __DRIVERS_NET_LAN9250_H
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* LAN9250 SPI Commands *****************************************************/
+
+#define LAN9250_SPI_CMD_READ        0x03
+#define LAN9250_SPI_CMD_FREAD       0x0b
+#define LAN9250_SPI_CMD_WRITE       0x02
+#define LAN9250_SPI_CMD_ENABLE_SQI  0x38
+
+#define LAN9250_QSPI_CMD_READ       0xeb
+#define LAN9250_QSPI_CMD_WRITE      0xe2
+
+/* System Control and Status Registers **************************************/
+
+#define LAN9250_RXDFR               0x000
+#define LAN9250_TXDFR               0x020
+#define LAN9250_RXSFR               0x040
+#define LAN9250_RXSPR               0x044
+#define LAN9250_TXSFR               0x048
+#define LAN9250_TXSPR               0x04c
+#define LAN9250_CIARR               0x050
+#define LAN9250_ICFGR               0x054
+#define LAN9250_ISR                 0x058
+#define LAN9250_IER                 0x05c
+#define LAN9250_BOTR                0x064
+#define LAN9250_FLIR                0x068
+#define LAN9250_RXCFGR              0x06c
+#define LAN9250_TXCFGR              0x070
+#define LAN9250_HWCFGR              0x074
+#define LAN9250_RDCR                0x078
+#define LAN9250_RXFIR               0x07c
+#define LAN9250_TXFIR               0x080
+#define LAN9250_PMCR                0x084
+#define LAN9250_GPTCFGR             0x08c
+#define LAN9250_GPTCR               0x090
+#define LAN9250_FR25MCR             0x09c
+#define LAN9250_HMRDFCR             0x0a0
+#define LAN9250_HMCSRICR            0x0a4
+#define LAN9250_HMCSRIDR            0x0a8
+#define LAN9250_HMAFCCFGR           0x0ac
+#define LAN9250_HMRXLPITXR          0x0b0
+#define LAN9250_HMRXLPITR           0x0b4
+#define LAN9250_HMTXLPITXR          0x0b8
+#define LAN9250_HMTXLPITR           0x0bc
+
+/* 1588 Register Addresses */
+
+#define LAN9250_1588CACR            0x100
+#define LAN9250_1588GCFGR           0x104
+#define LAN9250_1588ISR             0x108
+#define LAN9250_1588IER             0x10c
+#define LAN9250_1588CLKSR           0x110
+#define LAN9250_1588CLKNSR          0x114
+#define LAN9250_1588CLKSNSR         0x118
+#define LAN9250_1588CLKRAR          0x11c
+#define LAN9250_1588CLKTRAR         0x120
+#define LAN9250_1588CLKTRDR         0x124
+#define LAN9250_1588CLKSAR          0x128
+#define LAN9250_1588CLKATXSR        0x12c
+#define LAN9250_1588CLKATXNSR       0x130
+#define LAN9250_1588CLKATXRASR      0x134
+#define LAN9250_1588CLKATXRANSR     0x138
+#define LAN9250_1588CLKBTXSR        0x13c
+#define LAN9250_1588CLKBTXNSR       0x140
+#define LAN9250_1588CLKBTXRASR      0x144
+#define LAN9250_1588CLKBTXRANSR     0x148
+#define LAN9250_1588UMAHWR          0x14c
+#define LAN9250_1588UMALWR          0x150
+#define LAN9250_1588BPGSR           0x154
+
+/* Bank 0 Control Register Addresses */
+
+#define LAN9250_1588PLR             0x158
+#define LAN9250_1588PAAPDR          0x15c
+#define LAN9250_1588PCIR            0x160
+
+/* Bank 1 Control Register Addresses */
+
+#define LAN9250_1588PRXPCR          0x158
+#define LAN9250_1588PRXTSCR         0x15c
+#define LAN9250_1588PRXTICR         0x160
+#define LAN9250_1588PRXFCFGR        0x168
+#define LAN9250_1588PRXITSR         0x16c
+#define LAN9250_1588PRXITNSR        0x170
+#define LAN9250_1588PRXMHR          0x174
+#define LAN9250_1588PRXPDRITSR      0x178
+#define LAN9250_1588PRXPDRITNSR     0x17c
+#define LAN9250_1588PRXPDRICFHR     0x180
+#define LAN9250_1588PRXPDRICFLR     0x184
+#define LAN9250_1588PRXCSDCR        0x188
+#define LAN9250_1588PRXFCR          0x18c
+
+/* Bank 2 Control Register Addresses */
+
+#define LAN9250_1588PTXPCR          0x158
+#define LAN9250_1588PTXTSCR         0x15c
+#define LAN9250_1588PTXMR           0x164
+#define LAN9250_1588PTXM2R          0x168
+#define LAN9250_1588PTXETSR         0x16c
+#define LAN9250_1588PTXETNSR        0x170
+#define LAN9250_1588PTXMHR          0x174
+#define LAN9250_1588PTXDRDTSR       0x178
+#define LAN9250_1588PTXDRDTNSR      0x17c
+#define LAN9250_1588TXOSSUSR        0x180
+
+/* Bank 3 Control Register Addresses */
+
+#define LAN9250_1588GPIOCCFGR       0x15c
+#define LAN9250_1588GPIOXRECLKSCR   0x16c
+#define LAN9250_1588GPIOXRECLKNSCR  0x170
+#define LAN9250_1588GPIOXFECLKSCR   0x178
+#define LAN9250_1588GPIOXFECLKNSCR  0x17c
+
+/* ISR_GPIO Register Addresses */
+
+#define LAN9250_GPIOCFGR            0x1e0
+#define LAN9250_GPIODADR            0X1e4
+#define LAN9250_GPIOISAER           0X1e8
+
+/* Reset Register Addresses */
+
+#define LAN9250_RSTCR               0x1f8
+
+/* Host MAC Registers *******************************************************/
+
+#define LAN9250_HMACCR              0x01
+#define LAN9250_HMACAHR             0x02
+#define LAN9250_HMACALR             0x03
+#define LAN9250_HMACHTHR            0x04
+#define LAN9250_HMACHTLR            0x05
+#define LAN9250_HMACMIIAR           0x06
+#define LAN9250_HMACMIIDR           0x07
+#define LAN9250_HMACFCR             0x08
+#define LAN9250_HMACVLAN1TR         0x09
+#define LAN9250_HMACVLAN2TR         0x0a
+#define LAN9250_HMACWUFFR           0x0b
+#define LAN9250_HMACWUCASR          0x0c
+#define LAN9250_HMACCSOECR          0x0d
+#define LAN9250_HMACEEETWTXSR       0x0e
+#define LAN9250_HMACEEETXLPIRDR     0x0f
+
+/* PHY Registers ************************************************************/
+
+#define LAN9250_PHYBCR              0
+#define LAN9250_PHYBSR              1
+#define LAN9250_PHYIMSBR            2
+#define LAN9250_PHYILSBR            3
+#define LAN9250_PHYANAR             4
+#define LAN9250_PHYANLPBPAR         5
+#define LAN9250_PHYANER             6
+#define LAN9250_PHYANNPTXR          7
+#define LAN9250_PHYANNPRXR          8
+#define LAN9250_PHYMMDACR           13
+#define LAN9250_PHYMMDAODR          14
+#define LAN9250_PHYEDPDCFGR         16
+#define LAN9250_PHYMCOSR            17
+#define LAN9250_PHYSMR              18
+#define LAN9250_PHYTDRPODCR         24
+#define LAN9250_PHYTDRCOSR          25
+#define LAN9250_PHYSECR             26
+#define LAN9250_PHYSCOSIR           27
+#define LAN9250_PHYCLR              28
+#define LAN9250_PHYISFR             29
+#define LAN9250_PHYIER              30
+#define LAN9250_PHYSCOSR            31
+
+/* LAN9250 SPI Commands Fields **********************************************/
+
+/* SPI Write Command A */
+
+#define SPI_CMD_WRITE_A_IOC         0X80000000
+#define SPI_CMD_WRITE_A_BEA         0x03000000
+#define SPI_CMD_WRITE_A_4BA         0x00000000
+#define SPI_CMD_WRITE_A_16BA        0x01000000
+#define SPI_CMD_WRITE_A_32BA        0x02000000
+#define SPI_CMD_WRITE_A_DO          0x00000000
+#define SPI_CMD_WRITE_A_FS          0x00002000
+#define SPI_CMD_WRITE_A_LS          0x00001000
+#define SPI_CMD_WRITE_A_BS_M        0x000007ff
+
+/* SPI Write Command B */
+
+#define SPI_CMD_WRITE_B_PT          0x05200000
+#define SPI_CMD_WRITE_B_CE          0x00004000
+#define SPI_CMD_WRITE_B_ACD         0x00002000
+#define SPI_CMD_WRITE_B_DP          0x00001000
+#define SPI_CMD_WRITE_B_PL_M        0x000007ff
+
+/* RX FIFO Status Format Fields *********************************************/
+
+#define RXSFF_PF                    0x80000000
+#define RXSFF_FF                    0x40000000
+#define RXSFF_PL_M                  0x3fff0000
+#define RXSFF_PL_S                  16
+#define RXSFF_ES                    0x00008000
+#define RXSFF_BF                    0x00002000
+#define RXSFF_LE                    0x00001000
+#define RXSFF_RF                    0x00000800
+#define RXSFF_MF                    0x00000400
+#define RXSFF_FTL                   0x00000080
+#define RXSFF_CS                    0x00000040
+#define RXSFF_FT                    0x00000020
+#define RXSFF_RWTO                  0x00000010
+#define RXSFF_MIIE                  0x00000008
+#define RXSFF_DB                    0x00000004
+#define RXSFF_CRCE                  0x00000002
+
+/* System Control and Status Registers Fields *******************************/
+
+/* RX FIFO Status Register */
+
+#define RXFIR_RXSFUS_M              0x00ff0000
+#define RXFIR_RXSFUS_S              16
+#define RXFIR_RXDFUS_M              0x0000ffff
+
+/* TX FIFO Status Register */
+
+#define TXFIR_TXSFUS_M              0x00ff0000
+#define TXFIR_TXSFUS_S              16
+#define TXFIR_TXDFFS_M              0x0000ffff
+
+/* Hardware Configuration Register */
+
+#define HWCFGR_READY                0x08000000
+#define HWCFGR_AMDIXENSS            0x02000000
+#define HWCFGR_MBO                  0x00100000
+#define HWCFGR_TXFS_M               0x000f0000
+#define HWCFGR_TXFS_S               16
+
+/* Byte Order Test Register */
+
+#define BOTR_MASK                   0xffffffff
+#define BOTR_VAL                    0x87654321
+
+/* Host MAC Automatic Flow Control Configuration Register */
+
+#define HMAFCCFGR_AFCHL_M           0x00ff0000
+#define HMAFCCFGR_AFCHL_S           16
+#define HMAFCCFGR_AFCLL_M           0x0000ff00
+#define HMAFCCFGR_AFCLL_S           8
+#define HMAFCCFGR_BPD_M             0x000000f0
+#define HMAFCCFGR_BPD_S             4
+#define HMAFCCFGR_FCOMF             0x00000008
+#define HMAFCCFGR_FCOBF             0x00000004
+#define HMAFCCFGR_FCOAD             0x00000002
+#define HMAFCCFGR_FCOAF             0x00000001
+
+/* Chip ID and Revision Register */
+
+#define CIARR_CID_M                 0xffff0000
+#define CIARR_CID_S                 16
+#define CIARR_CID_V                 (0x9250 << 16)
+#define CIARR_CREV_M                0x0000ffff
+
+/* Interrupt Configuration Register */
+
+#define ICFGR_IDAI_M                0xf0000000
+#define ICFGR_IDAI_S                24
+#define ICFGR_IDAIC                 0x00004000
+#define ICFGR_IDAS                  0x00002000
+#define ICFGR_MI                    0x00001000
+#define ICFGR_IRQE                  0x00000100
+#define ICFGR_IRQP                  0x00000010
+#define ICFGR_IRQCLKS               0x00000002
+#define ICFGR_IRQBT                 0x00000001
+
+/* Interrupt Enable Register */
+
+#define IER_SW                      0x80000000
+#define IER_RAEDY                   0x40000000
+#define IER_1588                    0x20000000
+#define IER_PHY                     0x04000000
+#define IER_TXSTOP                  0x02000000
+#define IER_RXSTOP                  0x01000000
+#define IER_RXDFH                   0x00800000
+#define IER_TXIOC                   0x00200000
+#define IER_RXD                     0x00100000
+#define IER_GPT                     0x00080000
+#define IER_PME                     0x00020000
+#define IER_TXSO                    0x00010000
+#define IER_RWT                     0x00008000
+#define IER_RXE                     0x00004000
+#define IER_TXE                     0x00002000
+#define IER_GPIO                    0x00001000
+#define IER_TDFO                    0x00000400
+#define IER_TDFA                    0x00000200
+#define IER_TSFF                    0x00000100
+#define IER_TSFL                    0x00000080
+#define IER_RXDF                    0x00000040
+#define IER_RSFF                    0x00000010
+#define IER_RSFL                    0x00000008
+
+/* Interrupt Status Register */
+
+#define ISR_SW                      0x80000000
+#define ISR_READY                   0x40000000
+#define ISR_1588                    0x20000000
+#define ISR_PHY                     0x04000000
+#define ISR_TXS                     0x02000000
+#define ISR_RXS                     0x01000000
+#define ISR_RXDFH                   0x00800000
+#define ISR_TXIOC                   0x00200000
+#define ISR_RXD                     0x00100000
+#define ISR_GPT                     0x00080000
+#define ISR_PME                     0x00020000
+#define ISR_TXSO                    0x00010000
+#define ISR_RWT                     0x00008000
+#define ISR_RXE                     0x00004000
+#define ISR_TXE                     0x00002000
+#define ISR_GPIO                    0x00001000
+#define ISR_TDFO                    0x00000400
+#define ISR_TDFA                    0x00000200
+#define ISR_TSFF                    0x00000100
+#define ISR_TSFL                    0x00000080
+#define ISR_RXDF                    0x00000040
+#define ISR_RSFF                    0x00000010
+#define ISR_RSFL                    0x00000008
+
+/* FIFO Level Interrupt Register */
+
+#define FLIR_FITXDAL_M              0xff000000
+#define FLIR_FITXDAL_S              24
+#define FLIR_FITXSL_M               0x00ff0000
+#define FLIR_FITXSL_S               16
+#define FLIR_FIRXSL_M               0x000000ff
+#define FLIR_FIRXSL_S               0
+
+/* Receive Configuration Register */
+
+#define RXCFGR_RXEA                 0xc0000000
+#define RXCFGR_RXDMAC               0x06000000
+#define RXCFGR_RXDMAC_M             0x0fff0000
+#define RXCFGR_RXDMAC_S             16
+#define RXCFGR_FRXD                 0x00008000
+#define RXCFGR_RXDO_M               0x00001f00
+#define RXCFGR_RXDO_S               8
+
+/* Transmit Configuration Register */
+
+#define TXCFGR_FTXSD                0x00008000
+#define TXCFGR_FTXDD                0x00004000
+#define TXCFGR_TXSAO                0x00000004
+#define TXCFGR_TXE                  0x00000002
+#define TXCFGR_TXD                  0x00000001
+
+/* Power Management Control Register */
+
+#define PMCR_PMM_M                  0xe0000000
+#define PMCR_PMSE                   0x10000000
+#define PMCR_PMWU                   0x08000000
+#define PMCR_LEDD                   0x04000000
+#define PMCR_1588CLKD               0x02000000
+#define PMCR_1588TSUCLKD            0x00400000
+#define PMCR_HMACCLKD               0x00080000
+#define PMCR_HMACSCOD               0x00040000
+#define PMCR_EDS                    0x00010000
+#define PMCR_EDE                    0x00004000
+#define PMCR_WOE                    0x00000200
+#define PMCR_PMEBT                  0x00000040
+#define PMCR_WOLS                   0x00000020
+#define PMCR_PMEI                   0x00000008
+#define PMCR_PMEP                   0x00000004
+#define PMCR_PMEE                   0x00000002
+#define PMCR_READY                  0x00000001
+
+/* Host MAC CSR Interface Command Register */
+
+#define HMCSRICR_CSRB               0x80000000
+#define HMCSRICR_RNW                0x40000000
+#define HMCSRICR_CSRA_M             0x000000ff
+
+/* Reset Control Register */
+
+#define RSTCR_HMACR                 0x00000020
+#define RSTCR_PHYR                  0x00000002
+#define RSTCR_DR                    0x00000001
+
+/* Host MAC Registers Fields ************************************************/
+
+/* Host MAC Control Register */
+
+#define HMACCR_RXAM                 0x80000000
+#define HMACCR_EEEE                 0x02000000
+#define HMACCR_DRXO                 0x00400000
+#define HMACCR_LOM                  0x00200000
+#define HMACCR_FDM                  0x00100000
+#define HMACCR_PAM                  0x00080000
+#define HMACCR_PM                   0x00040000
+#define HMACCR_IF                   0x00020000
+#define HMACCR_PBF                  0x00010000
+#define HMACCR_HOFM                 0x00008000
+#define HMACCR_HOPFM                0x00002000
+#define HMACCR_DBF                  0x00000800
+#define HMACCR_DR                   0x00000400
+#define HMACCR_APS                  0x00000100
+#define HMACCR_BOL_M                0x000000c0
+#define HMACCR_DC                   0x00000020
+#define HMACCR_TXE                  0x00000008
+#define HMACCR_RXE                  0x00000004
+
+/* Host MAC MII Access Register */
+
+#define HMACMIIAR_PHYA_M            0x0000f800
+#define HMACMIIAR_PHYA_S            11
+#define HMACMIIAR_MIIRX_M           0x000007c0
+#define HMACMIIAR_MIIRX_S           6
+#define HMACMIIAR_MIIW              0x00000002
+#define HMACMIIAR_MIIB              0x00000001
+
+/* Host MAC Flow Control Register */
+
+#define HMACFCR_PT_M                0xffff0000
+#define HMACFCR_PT_S                16
+#define HMACFCR_PCF                 0x00000004
+#define HMACFCR_FLE                 0x00000002
+#define HMACFCR_FLB                 0x00000001
+
+/* PHY Registers Fields *****************************************************/
+
+/* PHY Basic Control Register */
+
+#define PHYBCR_SWR                  0x8000
+#define PHYBCR_LB                   0x4000
+#define PHYBCR_SSLSB                0x2000
+#define PHYBCR_ANE                  0x1000
+#define PHYBCR_PD                   0x0800
+#define PHYBCR_RAN                  0x0200
+#define PHYBCR_DM                   0x0100
+#define PHYBCR_CTM                  0x0080
+
+/* PHY Basic Status Register */
+
+#define PHYBSR_100BT4               0x8000
+#define PHYBSR_100BXFD              0x4000
+#define PHYBSR_100BXHD              0x2000
+#define PHYBSR_10BXFD               0x1000
+#define PHYBSR_10BXHD               0x0800
+#define PHYBSR_100BT2FD             0x0400
+#define PHYBSR_100BT2HD             0x0200
+#define PHYBSR_ES                   0x0100
+#define PHYBSR_UDA                  0x0080
+#define PHYBSR_MFPS                 0x0040
+#define PHYBSR_ANC                  0x0020
+#define PHYBSR_RF                   0x0010
+#define PHYBSR_ANA                  0x0008
+#define PHYBSR_LS                   0x0004
+#define PHYBSR_JD                   0x0002
+#define PHYBSR_EC                   0x0001
+
+/* PHY Identification MSB Register */
+
+#define PHYIMSBR_ID                 0xffff
+
+/* PHY Identification LSB Register */
+
+#define PHYILSBR_ID_M               0xfc00
+#define PHYILSBR_ID_S               10
+#define PHYILSBR_MN_M               0x03f0
+#define PHYILSBR_MN_S               4
+#define PHYILSBR_RN_M               0x000f
+#define PHYILSBR_RN_S               0
+
+/* PHY Auto-Negotiation Advertisement Register */
+
+#define PHYANAR_NP                  0x8000
+#define PHYANAR_RF                  0x2000
+#define PHYANAR_ENP                 0x1000
+#define PHYANAR_AP                  0x0800
+#define PHYANAR_SP                  0x0400
+#define PHYANAR_100BXFD             0x0100
+#define PHYANAR_100BXHD             0x0080
+#define PHYANAR_10BXFD              0x0040
+#define PHYANAR_10BXHD              0x0020
+#define PHYANAR_SF                  0x0001
+
+/* PHY Auto-Negotiation Link Partner Base Page Ability Register */
+
+#define PHYANLPBPAR_NP              0x8000
+#define PHYANLPBPAR_ACK             0x4000
+#define PHYANLPBPAR_RF              0x2000
+#define PHYANLPBPAR_ENP             0x1000
+#define PHYANLPBPAR_AP              0x0800
+#define PHYANLPBPAR_PAUSE           0x0400
+#define PHYANLPBPAR_100BT4          0x0200
+#define PHYANLPBPAR_100BXFD         0x0100
+#define PHYANLPBPAR_100BXHD         0x0080
+#define PHYANLPBPAR_10BXFD          0x0040
+#define PHYANLPBPAR_10BXHD          0x0020
+#define PHYANLPBPAR_SF_M            0x001f
+
+/* PHY Auto-Negotiation Expansion Register */
+
+#define PHYANER_RXNPLA              0x0040
+#define PHYANER_RXNPSL              0x0020
+#define PHYANER_PDF                 0x0010
+#define PHYANER_LPNPA               0x0008
+#define PHYANER_NPA                 0x0004
+#define PHYANER_PRX                 0x0002
+#define PHYANER_LPANA               0x0001
+
+/* PHY Auto-Negotiation Next Page TX Register */
+
+#define PHYANNPTXR_NP               0x8000
+#define PHYANNPTXR_MP               0x2000
+#define PHYANNPTXR_ACK2             0x1000
+#define PHYANNPTXR_TOG              0x0800
+#define PHYANNPTXR_MC_M             0x07ff
+
+/* PHY Auto-Negotiation Next Page RX Register */
+
+#define PHYANNPRXR_NP               0x8000
+#define PHYANNPRXR_ACK              0x4000
+#define PHYANNPRXR_MP               0x2000
+#define PHYANNPRXR_ACK2             0x1000
+#define PHYANNPRXR_TOG              0x0800
+#define PHYANNPRXR_MC_M             0x07ff
+
+/* PHY MMD Access Control Register */
+
+#define PHYMMDACR_MMDF_M            0xc000
+#define PHYMMDACR_MMDDA_M           0x001f
+
+/* PHY EDPD NLP/Crossover Time/EEE Configuration Register */
+
+#define PHYEDPDCFGR_EDPDTXNLPE      0x8000
+#define PHYEDPDCFGR_EDPDTXNLPITS_M  0x6000
+#define PHYEDPDCFGR_EDPDRXSNLPWE    0x1000
+#define PHYEDPDCFGR_EDPDRXNLPMIDS_M 0x0c00
+#define PHYEDPDCFGR_PEEEE           0x0004
+#define PHYEDPDCFGR_EDPDEC          0x0002
+#define PHYEDPDCFGR_EMAMDIXCT       0x0001
+
+/* PHY Mode Control/Status Register */
+
+#define PHYMCOSR_EDPD               0x2000
+#define PHYMCOSR_AIM                0x0040
+#define PHYMCOSR_EO                 0x0002
+
+/* PHY Special Modes Register */
+
+#define PHYSMR_100BFXM              0x0400
+#define PHYSMR_PM_M                 0x00e0
+#define PHYSMR_PM_S                 5
+#define PHYSMR_ADDR_M               0x001f
+#define PHYSMR_ADDR_S               0x00e0
+
+/* PHY TDR Patterns/Delay Control Register */
+
+#define PHYTDRCOSR_TDRDI            0x8000
+#define PHYTDRCOSR_TDRLBC_M         0x7000
+#define PHYTDRCOSR_TDRPH            0x0fc0
+#define PHYTDRCOSR_TDRPL            0x003f
+
+/* PHY TDR Control/Status Register */
+
+#define PHYTDRCOSR_TDRE             0x8000
+#define PHYTDRCOSR_TDRATDFE         0x4000
+#define PHYTDRCOSR_TDRCCT           0x0600
+#define PHYTDRCOSR_TDRCS            0x0100
+#define PHYTDRCOSR_TDRCL            0x00FF
+
+/*  PHY Special Control/Status Indication register */
+
+#define PHYSCOSIR_AMDIXC            0x8000
+#define PHYSCOSIR_AMDIXE            0x4000
+#define PHYSCOSIR_DMDIXS            0x2000
+#define PHYSCOSIR_SQETD             0x0800
+#define PHYSCOSIR_FEFIE             0x0020
+#define PHYSCOSIR_10BTPS            0x0010
+
+/* PHY Cable Length Register */
+
+#define PHYCLR_CL_M                 0xf000
+
+/* PHY Interrupt Source Flags Register */
+
+#define PHYISFR_LU                  0x0200
+#define PHYISFR_EO                  0x0080
+#define PHYISFR_ANC                 0x0040
+#define PHYISFR_RF                  0x0020
+#define PHYISFR_LD                  0x0010
+#define PHYISFR_ANLPA               0x0008
+#define PHYISFR_PDF                 0x0004
+#define PHYISFR_ANPR                0x0002
+
+/* PHY Interrupt Enable Register */
+
+#define PHYIER_LU                   0x0200
+#define PHYIER_EO                   0x0080
+#define PHYIER_ANC                  0x0040
+#define PHYIER_RF                   0x0020
+#define PHYIER_LD                   0x0010
+#define PHYIER_ANLPA                0x0008
+#define PHYIER_PDF                  0x0004
+#define PHYIER_ANPR                 0x0002
+
+/* PHY Special Control/Status Register */
+
+#define PHYSCOSR_AD                 0x8000
+#define PHYSCOSR_RD                 0x0040
+#define PHYSCOSR_SI_M               0x001c
+
+#endif /* __DRIVERS_NET_LAN9250_H */
diff --git a/include/nuttx/net/lan9250.h b/include/nuttx/net/lan9250.h
new file mode 100644
index 0000000000..5702212102
--- /dev/null
+++ b/include/nuttx/net/lan9250.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+ * include/nuttx/net/lan9250.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_LAN9250_H
+#define __INCLUDE_NUTTX_NET_LAN9250_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <nuttx/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* The LAN9250 device typically provides interrupts to the MCU through a GPIO
+ * pin. The structure below provides an MCU-independent mechanism for
+ * controlling this LAN9250 GPIO interrupt.
+ *
+ * "When an enabled interrupt occurs, the interrupt pin will remain low until
+ * all flags which are causing the interrupt are cleared or masked off
+ * (enable bit is cleared) by the host controller."  However, the interrupt
+ * will behave like a falling edge interrupt because "After an interrupt
+ * occurs, the host controller [clears] the global enable bit for the
+ * interrupt pin before servicing the interrupt. Clearing the enable bit
+ * will cause the interrupt pin to return to the non-asserted state (high).
+ * Doing so will prevent the host controller from missing a falling edge
+ * should another interrupt occur while the immediate interrupt is being
+ * serviced."
+ */
+
+struct lan9250_lower_s
+{
+  int  (*attach)(FAR const struct lan9250_lower_s *lower, xcpt_t handler,
+                 FAR void *arg);
+  void (*enable)(FAR const struct lan9250_lower_s *lower);
+  void (*disable)(FAR const struct lan9250_lower_s *lower);
+
+  /* This function is optional and used to get a specific MAC address from
+   * a MCU-specific implementation. If this function is NULL, the LAN9250
+   * driver will not read the MAC from the CPU.
+   */
+
+  void (*getmac)(FAR const struct lan9250_lower_s *lower, FAR uint8_t *mac);
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lan9250_initialize
+ *
+ * Description:
+ *   Initialize the LAN9250 Ethernet driver.
+ *
+ * Input Parameters:
+ *   spi   - A reference to the platform's SPI driver for the LAN9250 when
+ *           enable CONFIG_LAN9250_SPI
+ *   qspi  - A reference to the platform's SQI driver for the LAN9250 when
+ *           enable CONFIG_LAN9250_SQI
+ *   lower - The MCU-specific interrupt used to control low-level MCU
+ *           functions (i.e., LAN9250 GPIO interrupts).
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_LAN9250_SPI
+struct spi_dev_s;   /* see nuttx/spi/spi.h */
+#else
+struct qspi_dev_s;  /* see nuttx/spi/qspi.h */
+#endif
+int lan9250_initialize(
+#ifdef CONFIG_LAN9250_SPI
+                       FAR struct spi_dev_s *spi,
+#else
+                       FAR struct qspi_dev_s *qspi,
+#endif
+                       FAR const struct lan9250_lower_s *lower);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_NET_LAN9250_H */

Reply via email to