diff --git a/ChangeLog b/ChangeLog
index 7a82c230d55a62f0df89bccddb13b1e8dcf3eb5b..775406486bc4079268d6ffdf98e88e1d65fae11d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5445,5 +5445,8 @@
 	  From Max Holtzberg (2013-8-25).
 	* arch/arm/src/sama5/sam_ohci.c:  SAMA5 OHCI is again functional by
 	  itself after all of the changes to integrate with EHCI. (2013-8-25).
-
-
+	* drivers/net/encx24j600.c/.h and include/nuttx/net/encx24j600.h: 
+	  Support the Microchip ENCX24J600 Ethernet driver from Max Holtberg
+	  (2013-8-25).
+	* configs/olimex-stm32-p107:  Incorporate ENCX24J600 support for the
+	  Olimex STM32 P107 board.  From Max Holtzberg (2013-8-25).
diff --git a/configs/olimex-stm32-p107/src/Makefile b/configs/olimex-stm32-p107/src/Makefile
index 66bd595306871690f2bfd6f4c94111a1125cda9d..83211584d7083d2f32577d1bf7ea239709acf087 100644
--- a/configs/olimex-stm32-p107/src/Makefile
+++ b/configs/olimex-stm32-p107/src/Makefile
@@ -37,15 +37,19 @@
 
 CFLAGS		+= -I$(TOPDIR)/sched
 
-ASRCS		= 
+ASRCS		=
 AOBJS		= $(ASRCS:.S=$(OBJEXT))
 
-CSRCS		= up_boot.c
+CSRCS		= up_boot.c up_spi.c
 
 ifeq ($(CONFIG_CAN),y)
 CSRCS		+= up_can.c
 endif
 
+ifeq ($(CONFIG_ENCX24J600),y)
+CSRCS		+= up_encx24j600.c
+endif
+
 COBJS		= $(CSRCS:.c=$(OBJEXT))
 
 SRCS		= $(ASRCS) $(CSRCS)
diff --git a/configs/olimex-stm32-p107/src/p107-internal.h b/configs/olimex-stm32-p107/src/p107-internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..f699e70d3ff1401d179623f15860a6cd043586ec
--- /dev/null
+++ b/configs/olimex-stm32-p107/src/p107-internal.h
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * configs/olimex-stm32-p107/src/p107-internal.h
+ *
+ *   Copyright (C) 2013 Max Holtzberg. All rights reserved.
+ *   Author: Max Holtzberg <mholtzberg@uvc-ingenieure.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+#ifndef __CONFIGS_OLIMEX_STM32_P107_SRC_INTERNAL_H
+#define __CONFIGS_OLIMEX_STM32_P107_SRC_INTERNAL_H
+
+/******************************************************************************
+ * Included Files
+ ******************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/compiler.h>
+#include <stdint.h>
+
+/******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/* ENCX24J600
+ *
+ * --- ------ -------------- ---------------------------------------------------
+ * PIN NAME   SIGNAL         NOTES
+ * --- ------ -------------- ---------------------------------------------------
+ *
+ * 54  PB15   PB15-CS_UEXT   ENCX24J600 #CS
+ * 78  PC10   PC10-SPI3-SCK  ENCX24J600 SCK
+ * 79  PC11   PC11-SPI3-MISO ENCX24J600 MISO
+ * 80  PC12   PC12-SPI3-MOSI ENCX24J600 MOSI
+ * 95  PB8    PB8            ENCX24J600 #Interrupt
+ */
+
+
+#ifdef CONFIG_ENCX24J600
+#  define GPIO_ENCX24J600_CS    (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz| \
+                                 GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN15)
+#  define GPIO_ENCX24J600_INTR  (GPIO_INPUT|GPIO_CNF_INFLOAT|GPIO_MODE_INPUT| \
+                                 GPIO_EXTI|GPIO_PORTB|GPIO_PIN8)
+#endif
+
+#ifndef __ASSEMBLY__
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: stm32_spiinitialize
+ *
+ * Description:
+ *   Called to configure SPI chip select GPIO pins for the M3 Wildfire board.
+ *
+ ************************************************************************************/
+
+void weak_function stm32_spiinitialize(void);
+
+#endif  /* __ASSEMBLY__ */
+#endif /* __CONFIGS_OLIMEX_STM32_P107_SRC_INTERNAL_H */
diff --git a/configs/olimex-stm32-p107/src/up_boot.c b/configs/olimex-stm32-p107/src/up_boot.c
index d7ece5a1e08844369bda3decb3a7c818a7c6631e..d10b143ec0a445c22703aed47e64752b9ebbc94d 100644
--- a/configs/olimex-stm32-p107/src/up_boot.c
+++ b/configs/olimex-stm32-p107/src/up_boot.c
@@ -39,12 +39,11 @@
  ************************************************************************************/
 
 #include <nuttx/config.h>
-
 #include <debug.h>
-
 #include <arch/board/board.h>
 
 #include "up_arch.h"
+#include "p107-internal.h"
 
 /************************************************************************************
  * Pre-processor Definitions
@@ -70,4 +69,15 @@
 
 void stm32_boardinitialize(void)
 {
+  /* Configure SPI chip selects if 1) SPI is not disabled, and 2) the weak function
+   * stm32_spiinitialize() has been brought into the link.
+   */
+
+#if defined(CONFIG_STM32_SPI3)
+  if (stm32_spiinitialize)
+    {
+      stm32_spiinitialize();
+    }
+#endif
+
 }
diff --git a/configs/olimex-stm32-p107/src/up_encx24j600.c b/configs/olimex-stm32-p107/src/up_encx24j600.c
new file mode 100644
index 0000000000000000000000000000000000000000..d8af313e33980d11c31e5210abb7da40802c3f9b
--- /dev/null
+++ b/configs/olimex-stm32-p107/src/up_encx24j600.c
@@ -0,0 +1,196 @@
+/****************************************************************************
+ * configs/olimex-stm32-p107/src/up_encx24j600.c
+ *
+ *   Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdio.h>
+#include <debug.h>
+
+#include <nuttx/spi/spi.h>
+#include <nuttx/net/encx24j600.h>
+
+#include <arch/board/board.h>
+
+#include "chip.h"
+#include "up_arch.h"
+#include "up_internal.h"
+#include "p107-internal.h"
+
+#ifdef CONFIG_ENCX24J600
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+/* Configuration ************************************************************/
+
+/* ENCX24J600
+ *
+ * --- ------ -------------- ------------------------------------------------
+ * PIN NAME   SIGNAL         NOTES
+ * --- ------ -------------- ------------------------------------------------
+ *
+ * 54  PB15   PB15-CS_UEXT   ENCX24J600 #CS
+ * 78  PC10   PC10-SPI3-SCK  ENCX24J600 SCK
+ * 79  PC11   PC11-SPI3-MISO ENCX24J600 MISO
+ * 80  PC12   PC12-SPI3-MOSI ENCX24J600 MOSI
+ * 95  PB8    PB8            ENCX24J600 #Interrupt
+ */
+
+/* ENCX24J600 is on SPI3 */
+
+#ifndef CONFIG_STM32_SPI3
+# error "Need CONFIG_STM32_SPI3 in the configuration"
+#endif
+
+/* SPI Assumptions **********************************************************/
+
+#define ENCX24J600_SPI_PORTNO 3   /* On SPI1 */
+#define ENCX24J600_DEVNO      0   /* Only one ENCX24J600 */
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct stm32_lower_s
+{
+  const struct enc_lower_s lower;    /* Low-level MCU interface */
+  xcpt_t                   handler;  /* ENCX24J600 interrupt handler */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int  up_attach(FAR const struct enc_lower_s *lower, xcpt_t handler);
+static void up_enable(FAR const struct enc_lower_s *lower);
+static void up_disable(FAR const struct enc_lower_s *lower);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The ENCX24J600 normal provides interrupts to the MCU via a GPIO pin.  The
+ * following structure provides an MCU-independent mechanixm for controlling
+ * the ENCX24J600 GPIO interrupt.
+ */
+
+static struct stm32_lower_s g_enclower =
+{
+  .lower =
+  {
+    .attach  = up_attach,
+    .enable  = up_enable,
+    .disable = up_disable
+  },
+  .handler = NULL,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: struct enc_lower_s methods
+ ****************************************************************************/
+
+static int up_attach(FAR const struct enc_lower_s *lower, xcpt_t handler)
+{
+  FAR struct stm32_lower_s *priv = (FAR struct stm32_lower_s *)lower;
+
+  /* Just save the handler for use when the interrupt is enabled */
+
+  priv->handler = handler;
+  return OK;
+}
+
+static void up_enable(FAR const struct enc_lower_s *lower)
+{
+  FAR struct stm32_lower_s *priv = (FAR struct stm32_lower_s *)lower;
+
+  DEBUGASSERT(priv->handler);
+  (void)stm32_gpiosetevent(GPIO_ENCX24J600_INTR, false, true, true, priv->handler);
+}
+
+static void up_disable(FAR const struct enc_lower_s *lower)
+{
+  (void)stm32_gpiosetevent(GPIO_ENCX24J600_INTR, false, true, true, NULL);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_netinitialize
+ ****************************************************************************/
+
+void up_netinitialize(void)
+{
+  FAR struct spi_dev_s *spi;
+  int ret;
+
+  /* Assumptions:
+   * 1) ENCX24J600 pins were configured in up_spi.c early in the boot-up phase.
+   * 2) Clocking for the SPI1 peripheral was also provided earlier in boot-up.
+   */
+
+  spi = up_spiinitialize(ENCX24J600_SPI_PORTNO);
+  if (!spi)
+    {
+      nlldbg("Failed to initialize SPI port %d\n", ENCX24J600_SPI_PORTNO);
+      return;
+    }
+
+  /* Bind the SPI port to the ENCX24J600 driver */
+
+  ret = enc_initialize(spi, &g_enclower.lower, ENCX24J600_DEVNO);
+
+  if (ret < 0)
+    {
+      nlldbg("Failed to bind SPI port %d ENCX24J600 device %d: %d\n",
+             ENCX24J600_SPI_PORTNO, ENCX24J600_DEVNO, ret);
+      return;
+    }
+
+  nllvdbg("Bound SPI port %d to ENCX24J600 device %d\n",
+          ENCX24J600_SPI_PORTNO, ENCX24J600_DEVNO);
+}
+
+#endif /* CONFIG_ENCX24J600 */
diff --git a/configs/olimex-stm32-p107/src/up_spi.c b/configs/olimex-stm32-p107/src/up_spi.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0e597d2236db9c0aa8ea0bf84c65e812063639e
--- /dev/null
+++ b/configs/olimex-stm32-p107/src/up_spi.c
@@ -0,0 +1,154 @@
+/************************************************************************************
+ * configs/olimex-stm32-p107/src/up_spi.c
+ *
+ *   Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************************/
+
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <debug.h>
+
+#include <nuttx/spi/spi.h>
+#include <arch/board/board.h>
+
+#include "up_arch.h"
+#include "chip.h"
+#include "stm32.h"
+#include "p107-internal.h"
+
+#if defined(CONFIG_STM32_SPI3)
+
+/************************************************************************************
+ * Definitions
+ ************************************************************************************/
+
+/* Enables debug output from this file (needs CONFIG_DEBUG too) */
+
+#undef SPI_DEBUG   /* Define to enable debug */
+#undef SPI_VERBOSE /* Define to enable verbose debug */
+
+#ifdef SPI_DEBUG
+#  define spidbg  lldbg
+#  ifdef SPI_VERBOSE
+#    define spivdbg lldbg
+#  else
+#    define spivdbg(x...)
+#  endif
+#else
+#  undef SPI_VERBOSE
+#  define spidbg(x...)
+#  define spivdbg(x...)
+#endif
+
+/************************************************************************************
+ * Private Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: stm32_spiinitialize
+ *
+ * Description:
+ *   Called to configure SPI chip select GPIO pins for the Olimex stm32-p107 board.
+ *
+ ************************************************************************************/
+
+void weak_function stm32_spiinitialize(void)
+{
+  /* NOTE: Clocking for SPI3 was already provided in stm32_rcc.c.
+   *       Configurations of SPI pins is performed in stm32_spi.c.
+   *       Here, we only initialize chip select pins unique to the board
+   *       architecture.
+   */
+
+  /* Configure ENCX24J600 SPI1 CS (also RESET and interrupt pins) */
+
+#if defined(CONFIG_ENCX24J600) && defined(CONFIG_STM32_SPI3)
+  stm32_configgpio(GPIO_ENCX24J600_CS);
+  stm32_configgpio(GPIO_ENCX24J600_INTR);
+#endif
+}
+
+/****************************************************************************
+ * Name:  stm32_spi1/2/3select and stm32_spi1/2/3status
+ *
+ * Description:
+ *   The external functions, stm32_spi1/2/3select and stm32_spi1/2/3status must be
+ *   provided by board-specific logic.  They are implementations of the select
+ *   and status methods of the SPI interface defined by struct spi_ops_s (see
+ *   include/nuttx/spi/spi.h). All other methods (including up_spiinitialize())
+ *   are provided by common STM32 logic.  To use this common SPI logic on your
+ *   board:
+ *
+ *   1. Provide logic in stm32_boardinitialize() to configure SPI chip select
+ *      pins.
+ *   2. Provide stm32_spi1/2/3select() and stm32_spi1/2/3status() functions in your
+ *      board-specific logic.  These functions will perform chip selection and
+ *      status operations using GPIOs in the way your board is configured.
+ *   3. Add a calls to up_spiinitialize() in your low level application
+ *      initialization logic
+ *   4. The handle returned by up_spiinitialize() may then be used to bind the
+ *      SPI driver to higher level logic (e.g., calling
+ *      mmcsd_spislotinitialize(), for example, will bind the SPI driver to
+ *      the SPI MMC/SD driver).
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_STM32_SPI3
+void stm32_spi3select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool selected)
+{
+  spidbg("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert");
+
+  if (devid == SPIDEV_ETHERNET)
+    {
+      /* Set the GPIO low to select and high to de-select */
+
+      stm32_gpiowrite(GPIO_ENCX24J600_CS, !selected);
+    }
+}
+
+uint8_t stm32_spi3status(FAR struct spi_dev_s *dev, enum spi_dev_e devid)
+{
+  return SPI_STATUS_PRESENT;
+}
+#endif
+
+#endif /* CONFIG_STM32_SPI3 */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d8878ecafd47cadcdd98e9516b689cab1a977cc4..346a51e60b8c67b3795dc011d7e018680a0a0d4c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -16,7 +16,7 @@ config NET_CS89x0
 	depends on EXPERIMENTAL
 	---help---
 	Under construction -- do not use
-	
+
 config ENC28J60
 	bool "Microchip ENC28J60 support"
 	default n
@@ -79,6 +79,62 @@ config ENC28J60_REGDEBUG
 
 endif
 
+config ENCX24J600
+	bool "Microchip ENCX24J600 support"
+	default n
+	select SPI
+	---help---
+		References:
+		ENC424J600/624J600 Data Sheet Stand-Alone 10/100 Ethernet Controller
+		with SPI or Parallel Interface DS39935B, 2009 Microchip Technology Inc.
+
+if ENCX24J600
+config ENC28J60_NINTERFACES
+	int "Number of physical ENCX24J600"
+	default 1
+	range 1,1
+	---help---
+		Specifies the number of physical ENCX24J600
+		devices that will be supported.
+
+config ENCX24J600_SPIMODE
+	int "SPI mode"
+	default 0
+	---help---
+		Controls the SPI mode.  The ENCX24J600 spec says that it supports SPI
+		mode 0,0 only: "The implementation used on this device supports SPI
+		mode 0,0 only. In addition, the SPI port requires that SCK be at Idle
+		in a low state; selectable clock polarity is not supported."
+		However, sometimes you need to tinker with these things.
+
+config ENCX24J600_FREQUENCY
+	int "SPI frequency"
+	default 14000000
+	---help---
+		Define to use a different bus frequency
+
+config ENCX24J600_STATS
+	bool "Network statistics support"
+	default n
+	---help---
+		Collect network statistics
+
+config ENCX24J600_DUMPPACKET
+	bool "Dump Packets"
+	default n
+	---help---
+		If selected, the ENCX24J600 driver  will dump the contents of each
+		packet to the console.
+
+config ENCX24J600_REGDEBUG
+	bool "Register-Level Debug"
+	default n
+	depends on DEBUG && DEBUG_NET
+	---help---
+		Enable very low-level register access debug.  Depends on DEBUG and DEBUG_NET.
+
+endif
+
 config NET_E1000
 	bool "E1000 support"
 	default n
@@ -86,7 +142,7 @@ config NET_E1000
 config NET_SLIP
 	bool "SLIP (serial line) support"
 	default n
-	---help---	
+	---help---
 		Reference: RFC 1055
 
 config NET_VNET
diff --git a/drivers/net/Make.defs b/drivers/net/Make.defs
index bb0d6a71891c27db372fe1844645e01dd6dc45f0..3d34aa9715d415623ff41fd0c0690e61f7a1eb90 100644
--- a/drivers/net/Make.defs
+++ b/drivers/net/Make.defs
@@ -51,6 +51,10 @@ ifeq ($(CONFIG_ENC28J60),y)
   CSRCS += enc28j60.c
 endif
 
+ifeq ($(CONFIG_ENCX24J600),y)
+  CSRCS += encx24j600.c
+endif
+
 ifeq ($(CONFIG_NET_VNET),y)
   CSRCS += vnet.c
 endif
diff --git a/drivers/net/encx24j600.c b/drivers/net/encx24j600.c
new file mode 100644
index 0000000000000000000000000000000000000000..6efef1a7a9d8818e21817309f1bbdf27a439ee59
--- /dev/null
+++ b/drivers/net/encx24j600.c
@@ -0,0 +1,2382 @@
+/****************************************************************************
+ * drivers/net/encx24j600.c
+ *
+ *   Copyright (C) 2013 UVC Ingenieure. All rights reserved.
+ *   Author: Max Holtberg <mh@uvc.de>
+ *
+ * References:
+ * - ENC424J600/624J600 Data Sheet, Stand-Alone 10/100 Ethernet Controller
+ *   with SPI or Parallel Interface, DS39935C, 2010 Microchip Technology Inc.
+ *
+ * Derived from enc28j60 driver written by:
+ *
+ *   Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#if defined(CONFIG_NET) && defined(CONFIG_ENCX24J600)
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <time.h>
+#include <string.h>
+#include <debug.h>
+#include <wdog.h>
+#include <errno.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/clock.h>
+#include <nuttx/net/encx24j600.h>
+
+#include <nuttx/net/uip/uip.h>
+#include <nuttx/net/uip/uip-arp.h>
+#include <nuttx/net/uip/uip-arch.h>
+
+#include "encx24j600.h"
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+/* ENCX24J600 Configuration Settings:
+ *
+ * CONFIG_ENCX24J600 - Enabled ENCX24J600 support
+ * CONFIG_ENCX24J600_SPIMODE - Controls the SPI mode
+ * CONFIG_ENCX24J600_FREQUENCY - Define to use a different bus frequency
+ * CONFIG_ENCX24J600_NINTERFACES - Specifies the number of physical ENCX24J600
+ *   devices that will be supported.
+ * CONFIG_ENCX24J600_STATS - Collect network statistics
+ */
+
+/* The ENCX24J600 spec says that it supports SPI mode 0,0 only: "The
+ * implementation used on this device supports SPI mode 0,0 only. In
+ * addition, the SPI port requires that SCK be at Idle in a low state;
+ * selectable clock polarity is not supported."  However, sometimes you
+ * need to tinker with these things.
+ */
+
+#ifndef CONFIG_ENCX24J600_SPIMODE
+#  define CONFIG_ENCX24J600_SPIMODE SPIDEV_MODE0
+#endif
+
+/* CONFIG_ENCX24J600_NINTERFACES determines the number of physical interfaces
+ * that will be supported.
+ */
+
+#ifndef CONFIG_ENCX24J600_NINTERFACES
+#  define CONFIG_ENCX24J600_NINTERFACES 1
+#endif
+
+/* CONFIG_NET_BUFSIZE must always be defined */
+
+#if !defined(CONFIG_NET_BUFSIZE) && (CONFIG_NET_BUFSIZE <= MAX_FRAMELEN)
+#  error "CONFIG_NET_BUFSIZE is not valid for the ENCX24J600"
+#endif
+
+/* We need to have the work queue to handle SPI interrupts */
+
+#ifndef CONFIG_SCHED_WORKQUEUE
+#  error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
+/* CONFIG_ENCX24J600_DUMPPACKET will dump the contents of each packet to the console. */
+
+#ifdef CONFIG_ENCX24J600_DUMPPACKET
+#  define enc_dumppacket(m,a,n) lib_dumpbuffer(m,a,n)
+#else
+#  define enc_dumppacket(m,a,n)
+#endif
+
+/* The ENCX24J600 will not do interrupt level processing */
+
+#ifndef CONFIG_NET_NOINTS
+#  warning "CONFIG_NET_NOINTS should be set"
+#endif
+
+/* Low-level register debug */
+
+#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_NET)
+#  undef CONFIG_ENCX24J600_REGDEBUG
+#endif
+
+/* Timing *******************************************************************/
+
+/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
+
+#define ENC_WDDELAY   (1*CLK_TCK)
+#define ENC_POLLHSEC  (1*2)
+
+/* TX timeout = 1 minute */
+
+#define ENC_TXTIMEOUT (60*CLK_TCK)
+
+/* Poll timeout */
+
+#define ENC_POLLTIMEOUT MSEC2TICK(50)
+
+/* Packet Memory ************************************************************/
+
+/* Packet memory layout */
+
+#define ALIGNED_BUFSIZE ((CONFIG_NET_BUFSIZE + 1) & ~1)   /* Address has to be even */
+#define PKTMEM_TX_START PKTMEM_START                      /* Start TX buffer at teh beginning of SRAM */
+#define PKTMEM_TX_ENDP1 ALIGNED_BUFSIZE                   /* Allow TX buffer for one frame */
+#define PKTMEM_RX_START PKTMEM_TX_ENDP1                   /* Followed by RX buffer */
+#define PKTMEM_RX_END   (PKTMEM_END - 1)                  /* RX buffer goes to the end of SRAM */
+
+/* This is a helper pointer for accessing the contents of the Ethernet header */
+
+#define BUF ((struct uip_eth_hdr *)priv->dev.d_buf)
+
+/* Debug ********************************************************************/
+
+#ifdef CONFIG_ENCX24J600_REGDEBUG
+#  define enc_wrdump(a,v)   lowsyslog("ENCX24J600: %02x<-%04x\n", a, v);
+#  define enc_rddump(a,v)   lowsyslog("ENCX24J600: %02x->%04x\n", a, v);
+#  define enc_bfsdump(a,m)  lowsyslog("ENCX24J600: %02x|=%04x\n", a, m);
+#  define enc_bfcdump(a,m)  lowsyslog("ENCX24J600: %02x&=~%04x\n", a, m);
+#  define enc_cmddump(c)    lowsyslog("ENCX24J600: CMD: %02x\n", c);
+#  define enc_bmdump(c,b,s) lowsyslog("ENCX24J600: CMD: %02x buffer: %p length: %d\n", c,b,s);
+#else
+#  define enc_wrdump(a,v)
+#  define enc_rddump(a,v)
+#  define enc_bfsdump(a,m)
+#  define enc_bfcdump(a,m)
+#  define enc_cmddump(c)
+#  define enc_bmdump(c,b,s)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The state of the interface */
+
+enum enc_state_e
+{
+  ENCSTATE_UNINIT = 0,                /* The interface is in an uninitialized state */
+  ENCSTATE_DOWN,                      /* The interface is down */
+  ENCSTATE_UP                         /* The interface is up */
+};
+
+/* The enc_driver_s encapsulates all state information for a single hardware
+ * interface
+ */
+
+struct enc_driver_s
+{
+  /* Device control */
+
+  uint8_t               ifstate;       /* Interface state:  See ENCSTATE_* */
+  uint8_t               bank;          /* Currently selected bank command */
+  uint16_t              nextpkt;       /* Next packet address */
+  FAR const struct enc_lower_s *lower; /* Low-level MCU-specific support */
+
+  /* Timing */
+
+  WDOG_ID               txpoll;        /* TX poll timer */
+  WDOG_ID               txtimeout;     /* TX timeout timer */
+
+  /* If we don't own the SPI bus, then we cannot do SPI accesses from the
+   * interrupt handler.
+   */
+
+  struct work_s         irqwork;       /* Interrupt continuation work queue support */
+  struct work_s         towork;        /* Tx timeout work queue support */
+  struct work_s         pollwork;      /* Poll timeout work queue support */
+
+  /* This is the contained SPI driver intstance */
+
+  FAR struct spi_dev_s *spi;
+
+  /* This holds the information visible to uIP/NuttX */
+
+  struct uip_driver_s   dev;          /* Interface understood by uIP */
+
+  /* Statistics */
+
+#ifdef CONFIG_ENCX24J600_STATS
+  struct enc_stats_s    stats;
+#endif
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct enc_driver_s g_encx24j600[CONFIG_ENCX24J600_NINTERFACES];
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Low-level SPI helpers */
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void enc_configspi(FAR struct spi_dev_s *spi);
+#  define enc_lock(priv);
+#  define enc_unlock(priv);
+#else
+#  define enc_configspi(spi)
+static void enc_lock(FAR struct enc_driver_s *priv);
+static inline void enc_unlock(FAR struct enc_driver_s *priv);
+#endif
+
+/* SPI control register access */
+
+static inline void enc_setethrst(FAR struct enc_driver_s *priv);
+static void enc_setbank(FAR struct enc_driver_s *priv, uint8_t bank);
+static uint16_t enc_rdreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg);
+static void enc_wrreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                         uint16_t wrdata);
+static int enc_waitreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                          uint16_t bits, uint16_t value);
+static void enc_bfs(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                    uint16_t bits);
+static void enc_bfc(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                    uint16_t bits);
+static void enc_cmd(FAR struct enc_driver_s *priv, uint8_t cmd, uint16_t arg);
+
+#if 0 /* Sometimes useful */
+static void enc_rxdump(FAR struct enc_driver_s *priv);
+static void enc_txdump(FAR struct enc_driver_s *priv);
+#endif
+
+/* SPI buffer transfers */
+
+static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer,
+         size_t buflen);
+static inline void enc_wrbuffer(FAR struct enc_driver_s *priv,
+         FAR const uint8_t *buffer, size_t buflen);
+
+/* PHY register access */
+
+static uint16_t enc_rdphy(FAR struct enc_driver_s *priv, uint8_t phyaddr);
+static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr,
+         uint16_t phydata);
+
+/* Common TX logic */
+
+static int  enc_transmit(FAR struct enc_driver_s *priv);
+static int  enc_uiptxpoll(struct uip_driver_s *dev);
+
+/* Interrupt handling */
+
+static void enc_linkstatus(FAR struct enc_driver_s *priv);
+static void enc_txif(FAR struct enc_driver_s *priv);
+static void enc_rxdispatch(FAR struct enc_driver_s *priv);
+static void enc_pktif(FAR struct enc_driver_s *priv);
+static void enc_irqworker(FAR void *arg);
+static int  enc_interrupt(int irq, FAR void *context);
+
+/* Watchdog timer expirations */
+
+static void enc_toworker(FAR void *arg);
+static void enc_txtimeout(int argc, uint32_t arg, ...);
+static void enc_pollworker(FAR void *arg);
+static void enc_polltimer(int argc, uint32_t arg, ...);
+
+/* NuttX callback functions */
+
+static int  enc_ifup(struct uip_driver_s *dev);
+static int  enc_ifdown(struct uip_driver_s *dev);
+static int  enc_txavail(struct uip_driver_s *dev);
+#ifdef CONFIG_NET_IGMP
+static int  enc_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
+static int  enc_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac);
+#endif
+
+/* Initialization */
+
+static void enc_pwrsave(FAR struct enc_driver_s *priv);
+static void enc_setmacaddr(FAR struct enc_driver_s *priv);
+static int  enc_reset(FAR struct enc_driver_s *priv);
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: enc_configspi
+ *
+ * Description:
+ *   Configure the SPI for use with the ENCX24J600
+ *
+ * Parameters:
+ *   spi  - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void enc_configspi(FAR struct spi_dev_s *spi)
+{
+  /* Configure SPI for the ENCX24J600.  But only if we own the SPI bus.
+   * Otherwise, don't bother because it might change.
+   */
+
+  SPI_SETMODE(spi, CONFIG_ENCX24J600_SPIMODE);
+  SPI_SETBITS(spi, 8);
+  SPI_SETFREQUENCY(spi, CONFIG_ENCX24J600_FREQUENCY)
+}
+#endif
+
+/****************************************************************************
+ * Function: enc_lock
+ *
+ * Description:
+ *   Select the SPI, locking and  re-configuring if necessary
+ *
+ * Parameters:
+ *   spi  - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_OWNBUS
+static void enc_lock(FAR struct enc_driver_s *priv)
+{
+  /* Lock the SPI bus in case there are multiple devices competing for the SPI
+   * bus.
+   */
+
+  SPI_LOCK(priv->spi, true);
+
+  /* Now make sure that the SPI bus is configured for the ENCX24J600 (it
+   * might have gotten configured for a different device while unlocked)
+   */
+
+  SPI_SETMODE(priv->spi, CONFIG_ENCX24J600_SPIMODE);
+  SPI_SETBITS(priv->spi, 8);
+  SPI_SETFREQUENCY(priv->spi, CONFIG_ENCX24J600_FREQUENCY);
+}
+#endif
+
+/****************************************************************************
+ * Function: enc_unlock
+ *
+ * Description:
+ *   De-select the SPI
+ *
+ * Parameters:
+ *   spi  - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_OWNBUS
+static inline void enc_unlock(FAR struct enc_driver_s *priv)
+{
+  /* Relinquish the lock on the bus. */
+
+  SPI_LOCK(priv->spi, false);
+}
+#endif
+
+/****************************************************************************
+ * Function: enc_cmd
+ *
+ * Description:
+ *   Execute two byte command.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   cmd     - ENCX24J600 two-byte command
+ *   arg     - Two byte argument to the command
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_cmd(FAR struct enc_driver_s *priv, uint8_t cmd, uint16_t arg)
+{
+  DEBUGASSERT(priv && priv->spi);
+
+  /* Select ENCX24J600 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);;
+
+  (void)SPI_SEND(priv->spi, cmd);          /* Clock out the command */
+  (void)SPI_SEND(priv->spi, arg & 0xff);   /* clock out the low byte */
+  (void)SPI_SEND(priv->spi, arg >> 8);     /* clock out the high byte */
+
+  /* De-select ENCX24J600 chip. */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_wrdump(cmd, arg);
+}
+
+/****************************************************************************
+ * Function: enc_setethrst
+ *
+ * Description:
+ *   Issues System Reset by setting ETHRST (ECON2<4>)
+ *
+ * Parameters:
+ *   priv   - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static inline void enc_setethrst(FAR struct enc_driver_s *priv)
+{
+  DEBUGASSERT(priv && priv->spi);
+
+  /* Select ENC28J60 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);;
+
+  /* Send the system reset command. */
+
+  (void)SPI_SEND(priv->spi, ENC_SETETHRST);
+
+  up_udelay(25);
+
+  /* De-select ENC28J60 chip. */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_cmddump(ENC_SETETHRST);
+}
+
+/****************************************************************************
+ * Function: enc_setbank
+ *
+ * Description:
+ *   Set the bank for the next control register access.
+ *
+ * Assumption:
+ *   The caller has exclusive access to the SPI bus
+ *
+ * Parameters:
+ *   priv   - Reference to the driver state structure
+ *   bank   - SPI command to select the bank with
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The chip is selected and SPI is ready for communication.
+ *
+ ****************************************************************************/
+
+static void enc_setbank(FAR struct enc_driver_s *priv, uint8_t bank)
+{
+
+  /* Check if a bank has to be set and if the bank setting has changed.
+   * For registers that are available on all banks, the bank command is set to 0.
+   */
+
+  if (bank != 0 && bank != priv->bank)
+    {
+      /* Select bank with supplied command */
+
+      SPI_SEND(priv->spi, bank);
+
+      /* Then remember the bank setting */
+
+      priv->bank = bank;
+    }
+}
+
+/****************************************************************************
+ * Function: enc_rdreg
+ *
+ * Description:
+ *   Read one word from a control register using the RCR command.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   ctrlreg - Bit encoded address of banked register to read
+ *
+ * Returned Value:
+ *   The byte read from the banked register
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static uint16_t enc_rdreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg)
+{
+  uint16_t rddata;
+
+  DEBUGASSERT(priv && priv->spi);
+  DEBUGASSERT((ctrlreg & 0xe0) == 0); /* banked regeitsers only */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);
+
+  enc_setbank(priv, GETBANK(ctrlreg));
+
+  SPI_SEND(priv->spi, ENC_RCR | GETADDR(ctrlreg));
+
+  rddata = SPI_SEND(priv->spi, 0);        /* clock in the low byte */
+  rddata |= SPI_SEND(priv->spi, 0) << 8;  /* clock in the high byte */
+
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_rddump(GETADDR(ctrlreg), rddata);
+
+  return rddata;
+}
+
+/****************************************************************************
+ * Function: enc_wrreg
+ *
+ * Description:
+ *   Write one word to a control register using the WCR command.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   ctrlreg - Bit encoded address of banked register to write
+ *   wrdata  - The data to send
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_wrreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                      uint16_t wrdata)
+{
+  DEBUGASSERT(priv && priv->spi);
+  DEBUGASSERT((ctrlreg & 0xe0) == 0); /* banked regeitsers only */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);;
+
+  enc_setbank(priv, GETBANK(ctrlreg));
+
+  SPI_SEND(priv->spi, ENC_WCR | GETADDR(ctrlreg));
+  SPI_SEND(priv->spi, wrdata & 0xff); /* clock out the low byte */
+  SPI_SEND(priv->spi, wrdata >> 8);   /* clock out the high byte */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_wrdump(GETADDR(ctrlreg), wrdata);
+}
+
+/****************************************************************************
+ * Function: enc_waitbreg
+ *
+ * Description:
+ *   Wait until banked register bit(s) take a specific value (or a timeout
+ *   occurs).
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   ctrlreg - Bit encoded address of banked register to check
+ *   bits    - The bits to check (a mask)
+ *   value   - The value of the bits to return (value under mask)
+ *
+ * Returned Value:
+ *   OK on success, negated errno on failure
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int enc_waitreg(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                          uint16_t bits, uint16_t value)
+{
+  uint32_t start = clock_systimer();
+  uint32_t elapsed;
+  uint16_t rddata;
+
+  /* Loop until the exit condition is met */
+
+  do
+    {
+      /* Read the byte from the requested banked register */
+
+      rddata  = enc_rdreg(priv, ctrlreg);
+      elapsed = clock_systimer() - start;
+    }
+  while ((rddata & bits) != value || elapsed > ENC_POLLTIMEOUT);
+
+  return (rddata & bits) == value ? OK : -ETIMEDOUT;
+}
+
+/****************************************************************************
+ * Function: enc_bfs
+ *
+ * Description:
+ *   Bit Field Set.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   ctrlreg - Bit encoded address of banked register to set bits in
+ *   bits    - The bits to set (a mask)
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_bfs(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                    uint16_t bits)
+{
+  DEBUGASSERT(priv && priv->spi);
+
+  /* Select ENCX24J600 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);;
+
+  /* Set the bank */
+
+  enc_setbank(priv, GETBANK(ctrlreg));
+
+  /* Send the BFS command and data.  The sequence requires 24-clocks:
+   * 8 to clock out the cmd + 16 to clock out the data.
+   */
+
+  (void)SPI_SEND(priv->spi, ENC_BFS | GETADDR(ctrlreg)); /* Clock out the command */
+  (void)SPI_SEND(priv->spi, bits & 0xff);                /* clock out the low byte */
+  (void)SPI_SEND(priv->spi, bits >> 8);                  /* clock out the high byte */
+
+  /* De-select ENCX24J600 chip. */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_bfsdump(GETADDR(ctrlreg), bits);
+}
+
+/****************************************************************************
+ * Function: enc_bfc
+ *
+ * Description:
+ *   Bit Field Clear.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   ctrlreg - Bit encoded address of banked register to clear bits in
+ *   bits    - The bits to clear (a mask)
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_bfc(FAR struct enc_driver_s *priv, uint16_t ctrlreg,
+                    uint16_t bits)
+{
+  DEBUGASSERT(priv && priv->spi);
+
+  /* Select ENCX24J600 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);;
+
+  /* Set the bank */
+
+  enc_setbank(priv, GETBANK(ctrlreg));
+
+  /* Send the BFC command and data. The sequence requires 24-clocks:
+   * 8 to clock out the cmd + 16 to clock out the data.
+   */
+
+  (void)SPI_SEND(priv->spi, ENC_BFC | GETADDR(ctrlreg)); /* Clock out the command */
+  (void)SPI_SEND(priv->spi, bits & 0xff);                /* clock out the low byte */
+  (void)SPI_SEND(priv->spi, bits >> 8);                  /* clock out the high byte */
+
+  /* De-select ENCX24J600 chip. */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_bfcdump(GETADDR(ctrlreg), bits);
+}
+
+/****************************************************************************
+ * Function: enc_txdump enc_rxdump
+ *
+ * Description:
+ *   Dump registers associated with receiving or sending packets.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#if 0 /* Sometimes useful */
+static void enc_rxdump(FAR struct enc_driver_s *priv)
+{
+  lowsyslog("Rx Registers:\n");
+  lowsyslog("  EIE:      %02x EIR:      %02x\n",
+            enc_rdgreg(priv, ENC_EIE), enc_rdgreg(priv, ENC_EIR));
+  lowsyslog("  ESTAT:    %02x ECON1:    %02x ECON2:    %02x\n",
+            enc_rdgreg(priv, ENC_ESTAT), enc_rdgreg(priv, ENC_ECON1),
+            enc_rdgreg(priv, ENC_ECON2));
+  lowsyslog("  ERXST:    %02x %02x\n",
+            enc_rdbreg(priv, ENC_ERXSTH), enc_rdbreg(priv, ENC_ERXSTL));
+  lowsyslog("  ERXND:    %02x %02x\n",
+            enc_rdbreg(priv, ENC_ERXNDH), enc_rdbreg(priv, ENC_ERXNDL));
+  lowsyslog("  ERXRDPT:  %02x %02x\n",
+            enc_rdbreg(priv, ENC_ERXRDPTH), enc_rdbreg(priv, ENC_ERXRDPTL));
+  lowsyslog("  ERXFCON:  %02x EPKTCNT:  %02x\n",
+            enc_rdbreg(priv, ENC_ERXFCON), enc_rdbreg(priv, ENC_EPKTCNT));
+  lowsyslog("  MACON1:   %02x MACON3:   %02x\n",
+            enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3));
+  lowsyslog("  MAMXFL:   %02x %02x\n",
+            enc_rdbreg(priv, ENC_MAMXFLH), enc_rdbreg(priv, ENC_MAMXFLL));
+  lowsyslog("  MAADR:    %02x:%02x:%02x:%02x:%02x:%02x\n",
+            enc_rdbreg(priv, ENC_MAADR1), enc_rdbreg(priv, ENC_MAADR2),
+            enc_rdbreg(priv, ENC_MAADR3), enc_rdbreg(priv, ENC_MAADR4),
+            enc_rdbreg(priv, ENC_MAADR5), enc_rdbreg(priv, ENC_MAADR6));
+}
+#endif
+
+#if 0 /* Sometimes useful */
+static void enc_txdump(FAR struct enc_driver_s *priv)
+{
+  lowsyslog("Tx Registers:\n");
+  lowsyslog("  EIE:      %02x EIR:      %02x ESTAT:    %02x\n",
+            enc_rdgreg(priv, ENC_EIE), enc_rdgreg(priv, ENC_EIR),);
+  lowsyslog("  ESTAT:    %02x ECON1:    %02x\n",
+            enc_rdgreg(priv, ENC_ESTAT), enc_rdgreg(priv, ENC_ECON1));
+  lowsyslog("  ETXST:    %02x %02x\n",
+            enc_rdbreg(priv, ENC_ETXSTH), enc_rdbreg(priv, ENC_ETXSTL));
+  lowsyslog("  ETXND:    %02x %02x\n",
+            enc_rdbreg(priv, ENC_ETXNDH), enc_rdbreg(priv, ENC_ETXNDL));
+  lowsyslog("  MACON1:   %02x MACON3:   %02x MACON4:   %02x\n",
+            enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3),
+            enc_rdbreg(priv, ENC_MACON4));
+  lowsyslog("  MACON1:   %02x MACON3:   %02x MACON4:   %02x\n",
+            enc_rdbreg(priv, ENC_MACON1), enc_rdbreg(priv, ENC_MACON3),
+            enc_rdbreg(priv, ENC_MACON4));
+  lowsyslog("  MABBIPG:  %02x MAIPG %02x %02x\n",
+            enc_rdbreg(priv, ENC_MABBIPG), enc_rdbreg(priv, ENC_MAIPGH),
+            enc_rdbreg(priv, ENC_MAIPGL));
+  lowsyslog("  MACLCON1: %02x MACLCON2:   %02x\n",
+            enc_rdbreg(priv, ENC_MACLCON1), enc_rdbreg(priv, ENC_MACLCON2));
+  lowsyslog("  MAMXFL:   %02x %02x\n",
+            enc_rdbreg(priv, ENC_MAMXFLH), enc_rdbreg(priv, ENC_MAMXFLL));
+}
+#endif
+
+/****************************************************************************
+ * Function: enc_rdbuffer
+ *
+ * Description:
+ *   Read a buffer of data from RX Data Buffer.
+ *
+ * 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
+ *
+ * Assumptions:
+ *   RX Data pointer is set to the correct address
+ *
+ ****************************************************************************/
+
+static void enc_rdbuffer(FAR struct enc_driver_s *priv, FAR uint8_t *buffer,
+                         size_t buflen)
+{
+  DEBUGASSERT(priv && priv->spi);
+
+  /* Select ENCX24J600 chip */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);
+
+  /* Send the read buffer memory command (ignoring the response) */
+
+  (void)SPI_SEND(priv->spi, ENC_RRXDATA);
+
+  /* Then read the buffer data */
+
+  SPI_RECVBLOCK(priv->spi, buffer, buflen);
+
+  /* De-select ENCX24J600 chip. */
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_bmdump(ENC_RRXDATA, buffer, buflen);
+}
+
+/****************************************************************************
+ * Function: enc_wrbuffer
+ *
+ * Description:
+ *   Write a buffer of data.
+ *
+ * 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
+ *
+ * Assumptions:
+ *   General Purpose Write pointer is set to the correct address
+ *
+ ****************************************************************************/
+
+static inline void enc_wrbuffer(FAR struct enc_driver_s *priv,
+                                FAR const uint8_t *buffer, size_t buflen)
+{
+  DEBUGASSERT(priv && priv->spi);
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, true);;
+
+  SPI_SEND(priv->spi, ENC_WGPDATA);
+  SPI_SNDBLOCK(priv->spi, buffer, buflen);
+
+  SPI_SELECT(priv->spi, SPIDEV_ETHERNET, false);
+  enc_bmdump(ENC_WGPDATA, buffer, buflen);
+}
+
+/****************************************************************************
+ * Function: enc_rdphy
+ *
+ * Description:
+ *   Read 16-bits of PHY data.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   phyaddr - The PHY register address
+ *
+ * Returned Value:
+ *   16-bit value read from the PHY
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static uint16_t enc_rdphy(FAR struct enc_driver_s *priv, uint8_t phyaddr)
+{
+  uint16_t data = 0;
+
+  /* "To read from a PHY register:
+   *   1. Write the address of the PHY register to read from into the MIREGADR
+   *      register (Register 3-1). Make sure to also set reserved bit 8 of this
+   *      register.
+   */
+
+  enc_wrreg(priv, ENC_MIREGADR, phyaddr);
+
+  /*   2. Set the MIIRD bit (MICMD<0>, Register 3-2). The read operation begins
+   *      and the BUSY bit (MISTAT<0>, Register 3-3) is automatically set by
+   *      hardware.
+   */
+
+  enc_bfs(priv, ENC_MICMD, MICMD_MIIRD);
+
+  /*   3. Wait 25.6 μs. Poll the BUSY (MISTAT<0>) bit to be certain that the
+   *      operation is complete. While busy, the host controller should not
+   *      start any MIISCAN operations or write to the MIWR register. When the
+   *      MAC has obtained the register contents, the BUSY bit will clear
+   *      itself.
+   */
+
+  up_udelay(26);
+  if (enc_waitreg(priv, ENC_MISTAT, MISTAT_BUSY, 0x00) == OK)
+    {
+      /* 4. Clear the MIIRD (MICMD<0>) bit. */
+
+      enc_bfc(priv, ENC_MICMD, MICMD_MIIRD);
+
+      /* 5. Read the desired data from the MIRD register. For 8-bit interfaces,
+       *    the order that these bytes are read is unimportant."
+       */
+
+      data = enc_rdreg(priv, ENC_MIRD);
+    }
+
+  return data;
+}
+
+/****************************************************************************
+ * Function: enc_wrphy
+ *
+ * Description:
+ *   write 16-bits of PHY data.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *   phyaddr - The PHY register address
+ *   phydata - 16-bit data to write to the PHY
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_wrphy(FAR struct enc_driver_s *priv, uint8_t phyaddr,
+                      uint16_t phydata)
+{
+  /* "To write to a PHY register:
+   *
+   *    1. Write the address of the PHY register to write to into the MIREGADR
+   *       register. Make sure to also set reserved bit 8 of this register.
+   */
+
+  enc_wrreg(priv, ENC_MIREGADR, 0x0100 | phyaddr);
+
+  /*    2. Write the 16 bits of data into the MIWR register. The low byte must
+   *       be written first, followed by the high byte.
+   */
+
+  enc_wrreg(priv, ENC_MIWR, phydata);
+
+  /*    3. Writing to the high byte of MIWR begins the MIIM transaction and the
+   *       BUSY (MISTAT<0>) bit is automatically set by hardware.
+   *
+   * The PHY register is written after the MIIM operation completes, which takes
+   * 25.6 μs. When the write operation has completed, the BUSY bit clears
+   * itself. The host controller should not start any MIISCAN, MIWR or MIIRD
+   * operations while the BUSY bit is set.
+   */
+
+  up_udelay(26);
+  enc_waitreg(priv, ENC_MISTAT, MISTAT_BUSY, 0);
+}
+
+/****************************************************************************
+ * Function: enc_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.
+ *
+ * Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int enc_transmit(FAR struct enc_driver_s *priv)
+{
+  /* Increment statistics */
+
+  nllvdbg("Sending packet, pktlen: %d\n", priv->dev.d_len);
+
+#ifdef CONFIG_ENCX24J600_STATS
+  priv->stats.txrequests++;
+#endif
+
+  /* Verify that the hardware is ready to send another packet.  The driver
+   * starts a transmission process by setting ECON1.TXRTS. When the packet is
+   * finished transmitting or is aborted due to an error/cancellation, the
+   * ECON1.TXRTS bit will be cleared.
+   *
+   * NOTE: If we got here, then we have committed to sending a packet.
+   * higher level logic must have assured that (1) there is no transmission
+   * in progress, and that (2) TX-related interrupts are disabled.
+   */
+
+  DEBUGASSERT((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0);
+
+  /* Send the packet: address=priv->dev.d_buf, length=priv->dev.d_len */
+
+  enc_dumppacket("Transmit Packet", priv->dev.d_buf, priv->dev.d_len);
+
+  /* copy the packet into the transmit buffer */
+
+  enc_cmd(priv, ENC_WGPWRPT, PKTMEM_TX_START);
+  enc_wrbuffer(priv, priv->dev.d_buf, priv->dev.d_len);
+
+  /* Set TX Len registers. TX Start is set in enc_reset  */
+
+  enc_wrreg(priv, ENC_ETXLEN, priv->dev.d_len);
+
+
+  /* Set TXRTS to send the packet in the transmit buffer */
+
+  enc_bfs(priv, ENC_ECON1, ECON1_TXRTS);
+
+  /* Setup the TX timeout watchdog (perhaps restarting the timer).  Note:
+   * Is there a race condition.  Could the TXIF interrupt occur before
+   * the timer is started?
+   */
+
+  (void)wd_start(priv->txtimeout, ENC_TXTIMEOUT, enc_txtimeout, 1, (uint32_t)priv);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: enc_uiptxpoll
+ *
+ * Description:
+ *   The transmitter is available, check if uIP has any outgoing packets ready
+ *   to send.  This is a callback from uip_poll().  uip_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send timedout and the interface is reset
+ *   3. During normal TX polling
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   Interrupts are enabled but the caller holds the uIP lock.
+ *
+ ****************************************************************************/
+
+static int enc_uiptxpoll(struct uip_driver_s *dev)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  nllvdbg("Poll result: d_len=%d\n", priv->dev.d_len);
+  if (priv->dev.d_len > 0)
+    {
+      uip_arp_out(&priv->dev);
+      enc_transmit(priv);
+
+      /* Stop the poll now because we can queue only one packet */
+
+      return -EBUSY;
+    }
+
+  /* If zero is returned, the polling will continue until all connections have
+   * been examined.
+   */
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: enc_linkstatus
+ *
+ * Description:
+ *   The current link status can be obtained from the PHSTAT1.LLSTAT or
+ *   PHSTAT2.LSTAT.
+ *
+ * Parameters:
+ *   priv    - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_linkstatus(FAR struct enc_driver_s *priv)
+{
+  uint16_t regval;
+
+  /* Before transmitting the first packet after link establishment or
+   * auto-negotiation, the MAC duplex configuration must be manually set to
+   * match the duplex configuration of the PHY. To do this, configure
+   * FULDPX (MACON2<0>) to match PHYDPX (ESTAT<10>).
+   */
+
+  regval = enc_rdphy(priv, ENC_ESTAT);
+
+  if (regval & ESTAT_PHYDPX)
+    {
+      /* configure full-duplex */
+
+      enc_wrreg(priv, ENC_MABBIPG, 0x15);
+      enc_bfs(priv, ENC_MACON2, MACON2_FULDPX);
+    }
+  else
+    {
+      /* configure half-duplex */
+
+      enc_wrreg(priv, ENC_MABBIPG, 0x12);
+      enc_bfc(priv, ENC_MACON2, MACON2_FULDPX);
+    }
+}
+
+/****************************************************************************
+ * Function: enc_txif
+ *
+ * Description:
+ *   An TXIF interrupt was received indicating that the last TX packet(s) is
+ *   done
+ *
+ * Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Interrupts are enabled but the caller holds the uIP lock.
+ *
+ ****************************************************************************/
+
+static void enc_txif(FAR struct enc_driver_s *priv)
+{
+  /* If no further xmits are pending, then cancel the TX timeout */
+
+  wd_cancel(priv->txtimeout);
+
+  /* Then poll uIP for new XMIT data */
+
+  (void)uip_poll(&priv->dev, enc_uiptxpoll);
+}
+
+/****************************************************************************
+ * Function: enc_rxdispatch
+ *
+ * Description:
+ *   Give the newly received packet to uIP.
+ *
+ * Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Interrupts are enabled but the caller holds the uIP lock.
+ *
+ ****************************************************************************/
+
+static void enc_rxdispatch(FAR struct enc_driver_s *priv)
+{
+ /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv6
+  if (BUF->type == HTONS(UIP_ETHTYPE_IP6))
+#else
+  if (BUF->type == HTONS(UIP_ETHTYPE_IP))
+#endif
+    {
+      nllvdbg("IP packet received (%02x)\n", BUF->type);
+      uip_arp_ipin(&priv->dev);
+      uip_input(&priv->dev);
+
+      /* If the above function invocation resulted in data that should be
+       * sent out on the network, the field  d_len will set to a value > 0.
+       */
+
+      if (priv->dev.d_len > 0)
+        {
+          uip_arp_out(&priv->dev);
+          enc_transmit(priv);
+        }
+    }
+  else if (BUF->type == htons(UIP_ETHTYPE_ARP))
+    {
+      nllvdbg("ARP packet received (%02x)\n", BUF->type);
+      uip_arp_arpin(&priv->dev);
+
+      /* If the above function invocation resulted in data that should be
+       * sent out on the network, the field  d_len will set to a value > 0.
+       */
+
+       if (priv->dev.d_len > 0)
+         {
+           enc_transmit(priv);
+         }
+     }
+  else
+    {
+      nlldbg("Unsupported packet type dropped (%02x)\n", htons(BUF->type));
+    }
+}
+
+/****************************************************************************
+ * Function: enc_pktif
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Interrupts are enabled but the caller holds the uIP lock.
+ *
+ ****************************************************************************/
+
+static void enc_pktif(FAR struct enc_driver_s *priv)
+{
+  uint8_t  rsv[8];
+  uint16_t pktlen;
+  uint32_t rxstat;
+
+  DEBUGASSERT(priv->nextpkt >= PKTMEM_RX_START && priv->nextpkt <= PKTMEM_RX_END);
+
+  /* Set the rx data pointer to the start of the received packet (ERXRDPT) */
+
+  enc_cmd(priv, ENC_WRXRDPT, priv->nextpkt);
+
+  /* Read the next packet pointer and the 6 byte read status vector (RSV)
+   * at the beginning of the received packet. (ERXRDPT should auto-increment
+   * and wrap to the beginning of the read buffer as necessary)
+   */
+
+  enc_rdbuffer(priv, rsv, 8);
+
+  /* Decode the new next packet pointer, and the RSV.  The
+   * RSV is encoded as:
+   *
+   *  Bits 0-15:  Indicates length of the received frame. This includes the
+   *              destination address, source address, type/length, data,
+   *              padding and CRC fields. This field is stored in little-
+   *              endian format.
+   *  Bits 16-47: Bit encoded RX status.
+   */
+
+  priv->nextpkt = (uint16_t)rsv[1] << 8  | (uint16_t)rsv[0];
+  pktlen        = (uint16_t)rsv[3] << 8  | (uint16_t)rsv[2];
+  rxstat        = (uint32_t)rsv[7] << 24 | (uint32_t)rsv[6] << 16 |
+                  (uint32_t)rsv[5] << 8  | (uint32_t)rsv[4];
+
+  nllvdbg("Receiving packet, nextpkt: %04x pktlen: %d rxstat: %08x\n",
+          priv->nextpkt, pktlen, rxstat);
+
+  /* Check if the packet was received OK */
+
+  if ((rxstat & RXSTAT_OK) == 0)
+    {
+      nlldbg("ERROR: RXSTAT: %08x\n", rxstat);
+
+#ifdef CONFIG_ENCX24J600_STATS
+      priv->stats.rxnotok++;
+#endif
+    }
+
+  /* Check for a usable packet length (4 added for the CRC) */
+
+  else if (pktlen > (CONFIG_NET_BUFSIZE + 4) || pktlen <= (UIP_LLH_LEN + 4))
+    {
+      nlldbg("Bad packet size dropped (%d)\n", pktlen);
+#ifdef CONFIG_ENCX24J600_STATS
+      priv->stats.rxpktlen++;
+#endif
+    }
+
+  /* Otherwise, read and process the packet */
+
+  else
+    {
+      /* Save the packet length (without the 4 byte CRC) in priv->dev.d_len */
+
+      priv->dev.d_len = pktlen - 4;
+
+      /* Copy the data data from the receive buffer to priv->dev.d_buf.
+       * ERXRDPT should be correctly positioned from the last call to to
+       * enc_rdbuffer (above).
+       */
+
+      enc_rdbuffer(priv, priv->dev.d_buf, priv->dev.d_len);
+      enc_dumppacket("Received Packet", priv->dev.d_buf, priv->dev.d_len);
+
+      /* Dispatch the packet to uIP */
+
+      enc_rxdispatch(priv);
+    }
+
+  /* Once the whole frame has been processed, the final value of ERXTAIL should
+   * be equal to (NextPacketPointer - 2).
+   */
+
+  /* @TODO check if no special handling needed (skip odd addresses?) */
+  enc_wrreg(priv, ENC_ERXTAIL, priv->nextpkt - 2);
+
+  /* Decrement the packet counter indicate we are done with this packet */
+
+  enc_bfs(priv, ENC_ECON1, ECON1_PKTDEC);
+
+}
+
+/****************************************************************************
+ * Function: enc_irqworker
+ *
+ * Description:
+ *   Perform interrupt handling logic outside of the interrupt handler (on
+ *   the work queue thread).
+ *
+ * Parameters:
+ *   arg     - The reference to the driver structure (case to void*)
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_irqworker(FAR void *arg)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+  uip_lock_t lock;
+  uint16_t eir;
+
+  DEBUGASSERT(priv);
+
+  /* Get exclusive access to both uIP and the SPI bus. */
+
+  lock = uip_lock();
+  enc_lock(priv);
+
+  /* A good practice is for the host controller to clear the Global Interrupt
+   * Enable bit, INTIE (EIE<15>), immediately after an interrupt event. This
+   * causes the interrupt pin to return to the non-asserted (high) state. Once
+   * the interrupt has been serviced, the INTIE bit is set again to re-enable
+   * interrupts. If a new interrupt occurs while servicing another, the act of
+   * resetting the global enable bit will cause a new falling edge to occur on
+   * the interrupt pin and ensure that the host does not miss any events
+   */
+
+  enc_bfc(priv, ENC_EIE, EIE_INTIE);
+
+  /* Loop until all interrupts have been processed (EIR==0).  Note that
+   * there is no infinite loop check... if there are always pending interrupts,
+   * we are just broken.
+   */
+
+  while ((eir = enc_rdreg(priv, ENC_EIR) & EIR_ALLINTS) != 0)
+    {
+      /* Handle interrupts according to interrupt register register bit
+       * settings.
+       */
+
+      nllvdbg("EIR: %04x\n", eir);
+
+      if ((eir & EIR_DMAIF) != 0) /* DMA interrupt */
+        {
+          /* Not used by this driver. Just clear the interrupt request. */
+
+          enc_bfc(priv, ENC_EIR, EIR_DMAIF);
+        }
+
+      /* LINKIF: The link change interrupt occurs when the PHY link status
+       * changes. This flag is set by hardware when a link has either been
+       * established or broken between the device and a remote Ethernet partner.
+       * The current link status can be read from PHYLNK (ESTAT<8>). The
+       * interrupt should be cleared by software once it has been serviced.
+       *
+       * To enable the link change interrupt, set LINKIE (EIE<11>).
+       */
+
+      if ((eir & EIR_LINKIF) != 0) /* PHY Link Status Change */
+        {
+          enc_linkstatus(priv);                /* Get current link status */
+          enc_bfc(priv, ENC_EIR, EIR_LINKIF);  /* Clear the LINKIF interrupt */
+        }
+
+      /* The transmit complete interrupt occurs when the transmission of a
+       * frame has ended (whether or not it was successful). This flag is set
+       * when TXRTS (ECON1<1>) is cleared. The interrupt should be cleared by
+       * software once it has been serviced.
+       */
+
+      if ((eir & EIR_TXIF) != 0) /* Transmit Done */
+        {
+          enc_txif(priv);
+          enc_bfc(priv, ENC_EIR, EIR_TXIF);
+        }
+
+      /* The received packet pending interrupt occurs when one or more frames
+       * have been received and are ready for software processing. This flag is
+       * set when the PKTCNT<7:0> (ESTAT<7:0>) bits are non-zero. This interrupt
+       * flag is read-only and will automatically clear when the PKTCNT bits are
+       * decremented to zero. For more details about receiving and processing
+       * incoming frames, refer to Section 9.0 "Transmitting and Receiving
+       * Packets".
+       *
+       * To enable the received packet pending interrupt, set PKTIE (EIE<6>).
+       * The corresponding interrupt flag is PKTIF (EIR<6>).
+       */
+
+      if ((eir & EIR_PKTIF) != 0    /* RX Packet Pending */
+          && (enc_rdreg(priv, ENC_ESTAT) & ESTAT_PKTCNT_MASK) != 0)
+        {
+          enc_pktif(priv);          /* Handle packet receipt */
+
+          /* No clearing necessary, after PKTCNT == 0 the bit is automatically
+           * cleared. This means we will loop until all packets are processed.
+           */
+        }
+
+#ifdef CONFIG_ENCX24J600_STATS
+
+      /* The transmit abort interrupt occurs when the transmission of a frame
+       * has been aborted. An abort can occur for any of the following reasons:
+       *
+       * * Excessive collisions occurred as defined by the Retransmission
+       *   Maximum, MAXRET<3:0> bits (MACLCON<3:0>), setting. If this occurs,
+       *   the COLCNT bits (ETXSTAT<3:0>) will indicate the number of collisions
+       *   that occurred.
+       *
+       * * A late collision occurred after 63 bytes were transmitted. If this
+       *   occurs, LATECOL (ETXSTAT<10>) will be set.
+       *
+       * * The medium was busy and the packet was deferred. If this occurs,
+       *   EXDEFER (ETXSTAT<8>) will be set.
+       *
+       * * The application aborted the transmission by clearing TXRTS
+       *   (ECON1<1>).
+       *
+       * The interrupt should be cleared by software once it has  been serviced.
+       * To enable the transmit abort interrupt, set TXABTIE (EIE<2>).
+       */
+
+      if ((eir & EIR_TXABTIF) != 0) /* Transmit Abort */
+        {
+          priv->stats.txerifs++;
+          enc_bfc(priv, ENC_EIR, EIR_TXABTIF);  /* Clear the TXABTIF interrupt */
+        }
+
+      /* The receive abort interrupt occurs when the reception of a frame has
+       * been aborted. A frame being received is aborted when the Head Pointer
+       * attempts to overrun the Tail Pointer, or when the packet counter has
+       * reached FFh. In either case, the receive buffer is full and cannot fit
+       * the incoming frame, so the packet has been dropped. This interrupt does
+       * not occur when packets are dropped due to the receive filters rejecting
+       * a packet. The interrupt should be cleared by software once it has been
+       * serviced.
+       *
+       * To enable the receive abort interrupt, set RXABTIE (EIE<1>).
+       * The corresponding interrupt flag is RXABTIF (EIR<1>).
+       */
+
+      if ((eir & EIR_RXABTIF) != 0) /* Receive Abort */
+        {
+          priv->stats.rxerifs++;
+          enc_bfc(priv, ENC_EIR, EIR_RXABTIF);  /* Clear the RXABTIF interrupt */
+        }
+#endif
+
+    }
+
+  /* Enable Ethernet interrupts */
+
+  enc_bfs(priv, ENC_EIE, EIE_INTIE);
+
+  /* Release lock on the SPI bus and uIP */
+
+  enc_unlock(priv);
+  uip_unlock(lock);
+
+  /* Enable GPIO interrupts */
+
+  priv->lower->enable(priv->lower);
+}
+
+/****************************************************************************
+ * Function: enc_interrupt
+ *
+ * Description:
+ *   Hardware interrupt handler
+ *
+ * Parameters:
+ *   irq     - Number of the IRQ that generated the interrupt
+ *   context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int enc_interrupt(int irq, FAR void *context)
+{
+  register FAR struct enc_driver_s *priv = &g_encx24j600[0];
+
+  /* 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->irqwork));
+
+  /* Notice that further GPIO interrupts are disabled until the work is
+   * actually performed.  This is to prevent overrun of the worker thread.
+   * Interrupts are re-enabled in enc_irqworker() when the work is completed.
+   */
+
+  priv->lower->disable(priv->lower);
+  return work_queue(HPWORK, &priv->irqwork, enc_irqworker, (FAR void *)priv, 0);
+}
+
+/****************************************************************************
+ * Function: enc_toworker
+ *
+ * Description:
+ *   Our TX watchdog timed out.  This is the worker thread continuation of
+ *   the watchdog timer interrupt.  Reset the hardware and start again.
+ *
+ * Parameters:
+ *   arg     - The reference to the driver structure (case to void*)
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_toworker(FAR void *arg)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+  uip_lock_t lock;
+  int ret;
+
+  nlldbg("Tx timeout\n");
+  DEBUGASSERT(priv);
+
+  /* Get exclusive access to both uIP and the SPI bus. */
+
+  lock = uip_lock();
+  enc_lock(priv);
+
+  /* Increment statistics and dump debug info */
+
+#ifdef CONFIG_ENCX24J600_STATS
+  priv->stats.txtimeouts++;
+#endif
+
+  /* Then reset the hardware: Take the interface down, then bring it
+   * back up
+   */
+
+  ret = enc_ifdown(&priv->dev);
+  DEBUGASSERT(ret == OK);
+  ret = enc_ifup(&priv->dev);
+  DEBUGASSERT(ret == OK);
+  (void)ret;
+
+  /* Then poll uIP for new XMIT data */
+
+  (void)uip_poll(&priv->dev, enc_uiptxpoll);
+
+  /* Release lock on the SPI bus and uIP */
+
+  enc_unlock(priv);
+  uip_unlock(lock);
+}
+
+/****************************************************************************
+ * Function: enc_txtimeout
+ *
+ * Description:
+ *   Our TX watchdog timed out.  Called from the timer interrupt handler.
+ *   The last TX never completed.  Perform work on the worker thread.
+ *
+ * Parameters:
+ *   argc - The number of available arguments
+ *   arg  - The first argument
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_txtimeout(int argc, uint32_t arg, ...)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+  int ret;
+
+  /* In complex environments, we cannot do SPI transfers from the timout
+   * 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->towork));
+
+  /* Notice that Tx timeout watchdog is not active so further Tx timeouts
+   * can occur until we restart the Tx timeout watchdog.
+   */
+
+  ret = work_queue(HPWORK, &priv->towork, enc_toworker, (FAR void *)priv, 0);
+  (void)ret;
+  DEBUGASSERT(ret == OK);
+}
+
+/****************************************************************************
+ * Function: enc_pollworker
+ *
+ * Description:
+ *   Periodic timer handler continuation.
+ *
+ * Parameters:
+ *   argc - The number of available arguments
+ *   arg  - The first argument
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_pollworker(FAR void *arg)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+  uip_lock_t lock;
+
+  DEBUGASSERT(priv);
+
+  /* Get exclusive access to both uIP and the SPI bus. */
+
+  lock = uip_lock();
+  enc_lock(priv);
+
+  /* Verify that the hardware is ready to send another packet.  The driver
+   * start a transmission process by setting ECON1.TXRTS. When the packet is
+   * finished transmitting or is aborted due to an error/cancellation, the
+   * ECON1.TXRTS bit will be cleared.
+   */
+
+  if ((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0)
+    {
+      /* Yes.. update TCP timing states and poll uIP for new XMIT data. Hmmm..
+       * looks like a bug here to me.  Does this mean if there is a transmit
+       * in progress, we will missing TCP time state updates?
+       */
+
+      (void)uip_timer(&priv->dev, enc_uiptxpoll, ENC_POLLHSEC);
+    }
+
+  /* Release lock on the SPI bus and uIP */
+
+  enc_unlock(priv);
+  uip_unlock(lock);
+
+  /* Setup the watchdog poll timer again */
+
+  (void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1, arg);
+}
+
+/****************************************************************************
+ * Function: enc_polltimer
+ *
+ * Description:
+ *   Periodic timer handler.  Called from the timer interrupt handler.
+ *
+ * Parameters:
+ *   argc - The number of available arguments
+ *   arg  - The first argument
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_polltimer(int argc, uint32_t arg, ...)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)arg;
+  int ret;
+
+  /* In complex environments, we cannot do SPI transfers from the timout
+   * 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->pollwork));
+
+  /* Notice that poll watchdog is not active so further poll timeouts can
+   * occur until we restart the poll timeout watchdog.
+   */
+
+  ret = work_queue(HPWORK, &priv->pollwork, enc_pollworker, (FAR void *)priv, 0);
+  (void)ret;
+  DEBUGASSERT(ret == OK);
+}
+
+/****************************************************************************
+ * Function: enc_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the Ethernet interface when an IP address is
+ *   provided
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int enc_ifup(struct uip_driver_s *dev)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
+  int ret;
+
+  nlldbg("Bringing up: %d.%d.%d.%d\n",
+         dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
+        (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 );
+
+  /* Lock the SPI bus so that we have exclusive access */
+
+  enc_lock(priv);
+
+  /* Initialize Ethernet interface, set the MAC address, and make sure that
+   * the ENC28J80 is not in power save mode.
+   */
+
+  ret = enc_reset(priv);
+  if (ret == OK)
+    {
+
+      enc_setmacaddr(priv);
+      /* enc_pwrfull(priv); */
+
+
+      /* Enable interrupts at the ENCX24J600.  Interrupts are still disabled
+       * at the interrupt controller.
+       */
+
+      enc_bfc(priv, ENC_EIR, EIR_ALLINTS);
+      enc_bfs(priv, ENC_EIE, EIE_INTIE  | EIE_LINKIE  |
+                             EIE_PKTIE  | EIE_RXABTIE |
+                             EIE_TXIE   );
+
+#ifdef CONFIG_ENCX24J600_STATS
+      enc_bfs(priv, ENC_EIE, EIE_TXABTIE);
+#endif
+
+      /* Enable the receiver */
+
+      enc_bfs(priv, ENC_ECON1, ECON1_RXEN);
+
+      /* Set and activate a timer process */
+
+      (void)wd_start(priv->txpoll, ENC_WDDELAY, enc_polltimer, 1, (uint32_t)priv);
+
+      /* Mark the interface up and enable the Ethernet interrupt at the
+       * controller
+       */
+
+      priv->ifstate = ENCSTATE_UP;
+      priv->lower->enable(priv->lower);
+    }
+
+  /* Un-lock the SPI bus */
+
+  enc_unlock(priv);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Function: enc_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int enc_ifdown(struct uip_driver_s *dev)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
+  irqstate_t flags;
+  int ret;
+
+  nlldbg("Taking down: %d.%d.%d.%d\n",
+         dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
+         (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24 );
+
+  /* Lock the SPI bus so that we have exclusive access */
+
+  enc_lock(priv);
+
+  /* Disable the Ethernet interrupt */
+
+  flags = irqsave();
+  priv->lower->disable(priv->lower);
+
+  /* Cancel the TX poll timer and TX timeout timers */
+
+  wd_cancel(priv->txpoll);
+  wd_cancel(priv->txtimeout);
+
+  /* Reset the device and leave in the power save state */
+
+  ret = enc_reset(priv);
+  enc_pwrsave(priv);
+
+  priv->ifstate = ENCSTATE_DOWN;
+  irqrestore(flags);
+
+  /* Un-lock the SPI bus */
+
+  enc_unlock(priv);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Function: enc_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.
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int enc_txavail(struct uip_driver_s *dev)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
+  irqstate_t flags;
+
+  /* Lock the SPI bus so that we have exclusive access */
+
+  enc_lock(priv);
+
+  /* Ignore the notification if the interface is not yet up */
+
+  flags = irqsave();
+  if (priv->ifstate == ENCSTATE_UP)
+    {
+      /* Check if the hardware is ready to send another packet.  The driver
+       * starts a transmission process by setting ECON1.TXRTS. When the packet is
+       * finished transmitting or is aborted due to an error/cancellation, the
+       * ECON1.TXRTS bit will be cleared.
+       */
+
+      if ((enc_rdreg(priv, ENC_ECON1) & ECON1_TXRTS) == 0)
+        {
+          /* The interface is up and TX is idle; poll uIP for new XMIT data */
+
+          (void)uip_poll(&priv->dev, enc_uiptxpoll);
+        }
+    }
+
+  /* Un-lock the SPI bus */
+
+  irqrestore(flags);
+  enc_unlock(priv);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Function: enc_addmac
+ *
+ * Description:
+ *   NuttX Callback: Add the specified MAC address to the hardware multicast
+ *   address filtering
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be added
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IGMP
+static int enc_addmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
+
+  /* Lock the SPI bus so that we have exclusive access */
+
+  enc_lock(priv);
+
+  /* Add the MAC address to the hardware multicast routing table */
+
+#warning "Multicast MAC support not implemented"
+
+  /* Un-lock the SPI bus */
+
+  enc_unlock(priv);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: enc_rmmac
+ *
+ * Description:
+ *   NuttX Callback: Remove the specified MAC address from the hardware multicast
+ *   address filtering
+ *
+ * Parameters:
+ *   dev  - Reference to the NuttX driver state structure
+ *   mac  - The MAC address to be removed
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IGMP
+static int enc_rmmac(struct uip_driver_s *dev, FAR const uint8_t *mac)
+{
+  FAR struct enc_driver_s *priv = (FAR struct enc_driver_s *)dev->d_private;
+
+  /* Lock the SPI bus so that we have exclusive access */
+
+  enc_lock(priv);
+
+  /* Add the MAC address to the hardware multicast routing table */
+
+#warning "Multicast MAC support not implemented"
+
+  /* Un-lock the SPI bus */
+
+  enc_unlock(priv);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: enc_pwrsave
+ *
+ * Description:
+ *   The ENCX24J600 may be placed in Power-Down mode through the command
+ *   interface. In this mode, the device will no longer be able to transmit or
+ *   receive any packets or perform DMA operations. However, most registers, and
+ *   all buffer memories, retain their states and remain accessible by the host
+ *   controller. The clock driver also remains operational, leaving the CLKOUT
+ *   function unaffected. However, the MAC/MII and PHY registers all become
+ *   inaccessible, and the PHY registers lose their current states.
+ *
+ *   1. Turn off the Modular Exponentiation and AES engines by clearing
+ *      CRYPTEN (EIR<15>).
+ *   2. Turn off packet reception by clearing RXEN (ECON1<0>).
+ *   3. Wait for any in-progress receptions to complete by polling
+ *      RXBUSY (ESTAT<13>) until it is clear.
+ *   4. Wait for any current transmission operation to complete by verifying
+ *      that TXRTS (ECON1<1>) is clear.
+ *   5. Power-down the PHY by setting the PSLEEP bit (PHCON1<11>).
+ *   6. Power-down the Ethernet interface by clearing
+ *      ETHEN and STRCH (ECON2<15,14>). Disabling the LED stretching behavior is
+ *      necessary to ensure no LEDs get trapped in a perpetually illuminated
+ *      state in the event they are being stretched on when ETHEN is cleared.
+ *
+ * Note:
+ *   Instead of providing a powerup function, the job is done by enc_reset.
+ *   enc_ifup calls it anyway.
+ *
+ * Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_pwrsave(FAR struct enc_driver_s *priv)
+{
+  uint16_t regval;
+
+  nllvdbg("Set PWRSV\n");
+
+  /* 1. Turn off AES */
+
+  enc_bfc(priv, ENC_EIR, EIR_CRYPTEN);
+
+  /* 2. Turn off packet reception */
+
+  enc_bfc(priv, ENC_ECON1, ECON1_RXEN);
+
+  /* 3. Wait for pending reception to complete */
+
+  enc_waitreg(priv, ENC_ESTAT, ESTAT_RXBUSY, 0);
+
+  /* 4. Wait for any current transmissions to complete */
+
+  enc_waitreg(priv, ENC_ECON1, ECON1_TXRTS, 0);
+
+  /* 5. Power down the PHY */
+
+  regval = enc_rdphy(priv, ENC_PHCON1);
+  regval |= PHCON1_PSLEEP;
+  enc_wrphy(priv, ENC_PHCON1, regval);
+
+  /* 6. Power down the Ethernet interface */
+
+  enc_bfc(priv, ENC_ECON2, ECON2_ETHEN | ECON2_STRCH);
+}
+
+/****************************************************************************
+ * Function: enc_setmacaddr
+ *
+ * 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.
+ *   If the MAC address is 0 in all digits, the ENCX24J600's MAC is read out.
+ *
+ * Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static void enc_setmacaddr(FAR struct enc_driver_s *priv)
+{
+  uint16_t regval;
+  uint8_t *mac = priv->dev.d_mac.ether_addr_octet;
+  struct ether_addr zmac;
+
+  memset(&zmac, 0, sizeof(zmac));
+
+  if (memcmp(&priv->dev.d_mac, &zmac, sizeof(zmac)) == 0)
+    {
+      /* No user defined MAC address. Read it from the device. */
+
+      nvdbg("Using ENCX24J600's built in MAC address\n");
+
+      regval = enc_rdreg(priv, ENC_MAADR1);
+      mac[0] = regval & 0xff;
+      mac[1] = regval >> 8;
+
+      regval = enc_rdreg(priv, ENC_MAADR2);
+      mac[2] = regval & 0xff;
+      mac[3] = regval >> 8;
+
+      regval = enc_rdreg(priv, ENC_MAADR3);
+      mac[4] = regval & 0xff;
+      mac[5] = regval >> 8;
+    }
+  else
+    {
+      /* There is a user defined mac address. Write it to the ENCXJ600 */
+
+      nvdbg("Using an user defined MAC address\n");
+
+      enc_wrreg(priv, ENC_MAADR1, (uint16_t)mac[1] << 8 | (uint16_t)mac[0]);
+      enc_wrreg(priv, ENC_MAADR2, (uint16_t)mac[3] << 8 | (uint16_t)mac[2]);
+      enc_wrreg(priv, ENC_MAADR3, (uint16_t)mac[5] << 8 | (uint16_t)mac[4]);
+    }
+}
+
+/****************************************************************************
+ * Function: enc_reset
+ *
+ * Description:
+ *   Stop, reset, re-initialize, and restart the ENCX24J600.  This is done
+ *   initially, on ifup, and after a TX timeout.
+ *
+ * Parameters:
+ *   priv  - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int enc_reset(FAR struct enc_driver_s *priv)
+{
+  int ret;
+  uint16_t regval;
+
+  nlldbg("Reset\n");
+
+  /* configure SPI for the ENCX24J600 */
+
+  enc_configspi(priv->spi);
+
+  do
+    {
+      enc_wrreg(priv, ENC_EUDAST, 0x1234);
+    }
+  while (enc_rdreg(priv, ENC_EUDAST) != 0x1234);
+
+  /* wait for clock to become ready */
+
+  ret = enc_waitreg(priv, ENC_ESTAT, ESTAT_CLKRDY, ESTAT_CLKRDY);
+
+  if (ret != OK)
+    {
+      nlldbg("ERROR: encx24j600 clock failed to become ready\n");
+      return -ENODEV;
+    }
+
+  /* reset the ENCX24J600 */
+
+  enc_setethrst(priv);
+
+  /* check if EUDAST has been reset to 0 */
+
+  regval = enc_rdreg(priv, ENC_EUDAST);
+
+  if (regval != 0x0000)
+    {
+      nlldbg("ERROR: encx24j600 seems not to be reset properly\n");
+      return -ENODEV;
+    }
+
+  /**
+   * Wait at least 256 μs for the PHY registers and PHY status bits to become
+   * available.
+   */
+  up_udelay(256);
+
+  /* Initialize receive and transmit buffers  */
+
+  priv->nextpkt = PKTMEM_RX_START;
+  enc_wrreg(priv, ENC_ERXST, PKTMEM_RX_START);
+  enc_wrreg(priv, ENC_ETXST, PKTMEM_TX_START);
+
+  /* Program the Tail Pointer, ERXTAIL, to the last even address of the buffer */
+
+  enc_wrreg(priv, ENC_ERXTAIL, PKTMEM_RX_END);
+
+  /* "Typically, when using auto-negotiation, users should write 0x05E1 to PHANA
+   * to advertise flow control capability."
+   */
+
+  enc_wrphy(priv, ENC_PHANA, PHANA_ADPAUS0 | PHANA_AD10FD | PHANA_AD10 |
+            PHANA_AD100FD | PHANA_AD100 | PHANA_ADIEEE0);
+
+  /* restart auto-negotiation */
+
+  enc_wrphy(priv, ENC_PHCON1, PHCON1_RENEG);
+
+  do
+    {
+      regval = enc_rdphy(priv, ENC_PHSTAT1);
+    }
+  while ((regval & PHSTAT1_ANDONE) != 0);
+
+  nlldbg("Auto-negotation completed\n");
+
+  enc_linkstatus(priv);
+
+  /* Set the maximum packet size which the controller will accept */
+
+  enc_wrreg(priv, ENC_MAMXFL, CONFIG_NET_BUFSIZE);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: enc_initialize
+ *
+ * Description:
+ *   Initialize the Ethernet driver.  The ENCX24J600 device is assumed to be
+ *   in the post-reset state upon entry to this function.
+ *
+ * Parameters:
+ *   spi   - A reference to the platform's SPI driver for the ENCX24J600
+ *   lower - The MCU-specific interrupt used to control low-level MCU
+ *           functions (i.e., ENCX24J600 GPIO interrupts).
+ *   devno - If more than one ENCX24J600 is supported, then this is the
+ *           zero based number that identifies the ENCX24J600;
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int enc_initialize(FAR struct spi_dev_s *spi,
+                          FAR const struct enc_lower_s *lower,
+                          unsigned int devno)
+{
+  FAR struct enc_driver_s *priv;
+
+  DEBUGASSERT(devno < CONFIG_ENCX24J600_NINTERFACES);
+  priv = &g_encx24j600[devno];
+
+  /* Initialize the driver structure */
+
+  memset(g_encx24j600, 0, CONFIG_ENCX24J600_NINTERFACES*sizeof(struct enc_driver_s));
+  priv->dev.d_ifup    = enc_ifup;     /* I/F up (new IP address) callback */
+  priv->dev.d_ifdown  = enc_ifdown;   /* I/F down callback */
+  priv->dev.d_txavail = enc_txavail;  /* New TX data callback */
+#ifdef CONFIG_NET_IGMP
+  priv->dev.d_addmac  = enc_addmac;   /* Add multicast MAC address */
+  priv->dev.d_rmmac   = enc_rmmac;    /* Remove multicast MAC address */
+#endif
+  priv->dev.d_private = priv;         /* Used to recover private state from dev */
+
+  /* Create a watchdog for timing polling for and timing of transmisstions */
+
+  priv->txpoll       = wd_create();   /* Create periodic poll timer */
+  priv->txtimeout    = wd_create();   /* Create TX timeout timer */
+  priv->spi          = spi;           /* Save the SPI instance */
+  priv->lower        = lower;         /* Save the low-level MCU interface */
+
+  /* The interface should be in the down state.  However, this function is called
+   * too early in initalization to perform the ENCX24J600 reset in enc_ifdown.  We
+   * are depending upon the fact that the application level logic will call enc_ifdown
+   * later to reset the ENCX24J600.
+   */
+
+  priv->ifstate = ENCSTATE_UNINIT;
+
+  /* Attach the interrupt to the driver (but don't enable it yet) */
+
+  if (lower->attach(lower, enc_interrupt))
+    {
+      /* We could not attach the ISR to the interrupt */
+
+      return -EAGAIN;
+    }
+
+  /* Power down the device */
+
+  enc_pwrsave(priv);
+
+  /* Register the device with the OS so that socket IOCTLs can be performed */
+
+  return netdev_register(&priv->dev);
+}
+
+/****************************************************************************
+ * Function: enc_stats
+ *
+ * Description:
+ *   Return accumulated ENCX24J600 statistics.  Statistics are cleared after
+ *   being returned.
+ *
+ * Parameters:
+ *   devno - If more than one ENCX24J600 is supported, then this is the
+ *           zero based number that identifies the ENCX24J600;
+ *   stats - The user-provided location to return the statistics.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ENCX24J600_STATS
+int enc_stats(unsigned int devno, struct enc_stats_s *stats)
+{
+  FAR struct enc_driver_s *priv ;
+  irqstate_t flags;
+
+  DEBUGASSERT(devno < CONFIG_ENCX24J600_NINTERFACES);
+  priv = &g_encx24j600[devno];
+
+  /* Disable the Ethernet interrupt */
+
+  flags = irqsave();
+  memcpy(stats, &priv->stats, sizeof(struct enc_stats_s));
+  memset(&priv->stats, 0, sizeof(struct enc_stats_s));
+  irqrestore(flags);
+  return OK;
+}
+#endif
+#endif /* CONFIG_NET && CONFIG_ENCX24J600_NET */
diff --git a/drivers/net/encx24j600.h b/drivers/net/encx24j600.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0343efba27525fec923edf318f5cba4e422db86
--- /dev/null
+++ b/drivers/net/encx24j600.h
@@ -0,0 +1,423 @@
+/****************************************************************************
+ * drivers/net/encx24j600.h
+ *
+ *   Copyright (C) 2013 UVC Ingenieure. All rights reserved.
+ *   Author: Max Holtberg <mh@uvc.de>
+ *
+ * References:
+ * - ENC424J600/624J600 Data Sheet, Stand-Alone 10/100 Ethernet Controller
+ *   with SPI or Parallel Interface, DS39935C, 2010 Microchip Technology Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __DRIVERS_NET_ENCX24J600_H
+#define __DRIVERS_NET_ENCX24J600_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* ENCX24J600 Commands ********************************************************/
+
+/* The SPI opcodes are divided into four families:
+ *
+ * Single Byte: Direct opcode instructions; designed for task-oriented SFR
+ * operations with no data returned
+ *
+ * Two-Byte: Direct opcode instruction; designed for SFR operation with byte
+ * data returned
+ *
+ * Three-Byte: Opcode with word length argument; includes read and write
+ * operations, designed for pointer manipulation with word length data returned
+ *
+ * N-Byte: Opcode with one or more bytes of argument; includes read and write
+ * operations designed for general memory space access with one or more bytes of
+ * data returned
+ */
+
+/* Single-Byte Instructions */
+
+/* Because all single byte instructions are fixed length with no optional
+ * parameters, it is possible to execute any instruction immediately following
+ * the execution of any single byte instruction without deasserting the chip
+ * select line in between.
+ */
+
+#define ENC_B0SEL       (0xc0)  /* Selects SFR Bank 0 */
+#define ENC_B1SEL       (0xc2)  /* Selects SFR Bank 1 */
+#define ENC_B2SEL       (0xc4)  /* Selects SFR Bank 2 */
+#define ENC_B3SEL       (0xc6)  /* Selects SFR Bank 3 */
+#define ENC_SETETHRST   (0xca)  /* Issues System Reset by setting ETHRST (ECON2<4>) */
+#define ENC_FCDISABLE   (0xe0)  /* Disables flow control (sets ECON1<7:6> = 00) */
+#define ENC_FCSINGLE    (0xe2)  /* Transmits a single pause frame (sets ECON1<7:6> = 01) */
+#define ENC_FCMULTIPLE  (0xe4)  /* Enables flow control with periodic pause frames (sets ECON1<7:6> = 10) */
+#define ENC_FCCLEAR     (0xe6)  /* Terminates flow control with a final pause frame (sets ECON1<7:6> = 11) */
+#define ENC_SETPKTDEC   (0xcc)  /* Decrements PKTCNT by setting PKTDEC (ECON1<8>) */
+#define ENC_DMASTOP     (0xd2)  /* Stops current DMA operation by clearing DMAST (ECON1<5>) */
+#define ENC_DMACKSUM    (0xd8)  /* Starts DMA and checksum operation (sets ECON1<5:2> = 1000) */
+#define ENC_DMACKSUMS   (0xda)  /* Starts DMA checksum operation with seed (sets ECON1<5:2> = 1010) */
+#define ENC_DMACOPY     (0xdc)  /* Starts DMA copy and checksum operation (sets ECON1<5:2> = 1100) */
+#define ENC_DMACOPYS    (0xde)  /* Starts DMA copy and checksum operation with seed (sets ECON1<5:2> = 1110) */
+#define ENC_SETTXRTS    (0xd4)  /* Sets TXRTS (ECON1<1>), sends an Ethernet packet */
+#define ENC_ENABLERX    (0xe8)  /* Enables packet reception by setting RXEN (ECON1<0>) */
+#define ENC_DISABLERX   (0xea)  /* Disables packet reception by clearing RXEN (ECON1<0>) */
+#define ENC_SETEIE      (0xec)  /* Enable Ethernet Interrupts by setting INT (ESTAT<15>) */
+#define ENC_CLREIE      (0xee)  /* Disable Ethernet Interrupts by clearing INT (ESTAT<15>) */
+
+/* Two-Byte Instructions */
+
+/* There is only one instruction in the ENCX24J600 command set which uses two
+ * SPI bytes. The Read Bank Select opcode, RBSEL, reads the internal SFR bank
+ * select state and returns the value to the host controller.
+ */
+
+#define ENC_RBSEL       (0xc8)
+
+/* Three-Byte Instructions */
+
+#define ENC_WGPRDPT     (0x60)  /* Write General Purpose Buffer Read Pointer (EGPRDPT) */
+#define ENC_RGPRDPT     (0x62)  /* Read General Purpose Buffer Read Pointer (EGPRDPT) */
+#define ENC_WRXRDPT     (0x64)  /* Write Receive Buffer Read Pointer (ERXRDPT) */
+#define ENC_RRXRDPT     (0x66)  /* Read Receive Buffer Read Pointer (ERXRDPT) */
+#define ENC_WUDARDPT    (0x68)  /* Write User-Defined Area Read Pointer (EUDARDPT) */
+#define ENC_RUDARDPT    (0x6a)  /* Read User-Defined Area Read Pointer (EUDARDPT) */
+#define ENC_WGPWRPT     (0x6c)  /* Write General Purpose Buffer Write Pointer (EGPWRPT) */
+#define ENC_RGPWRPT     (0x6e)  /* Read General Purpose Buffer Write Pointer (EGPWRPT) */
+#define ENC_WRXWRPT     (0x70)  /* Write Receive Buffer Write Pointer (ERXWRPT) */
+#define ENC_RRXWRPT     (0x72)  /* Read Receive Buffer Write Pointer (ERXWRPT) */
+#define ENC_WUDAWRPT    (0x78)  /* Write User-Defined Area Write Pointer (EUDAWRPT) */
+#define ENC_RUDAWRPT    (0x76)  /* Read User-Defined Area Write Pointer (EUDAWRPT) */
+
+/* Banked N-Byte Instructions */
+
+#define ENC_RCR         (0x00)  /* Read Control Register
+                                   000 | aaaaa | (Register value returned)) */
+#define ENC_WCR         (0x40)  /* Write Control Register
+                                   010 | aaaaa | dddddddd */
+#define ENC_BFS         (0x80)  /* Bit Field Set
+                                   100 | aaaaa | dddddddd */
+#define ENC_BFC         (0xa0)  /* Bit Field Clear
+                                   101 | aaaaa | dddddddd */
+
+/* Unbanked N-Byte Instructions */
+
+#define ENC_RCRU        (0x20)  /* Read Control Register(s), Unbanked */
+#define ENC_WCRU        (0x22)  /* Write Control Register(s), Unbanked */
+#define ENC_BFSU        (0x24)  /* Bit Field(s) Set, Unbanked */
+#define ENC_BFCU        (0x26)  /* Bit Field(s) Clear, Unbanked */
+
+/* SRAM Access Instructions */
+
+#define ENC_RGPDATA     (0x28)  /* Read Data from EGPDATA */
+#define ENC_WGPDATA     (0x2a)  /* Write Data from EGPDATA */
+#define ENC_RRXDATA     (0x2c)  /* Read Data from ERXDATA */
+#define ENC_WRXDATA     (0x2e)  /* Write Data from ERXDATA */
+#define ENC_RUDADATA    (0x30)  /* Read Data from EUDADATA */
+#define ENC_WUDADATA    (0x32)  /* Write Data from EUDADATA */
+
+/* Banked Control Registers *************************************************/
+/* Registers are described by 16 bit values. The high byte describes the bank
+ * by the appropiate bank selection command.
+ * For registers which are available on all banks the comnmand is set to 0.
+ * Unbanked registers are identified by 0x01.
+ */
+
+#define ENC_ADDR_SHIFT  (0)
+#define ENC_ADDR_MASK   (0xff << ENC_ADDR_SHIFT)
+#define ENC_BANK_SHIFT  (8)
+#define ENC_BANK_MASK   (0xff << ENC_BANK_SHIFT)
+
+#define REGADDR(a,b)    ((b) << ENC_BANK_SHIFT | (a) << ENC_ADDR_SHIFT)
+#define GETADDR(a)      (((a) & ENC_ADDR_MASK) >> ENC_ADDR_SHIFT)
+#define GETBANK(a)      (((a) & ENC_BANK_MASK) >> ENC_BANK_SHIFT)
+
+/* Bank 0 Control Register Addresses */
+
+#define ENC_ETXST       REGADDR(0x00, ENC_B0SEL)
+#define ENC_ETXLEN      REGADDR(0x02, ENC_B0SEL)
+#define ENC_ERXST       REGADDR(0x04, ENC_B0SEL)
+#define ENC_ERXTAIL     REGADDR(0x06, ENC_B0SEL)
+#define ENC_ERXHEAD     REGADDR(0x08, ENC_B0SEL)
+#define ENC_EDMAST      REGADDR(0x0a, ENC_B0SEL)
+#define ENC_EDMALEN     REGADDR(0x0c, ENC_B0SEL)
+#define ENC_EDMADST     REGADDR(0x0e, ENC_B0SEL)
+#define ENC_EDMACS      REGADDR(0x10, ENC_B0SEL)
+#define ENC_ETXSTAT     REGADDR(0x12, ENC_B0SEL)
+#define ENC_ETXWIRE     REGADDR(0x14, ENC_B0SEL)
+
+/* Bank 1 Contro Register Addresses */
+
+#define ENC_EHT1        REGADDR(0x00, ENC_B1SEL)
+#define ENC_EHT2        REGADDR(0x02, ENC_B1SEL)
+#define ENC_EHT3        REGADDR(0x04, ENC_B1SEL)
+#define ENC_EHT4        REGADDR(0x06, ENC_B1SEL)
+#define ENC_EPMM1       REGADDR(0x08, ENC_B1SEL)
+#define ENC_EPMM2       REGADDR(0x0a, ENC_B1SEL)
+#define ENC_EPMM3       REGADDR(0x0c, ENC_B1SEL)
+#define ENC_EPMM4       REGADDR(0x0e, ENC_B1SEL)
+#define ENC_EPMCS       REGADDR(0x10, ENC_B1SEL)
+#define ENC_EPMO        REGADDR(0x12, ENC_B1SEL)
+#define ENC_ERXFCON     REGADDR(0x14, ENC_B1SEL)
+
+/* Bank 2 Control Register Addresses */
+
+#define ENC_MACON1      REGADDR(0x00, ENC_B2SEL)
+#define ENC_MACON2      REGADDR(0x02, ENC_B2SEL)
+#define ENC_MABBIPG     REGADDR(0x04, ENC_B2SEL)
+#define ENC_MAIPG       REGADDR(0x06, ENC_B2SEL)
+#define ENC_MACLCON     REGADDR(0x08, ENC_B2SEL)
+#define ENC_MAMXFL      REGADDR(0x0a, ENC_B2SEL)
+/* 0x0c - 0x11 reserved */
+#define ENC_MICMD       REGADDR(0x12, ENC_B2SEL)
+#define ENC_MIREGADR    REGADDR(0x14, ENC_B2SEL)
+
+/* MAC Control Register 1 Bit Definitions */
+
+#define MACON1_PASSALL  (1 << 1)
+#define MACON1_RXPAUS   (1 << 2)
+#define MACON1_LOOPBK   (1 << 4)
+
+/* MAC Control Register 2 Bit Definitions */
+
+#define MACON2_FULDPX   (1 << 0)    /* MAC Full-Duplex Enable bit */
+#define MACON2_HFRMEN   (1 << 2)    /* Huge Frame Enable bit */
+#define MACON2_PHDREN   (1 << 3)    /* Proprietary Header Enable bit */
+#define MACON2_TXCRCEN  (1 << 4)    /* Transmit CRC Enable bit */
+#define MACON2_PADCFG0  (1 << 5)    /*  Automatic Pad and CRC Configuration bits */
+#define MACON2_PADCFG1  (1 << 6)
+#define MACON2_PADCFG2  (1 << 7)
+#define MACON2_NOBKOFF  (1 << 12)   /* No Backoff Enable bit (applies to half duplex only) */
+#define MACON2_BPEN     (1 << 13)   /* No Backoff During Back Pressure Enable bit (applies to half duplex only) */
+#define MACON2_DEFER    (1 << 14)   /* Defer Transmission Enable bit (applies to half duplex only) */
+
+/* MII Management Command Register Bit Definitions */
+
+#define MICMD_MIIRD     (1 << 0)    /* MII Read Enable bit */
+#define MICMD_MIISCAN   (1 << 1)    /* MII Scan Enable bit */
+
+/* MII Management Status Register Bit Definitions */
+
+#define MISTAT_BUSY     (1 << 0)    /* MII Management Busy Status bit */
+#define MISTAT_SCAN     (1 << 1)    /* MII Management Scan Status bit */
+#define MISTAT_NVALID   (1 << 2)    /* MII Management Read Data Not Valid Status bit */
+
+/* Bank 3 Control Register Addresses */
+
+#define ENC_MAADR3      REGADDR(0x00, ENC_B3SEL)
+#define ENC_MAADR2      REGADDR(0x02, ENC_B3SEL)
+#define ENC_MAADR1      REGADDR(0x04, ENC_B3SEL)
+#define ENC_MIWR        REGADDR(0x06, ENC_B3SEL)
+#define ENC_MIRD        REGADDR(0x08, ENC_B3SEL)
+#define ENC_MISTAT      REGADDR(0x0a, ENC_B3SEL)
+#define ENC_EPAUS       REGADDR(0x0c, ENC_B3SEL)
+#define ENC_ECON2       REGADDR(0x0e, ENC_B3SEL)
+#define ENC_ERXWM       REGADDR(0x10, ENC_B3SEL)
+#define ENC_EIE         REGADDR(0x12, ENC_B3SEL)
+#define ENC_EIDLED      REGADDR(0x14, ENC_B3SEL)
+
+/* Ethernet Control Register Bit Definitions */
+
+#define ECON2_AESLEN0        (1 << 0)   /* AES Key Length Control bits */
+#define ECON2_AESLEN1        (1 << 1)   /* Modular Exponentiation Length Control bits */
+#define ECON2_MODLEN0        (1 << 2)
+#define ECON2_MODLEN1        (1 << 3)
+#define ECON2_ETHRST         (1 << 4)   /* Master Ethernet Reset bit */
+#define ECON2_RXRST          (1 << 5)   /* Receive Logic Reset bit */
+#define ECON2_TXRST          (1 << 6)   /* Transmit Logic Reset bit */
+#define ECON2_AUTOFC         (1 << 7)   /* Automatic Flow Control Enable bit */
+#define ECON2_COCON_SHIFT    (8)        /* CLKOUT Frequency Control bits */
+#define ECON2_COCON_MASK     (0x0f << ECON2_COCON_SHIFT)
+#define ECON2_SHA1MD5        (1 << 12)  /* SHA-1/MD5 Hash Control bit */
+#define ECON2_TXMAC          (1 << 13)  /* Automatically Transmit MAC Address Enable bit */
+#define ECON2_STRCH          (1 << 14)  /* LED Stretching Enable bit */
+#define ECON2_ETHEN          (1 << 15)  /* Ethernet Enable bit */
+
+/* Ethernet Interrupt Enable Register Bit Definitions */
+
+#define EIE_PCFULIE     (1 << 0)   /* Packet Counter Full Interrupt Enable bit */
+#define EIE_RXABTIE     (1 << 1)   /* Receive Abort Interrupt Enable bit */
+#define EIE_TXABTIE     (1 << 2)   /* Transmit Abort Interrupt Enable bit */
+#define EIE_TXIE        (1 << 3)   /* Transmit Done Interrupt Enable bit */
+#define EIE_DMAIE       (1 << 5)   /* DMA Interrupt Enable bit */
+#define EIE_PKTIE       (1 << 6)   /* RX Packet Pending Interrupt Enable bit */
+#define EIE_LINKIE      (1 << 11)  /* PHY Link Status Change Interrupt Enable bit */
+#define EIE_AESIE       (1 << 12)  /* AES Encrypt/Decrypt Interrupt Enable bit */
+#define EIE_HASHIE      (1 << 13)  /* MD5/SHA-1 Hash Interrupt Enable bit */
+#define EIE_MODEXIE     (1 << 14)  /* Modular Exponentiation Interrupt Enable bit */
+#define EIE_INTIE       (1 << 15)  /* INT Global Interrupt Enable bit */
+
+/**
+ * The last 10 bytes (16h to 1Fh) of all SPI banks point to a common set of five
+ * registers: EUDAST, EUDAND, ESTAT, EIR and ECON1. These are key registers used
+ * in controlling and monitoring the operation of the device. Their common
+ * banked addresses allow easy access without switching the bank.
+ */
+
+/* Common Register Addresses */
+
+#define ENC_EUDAST      REGADDR(0x16, 0x00) /* User-Defined Area Start Pointer (EUDAST<7:0>) */
+#define ENC_EUDAND      REGADDR(0x18, 0x00) /* User-Defined Area End Pointer (EUDAND<7:0>) */
+#define ENC_ESTAT       REGADDR(0x1a, 0x00)
+#define ENC_EIR         REGADDR(0x1c, 0x00)
+#define ENC_ECON1       REGADDR(0x1e, 0x00)
+
+/* Ethernet Status Register Bit Definitions */
+
+#define ESTAT_PKTCNT_SHIFT  (0)           /* Receive Packet Count bits */
+#define ESTAT_PKTCNT_MASK   (0xff)
+#define ESTAT_PHYLNK        (1 << 8)      /* PHY Linked Status bit */
+#define ESTAT_PHYDPX        (1 << 10)     /* PHY Full Duplex Status bit */
+#define ESTAT_CLKRDY        (1 << 12)     /* Clock Ready Status bit */
+#define ESTAT_RXBUSY        (1 << 13)     /* Receive Logic Active Status bit */
+#define ESTAT_FCIDLE        (1 << 14)     /* Flow Control Idle Status bit */
+#define ESTAT_INT           (1 << 15)     /* Interrupt Pending Status bit */
+
+/* Ethernet Interrupt Flag Register Bit Definitions */
+
+#define EIR_PCFULIF     (1 << 0)   /* Packet Counter Full Interrupt Flag bit */
+#define EIR_RXABTIF     (1 << 1)   /* Receive Abort Interrupt Flag bit */
+#define EIR_TXABTIF     (1 << 2)   /* Transmit Abort Interrupt Flag bit */
+#define EIR_TXIF        (1 << 3)   /* Transmit Done Interrupt Flag bit */
+#define EIR_DMAIF       (1 << 5)   /* DMA Interrupt Flag bit */
+#define EIR_PKTIF       (1 << 6)   /* RX Packet Pending Interrupt Flag bit */
+#define EIR_LINKIF      (1 << 11)  /* PHY Link Status Change Interrupt Flag bit */
+#define EIR_AESIF       (1 << 12)  /* AES Encrypt/Decrypt Interrupt Flag bit */
+#define EIR_HASHIF      (1 << 13)  /* MD5/SHA-1 Hash Interrupt Flag bit */
+#define EIR_MODEXIF     (1 << 14)  /* Modular Exponentiation Interrupt Flag bit */
+#define EIR_CRYPTEN     (1 << 15)  /* Modular Exponentiation and AES Cryptographic Modules Enable bit */
+#define EIR_ALLINTS     (0xf86f)
+
+/* Ethernet Control Register 1 Bit Definitions */
+
+#define ECON1_RXEN      (1 << 0)   /* Receive Enable bit */
+#define ECON1_TXRTS     (1 << 1)   /* Transmit Request to Send Status/Control bit */
+#define ECON1_DMANOCS   (1 << 2)   /* DMA No Checksum Control bit */
+#define ECON1_DMACSSD   (1 << 3)   /* DMA Checksum Seed Control bit */
+#define ECON1_DMACPY    (1 << 4)   /* DMA Copy Control bit */
+#define ECON1_DMAST     (1 << 5)   /* DMA Start bit */
+#define ECON1_FCOP0     (1 << 6)   /* Flow Control Operation Control/Status bits */
+#define ECON1_FCOP1     (1 << 7)   /* Flow Control Operation Control/Status bits */
+#define ECON1_PKTDEC    (1 << 8)   /* RX Packet Counter Decrement Control bit */
+#define ECON1_AESOP0    (1 << 9)   /* AES Operation Control bits */
+#define ECON1_AESOP1    (1 << 10)  /* AES Operation Control bits */
+#define ECON1_AESST     (1 << 11)  /* AES Encrypt/Decrypt Start bit */
+#define ECON1_HASHLST   (1 << 12)  /* MD5/SHA-1 Hash Last Block Control bit */
+#define ECON1_HASHOP    (1 << 13)  /* MD5/SHA-1 Hash Operation Control bit */
+#define ECON1_HASHEN    (1 << 14)  /* MD5/SHA-1 Hash Enable bit */
+#define ECON1_MODEXST   (1 << 15)  /* Modular Exponentiation Start bit */
+
+/* Unbanked Register Addresses */
+
+#if 0
+/* Disabled to prevent accidental use. All unbanked operations are implemented
+ * using the specific manipulation commands.
+ */
+#define ENC_EGPDATA     0x80
+#define ENC_ERXDATA     0x82
+#define ENC_EUDADATA    0x84
+#define ENC_EGPRDPT     0x86
+#define ENC_EGPWRPT     0x88
+#define ENC_ERXRDPT     0x8a
+#define ENC_ERXWRPT     0x8c
+#define ENC_EUDARDPT    0x8e
+#define ENC_EUDAWRPT    0x90
+#endif
+
+/* PHY Registers ************************************************************/
+
+#define ENC_PHCON1      0x00
+#define ENC_PHSTAT1     0x01
+#define ENC_PHANA       0x04
+#define ENC_PHANLPA     0x05
+#define ENC_PHANE       0x06
+#define ENC_PHCON2      0x11
+#define ENC_PHSTAT2     0x1b
+#define ENC_PHSTAT3     0x1f
+
+/* PHY Control Register 1 Bit Definitions */
+
+#define PHCON1_PFULDPX  (1 << 8)  /* PHY Duplex Select Control bit */
+#define PHCON1_RENEG    (1 << 9)  /* Restart Auto-Negotiation Control bit */
+#define PHCON1_PSLEEP   (1 << 11) /* PHY Sleep Enable bit */
+#define PHCON1_ANEN     (1 << 12) /* PHY Auto-Negotiation Enable bit */
+#define PHCON1_SPD100   (1 << 13) /* PHY Speed Select Control bit */
+#define PHCON1_PLOOPBK  (1 << 14) /* PHY Loopback Enable bit */
+#define PHCON1_PRST     (1 << 15) /* PHY Reset bit */
+
+/* PHY Status Register 1 Bit Definitions */
+
+#define PHSTAT1_EXTREGS (1 << 0)  /* Extended Capabilities Registers Present Status bit */
+#define PHSTAT1_LLSTAT  (1 << 2)  /* Latching Link Status bit */
+#define PHSTAT1_ANABLE  (1 << 3)  /* Auto-Negotiation Ability Status bit */
+#define PHSTAT1_LRFAULT (1 << 4)  /* Latching Remote Fault Condition Status bit */
+#define PHSTAT1_ANDONE  (1 << 5)  /* Auto-Negotiation Done Status bit */
+#define PHSTAT1_HALF10  (1 << 11) /* 10Base-T Half-Duplex Ability Status bit */
+#define PHSTAT1_FULL10  (1 << 12) /* 10Base-T Full-Duplex Ability Status bit */
+#define PHSTAT1_HALF100 (1 << 13) /* 100Base-TX Half-Duplex Ability Status bit */
+#define PHSTAT1_FULL100 (1 << 13) /* 100Base-TX Full-Duplex Ability Status bit */
+
+/* PHY Auto-Negotiation Advertisement Register Bit Definitions */
+
+
+#define PHANA_ADIEEE0   (1 << 0)
+#define PHANA_ADIEEE1   (1 << 1)
+#define PHANA_ADIEEE2   (1 << 2)
+#define PHANA_ADIEEE3   (1 << 3)
+#define PHANA_ADIEEE4   (1 << 4)
+#define PHANA_AD10      (1 << 5)  /* Advertise 10Base-T Half-Duplex Ability bit */
+#define PHANA_AD10FD    (1 << 6)  /* Advertise 10Base-T Full-Duplex Ability bit */
+#define PHANA_AD100     (1 << 7)  /* Advertise 100Base-TX Half-Duplex Ability bit */
+#define PHANA_AD100FD   (1 << 8)  /* Advertise 100Base-TX Full-Duplex Ability bit */
+/* Advertise PAUSE Flow Control Ability bits */
+/* 11 = Local device supports both symmetric PAUSE and asymmetric PAUSE toward local device */
+/* 10 = Local device supports asymmetric PAUSE toward link partner only */
+/* 01 = Local device supports symmetric PAUSE only (Normal Flow Control mode) */
+/* 00 = Local device does not support PAUSE flow control */
+#define PHANA_ADPAUS0   (1 << 10)
+#define PHANA_ADPAUS1   (1 << 11)
+#define PHANA_ADFAULT   (1 << 13) /* Advertise Remote Fault Condition bit */
+#define PHANA_ADNP      (1 << 15) /* Advertise Next Page Ability bit */
+
+/* Packet Memory ************************************************************/
+
+/* 24-Kbyte Transmit/Receive Packet Dual Port SRAM */
+
+#define PKTMEM_START    0x0000
+#define PKTMEM_END      0x5fff
+
+/* RX Status Bit Definitions ************************************************/
+
+#define RXSTAT_OK       (1 << 7)
+
+#endif  /* __DRIVERS_NET_ENCX24J600_H */
diff --git a/include/nuttx/net/encx24j600.h b/include/nuttx/net/encx24j600.h
new file mode 100644
index 0000000000000000000000000000000000000000..d323583836fb74ec2fdfcb6a04762f808b8a2f14
--- /dev/null
+++ b/include/nuttx/net/encx24j600.h
@@ -0,0 +1,181 @@
+/****************************************************************************
+ * include/nuttx/net/encx24j600.h
+ *
+ *   Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_NET_ENCX24J600_H
+#define __INCLUDE_NUTTX_NET_ENCX24J600_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <nuttx/irq.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* ENCX24J600 Configuration Settings:
+ *
+ * CONFIG_ENCX24J600 - Enabled ENCX24J600 support
+ * CONFIG_ENCX24J600_SPIMODE - Controls the SPI mode
+ * CONFIG_ENCX24J600_FREQUENCY - Define to use a different bus frequency
+ * CONFIG_ENCX24J600_NINTERFACES - Specifies the number of physical ENCX24J600
+ *   devices that will be supported.
+ * CONFIG_ENCX24J600_STATS - Collect network statistics
+ * CONFIG_ENCX24J600_HALFDUPPLEX - Default is full duplex
+ */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* This structure returns driver statistics (if enabled) */
+
+#ifdef CONFIG_ENCX24J600_STATS
+struct enc_stats_s
+{
+  uint8_t  maxpktcnt;         /* Max. number of buffered RX packets */
+  uint32_t txrequests;        /* Number of TX packets queued */
+  uint32_t txifs;             /* TXIF completion events */
+  uint32_t txabrts;           /* TXIF completions with ESTAT.TXABRT */
+  uint32_t txerifs;           /* TXERIF error events */
+  uint32_t txtimeouts;        /* S/W detected TX timeouts */
+  uint32_t pktifs;            /* PKTIF RX completion events */
+  uint32_t rxnotok;           /* PKTIF without RXSTAT_OK */
+  uint32_t rxpktlen;          /* PKTIF with bad pktlen */
+  uint32_t rxerifs;           /* RXERIF error evernts */
+};
+#endif
+
+/* The ENCX24J600 normal provides interrupts to the MCU via a GPIO pin.  The
+ * following structure provides an MCU-independent mechanixm for controlling
+ * the ENCX24J600 GPIO interrupt.
+ *
+ * The ENC32J60 interrupt is an active low, *level* interrupt. "When an
+ * interrupt occurs, the interrupt flag is set. If the interrupt is enabled
+ * in the EIE register and the INTIE global interrupt enable bit is set, the
+ * INT pin will be driven low"
+ *
+ * "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 enc_lower_s
+{
+  int  (*attach)(FAR const struct enc_lower_s *lower, xcpt_t handler);
+  void (*enable)(FAR const struct enc_lower_s *lower);
+  void (*disable)(FAR const struct enc_lower_s *lower);
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: enc_initialize
+ *
+ * Description:
+ *   Initialize the Ethernet driver.  The ENCX24J600 device is assumed to be
+ *   in the post-reset state upon entry to this function.
+ *
+ * Parameters:
+ *   spi   - A reference to the platform's SPI driver for the ENCX24J600
+ *   lower - The MCU-specific interrupt used to control low-level MCU
+ *           functions (i.e., ENCX24J600 GPIO interrupts).
+ *   devno - If more than one ENCX24J600 is supported, then this is the
+ *           zero based number that identifies the ENCX24J600;
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+struct spi_dev_s; /* see nuttx/spi/spi.h */
+int enc_initialize(FAR struct spi_dev_s *spi,
+                   FAR const struct enc_lower_s *lower, unsigned int devno);
+
+/****************************************************************************
+ * Function: enc_stats
+ *
+ * Description:
+ *   Return accumulated ENCX24J600 statistics.  Statistics are cleared after
+ *   being returned.
+ *
+ * Parameters:
+ *   devno - If more than one ENCX24J600 is supported, then this is the
+ *           zero based number that identifies the ENCX24J600;
+ *   stats - The user-provided location to return the statistics.
+ *
+ * Returned Value:
+ *   OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_ENCX24J600_STATS
+int enc_stats(unsigned int devno, struct enc_stats_s *stats);
+#endif
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_NET_ENCX24J600_H */