From bd698bf574e1c16904dd2646d9aabd170eaedcd5 Mon Sep 17 00:00:00 2001
From: Kaspar Schleiser <kaspar@schleiser.de>
Date: Wed, 8 Apr 2015 19:54:00 +0200
Subject: [PATCH] drivers: add encx24j600 ethernet driver

---
 Makefile.dep                                  |   5 +
 drivers/Makefile.include                      |   3 +
 drivers/encx24j600/Makefile                   |   1 +
 drivers/encx24j600/encx24j600.c               | 447 ++++++++++++++++++
 .../encx24j600/include/encx24j600_defines.h   | 206 ++++++++
 .../encx24j600/include/encx24j600_internal.h  |  44 ++
 drivers/include/encx24j600.h                  |  64 +++
 sys/auto_init/auto_init.c                     |   5 +
 sys/auto_init/netif/auto_init_encx24j600.c    |  60 +++
 9 files changed, 835 insertions(+)
 create mode 100644 drivers/encx24j600/Makefile
 create mode 100644 drivers/encx24j600/encx24j600.c
 create mode 100644 drivers/encx24j600/include/encx24j600_defines.h
 create mode 100644 drivers/encx24j600/include/encx24j600_internal.h
 create mode 100644 drivers/include/encx24j600.h
 create mode 100644 sys/auto_init/netif/auto_init_encx24j600.c

diff --git a/Makefile.dep b/Makefile.dep
index a40aae3c39..07d2a27027 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -278,3 +278,8 @@ endif
 ifneq (,$(filter hih6130,$(USEMODULE)))
   USEMODULE += vtimer
 endif
+
+ifneq (,$(filter encx24j600,$(USEMODULE)))
+  USEMODULE += timex
+  USEMODULE += vtimer
+endif
diff --git a/drivers/Makefile.include b/drivers/Makefile.include
index e15584f92d..23cc3d0007 100644
--- a/drivers/Makefile.include
+++ b/drivers/Makefile.include
@@ -43,3 +43,6 @@ endif
 ifneq (,$(filter pcd8544,$(USEMODULE)))
     USEMODULE_INCLUDES += $(RIOTBASE)/drivers/pcd8544/include
 endif
+ifneq (,$(filter encx24j600,$(USEMODULE)))
+    USEMODULE_INCLUDES += $(RIOTBASE)/drivers/encx24j600/include
+endif
diff --git a/drivers/encx24j600/Makefile b/drivers/encx24j600/Makefile
new file mode 100644
index 0000000000..48422e909a
--- /dev/null
+++ b/drivers/encx24j600/Makefile
@@ -0,0 +1 @@
+include $(RIOTBASE)/Makefile.base
diff --git a/drivers/encx24j600/encx24j600.c b/drivers/encx24j600/encx24j600.c
new file mode 100644
index 0000000000..a9b8ab060f
--- /dev/null
+++ b/drivers/encx24j600/encx24j600.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2015 Ell-i open source co-operative
+ *                    Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup     driver_encx24j600
+ * @{
+ *
+ * @file
+ * @brief       Internal functions for the ENCX24J600 driver
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * @}
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include "mutex.h"
+#include "encx24j600.h"
+#include "encx24j600_internal.h"
+#include "encx24j600_defines.h"
+#include "vtimer.h"
+
+#include "net/netdev2.h"
+#include "net/eui64.h"
+#include "net/ethernet.h"
+//#include "net/ethernet/hdr.h"
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#define ENCX24J600_SPI_SPEED SPI_SPEED_1MHZ
+
+#define ENCX24J600_INIT_DELAY 100000U
+
+#define ENC_BUFFER_START 0x0000
+#define ENC_BUFFER_SIZE  0x6000
+#define ENC_BUFFER_END   0x5FFF
+#define RX_BUFFER_START (0x5340) /* Default value */
+#define RX_BUFFER_END   (ENC_BUFFER_END)
+#define TX_BUFFER_LEN   (0x2000)
+#define TX_BUFFER_END   (RX_BUFFER_START)
+#define TX_BUFFER_START (TX_BUFFER_END - TX_BUFFER_LEN)
+
+static void cmd(encx24j600_t *dev, char cmd);
+static void reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value);
+static uint16_t reg_get(encx24j600_t *dev, uint8_t reg);
+static void reg_clear_bits(encx24j600_t *dev, uint8_t reg, uint16_t mask);
+static inline int _packets_available(encx24j600_t *dev);
+
+static int _get_iid(netdev2_t *netdev, eui64_t *value, size_t max_len);
+static void _get_mac_addr(netdev2_t *dev, uint8_t* buf);
+
+/* netdev2 interface */
+static int _send(netdev2_t *netdev, const struct iovec *vector, int count);
+static int _recv(netdev2_t *netdev, char* buf, int len);
+static int _init(netdev2_t *dev);
+static void _isr(netdev2_t *dev);
+int _get(netdev2_t *dev, netopt_t opt, void *value, size_t max_len);
+int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len);
+
+const static netdev2_driver_t netdev2_driver_encx24j600 = {
+    .send = _send,
+    .recv = _recv,
+    .init = _init,
+    .isr = _isr,
+    .get = _get,
+    .set = _set,
+};
+
+static inline void lock(encx24j600_t *dev) {
+    mutex_lock(&dev->mutex);
+}
+
+static inline void unlock(encx24j600_t *dev) {
+    mutex_unlock(&dev->mutex);
+}
+
+void encx24j600_setup(encx24j600_t *dev, spi_t spi, gpio_t cs, gpio_t int_pin)
+{
+    dev->netdev.driver = &netdev2_driver_encx24j600;
+    dev->spi = spi;
+    dev->cs = cs;
+    dev->int_pin = int_pin;
+    dev->rx_next_ptr = RX_BUFFER_START;
+
+    mutex_init(&dev->mutex);
+}
+
+static void encx24j600_isr(void *arg)
+{
+    encx24j600_t *dev = (encx24j600_t *) arg;
+
+    /* disable interrupt line */
+    gpio_irq_disable(dev->int_pin);
+
+    /* call netdev2 hook */
+    dev->netdev.event_callback((netdev2_t*) dev, NETDEV2_EVENT_ISR, NULL);
+}
+
+static void _isr(netdev2_t *netdev)
+{
+    encx24j600_t *dev = (encx24j600_t *) netdev;
+
+    uint16_t eir;
+
+    lock(dev);
+    cmd(dev, CLREIE);
+
+    eir = reg_get(dev, EIR);
+
+    /* check & handle link state change */
+    if (eir & LINKIF) {
+        uint16_t estat = reg_get(dev, ESTAT);
+
+        netdev2_event_t event = (estat & PHYLNK) ?
+            NETDEV2_EVENT_LINK_DOWN :
+            NETDEV2_EVENT_LINK_UP;
+
+        netdev->event_callback(netdev, event, NULL);
+    }
+
+    /* check & handle available packets */
+    if (eir & PKTIF) {
+        while (_packets_available(dev)) {
+            unlock(dev);
+            netdev->event_callback(netdev, NETDEV2_EVENT_RX_COMPLETE,
+                    NULL);
+            lock(dev);
+        }
+    }
+
+    /* drop all flags */
+    reg_clear_bits(dev, EIR, LINKIF);
+
+    /* re-enable interrupt */
+    gpio_irq_enable(dev->int_pin);
+    cmd(dev, SETEIE);
+
+    unlock(dev);
+}
+
+static inline void enc_spi_transfer(encx24j600_t *dev, char *out, char *in, int len)
+{
+    spi_acquire(dev->spi);
+    gpio_clear(dev->cs);
+    spi_transfer_bytes(dev->spi, out, in, len);
+    gpio_set(dev->cs);
+    spi_release(dev->spi);
+}
+
+static inline uint16_t reg_get(encx24j600_t *dev, uint8_t reg)
+{
+    char cmd[4] = { RCRU, reg, 0, 0 };
+    char result[4];
+
+    enc_spi_transfer(dev, cmd, result, 4);
+
+    return result[2] | (result[3] << 8);
+}
+
+static void phy_reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value) {
+    reg_set(dev, MIREGADR, reg | (1<<8));
+    reg_set(dev, MIWR, value);
+}
+
+static void cmd(encx24j600_t *dev, char cmd) {
+    spi_acquire(dev->spi);
+    gpio_clear(dev->cs);
+    spi_transfer_byte(dev->spi, cmd, NULL);
+    gpio_set(dev->cs);
+    spi_release(dev->spi);
+}
+
+static void cmdn(encx24j600_t *dev, uint8_t cmd, char *out, char *in, int len) {
+    spi_acquire(dev->spi);
+    gpio_clear(dev->cs);
+    spi_transfer_byte(dev->spi, cmd, NULL);
+    spi_transfer_bytes(dev->spi, out, in, len);
+    gpio_set(dev->cs);
+    spi_release(dev->spi);
+}
+
+static void reg_set(encx24j600_t *dev, uint8_t reg, uint16_t value)
+{
+    char cmd[4] = { WCRU, reg, value, value >> 8 };
+    enc_spi_transfer(dev, cmd, NULL, 4);
+}
+
+static void reg_set_bits(encx24j600_t *dev, uint8_t reg, uint16_t mask)
+{
+    char cmd[4] = { BFSU, reg, mask, mask >> 8 };
+    enc_spi_transfer(dev, cmd, NULL, 4);
+}
+
+static void reg_clear_bits(encx24j600_t *dev, uint8_t reg, uint16_t mask)
+{
+    char cmd[4] = { BFCU, reg, mask, mask >> 8 };
+    enc_spi_transfer(dev, cmd, NULL, 4);
+}
+
+/*
+ * @brief Read/Write to encx24j600's SRAM
+ *
+ * @param[in] dev   ptr to encx24j600 device handle
+ * @param[in] cmd   either WGPDATA, RGPDATA, WRXDATA, RRXDATA, WUDADATA, RUDADATA
+ * @param[in] addr  SRAM address to start reading. 0xFFFF means continue from old address
+ * @param     ptr   pointer to buffer to read from / write to
+ * @param[in] len   nr of bytes to read/write
+ */
+static void sram_op(encx24j600_t *dev, uint16_t cmd, uint16_t addr, char *ptr, int len)
+{
+    uint16_t reg;
+    char* in = NULL;
+    char* out = NULL;
+
+    /* determine pointer addr
+     *
+     * all SRAM access commands have an
+     * offset 0x5e to their pointer registers
+     * */
+    reg = cmd + 0x5e;
+
+    /* read or write? bit 1 tells us */
+    if (reg & 0x2) {
+        out = ptr;
+    } else {
+        in = ptr;
+    }
+
+    /* set pointer */
+    if (addr != 0xFFFF) {
+        reg_set(dev, reg, addr);
+    }
+
+    /* copy data */
+    cmdn(dev, cmd, in, out, len);
+}
+
+static int _init(netdev2_t *encdev)
+{
+    encx24j600_t *dev = (encx24j600_t *) encdev;
+
+    DEBUG("encx24j600: starting initialization...\n");
+
+    /* setup IO */
+    gpio_init(dev->cs, GPIO_DIR_OUT, GPIO_PULLUP);
+    gpio_set(dev->cs);
+    gpio_init_int(dev->int_pin, GPIO_PULLUP, GPIO_FALLING, encx24j600_isr, (void*)dev);
+
+    if (spi_init_master(dev->spi, SPI_CONF_FIRST_RISING, ENCX24J600_SPI_SPEED) < 0) {
+        return -1;
+    }
+
+    lock(dev);
+
+    /* initialization procedure as described in data sheet (39935c.pdf) */
+    do {
+        do {
+            vtimer_usleep(ENCX24J600_INIT_DELAY);
+            reg_set(dev, EUDAST, 0x1234);
+            vtimer_usleep(ENCX24J600_INIT_DELAY);
+        } while (reg_get(dev, EUDAST) != 0x1234);
+
+        while (!(reg_get(dev, ESTAT) & CLKRDY));
+
+        /* issue System Reset */
+        cmd(dev, SETETHRST);
+
+        /* make sure initialization finalizes */
+        vtimer_usleep(1000);
+    } while (!(reg_get(dev, EUDAST) == 0x0000));
+
+    /* configure flow control */
+    phy_reg_set(dev, PHANA, 0x05E1);
+    reg_set_bits(dev, ECON2, AUTOFC);
+
+    /* setup receive buffer */
+    reg_set(dev, ERXST, RX_BUFFER_START);
+    reg_set(dev, ERXTAIL, RX_BUFFER_END);
+    dev->rx_next_ptr = RX_BUFFER_START;
+
+    /* configure receive filter to receive multicast frames */
+    reg_set_bits(dev, ERXFCON, MCEN);
+
+    /* setup interrupts */
+    reg_set_bits(dev, EIE, PKTIE | LINKIE);
+    cmd(dev, ENABLERX);
+    cmd(dev, SETEIE);
+
+    DEBUG("encx24j600: initialization complete.\n");
+
+    unlock(dev);
+
+    return 0;
+}
+
+static int _send(netdev2_t *netdev, const struct iovec *vector, int count) {
+    encx24j600_t * dev = (encx24j600_t *) netdev;
+    lock(dev);
+
+    /* wait until previous packet has been sent */
+    while ((reg_get(dev, ECON1) & TXRTS));
+
+    /* copy packet to SRAM */
+    size_t len = 0;
+
+    for (int i = 0; i < count; i++) {
+        sram_op(dev, WGPDATA, (i ? 0xFFFF : TX_BUFFER_START), vector[i].iov_base, vector[i].iov_len);
+        len += vector[i].iov_len;
+    }
+
+    /* set start of TX packet and length */
+    reg_set(dev, ETXST, TX_BUFFER_START);
+    reg_set(dev, ETXLEN, len);
+
+    /* initiate sending */
+    cmd(dev, SETTXRTS);
+
+    /* wait for sending to complete */
+    /* (not sure if it is needed, keeping the line uncommented) */
+    /*while ((reg_get(dev, ECON1) & TXRTS));*/
+
+    unlock(dev);
+
+    return len;
+}
+
+static inline int _packets_available(encx24j600_t *dev)
+{
+    /* return PKTCNT (low byte of ESTAT) */
+    return reg_get(dev, ESTAT) & ~0xFF00;
+}
+
+static void _get_mac_addr(netdev2_t *encdev, uint8_t* buf)
+{
+    encx24j600_t * dev = (encx24j600_t *) encdev;
+    uint16_t *addr = (uint16_t *) buf;
+
+    lock(dev);
+
+    addr[0] = reg_get(dev, MAADR1);
+    addr[1] = reg_get(dev, MAADR2);
+    addr[2] = reg_get(dev, MAADR3);
+
+    unlock(dev);
+}
+
+static int _recv(netdev2_t *netdev, char* buf, int len)
+{
+    encx24j600_t * dev = (encx24j600_t *) netdev;
+    encx24j600_frame_hdr_t hdr;
+
+    lock(dev);
+
+    /* read frame header */
+    sram_op(dev, RRXDATA, dev->rx_next_ptr, (char*)&hdr, sizeof(hdr));
+
+    /* hdr.frame_len given by device contains 4 bytes checksum */
+    size_t payload_len = hdr.frame_len - 4;
+
+    if (buf) {
+        /* read packet (without 4 bytes checksum) */
+        sram_op(dev, RRXDATA, 0xFFFF, buf, payload_len);
+
+        /* decrement available packet count */
+        cmd(dev, SETPKTDEC);
+
+        dev->rx_next_ptr = hdr.rx_next_ptr;
+
+        reg_set(dev, ERXTAIL, dev->rx_next_ptr - 2);
+    }
+
+    unlock(dev);
+
+    return payload_len;
+}
+
+static int _get_iid(netdev2_t *netdev, eui64_t *value, size_t max_len)
+{
+    if (max_len < sizeof(eui64_t)) {
+        return -EOVERFLOW;
+    }
+
+    uint8_t addr[ETHERNET_ADDR_LEN];
+    _get_mac_addr(netdev, addr);
+    ethernet_get_iid(value, addr);
+
+    return sizeof(eui64_t);
+}
+
+int _get(netdev2_t *dev, netopt_t opt, void *value, size_t max_len)
+{
+    int res = 0;
+
+    switch (opt) {
+        case NETOPT_DEVICE_TYPE:
+            {
+               uint16_t *tgt = (uint16_t *)value;
+                *tgt = NETDEV2_TYPE_ETHERNET;
+                res = 2;
+                break;
+            }
+        case NETOPT_ADDRESS:
+            if (max_len < ETHERNET_ADDR_LEN) {
+                res = -EINVAL;
+            }
+            else {
+                _get_mac_addr(dev, (uint8_t*)value);
+                res = ETHERNET_ADDR_LEN;
+            }
+            break;
+        case NETOPT_ADDR_LEN:
+        case NETOPT_SRC_LEN:
+            assert(max_len == 2);
+            uint16_t *tgt = (uint16_t*)value;
+            *tgt=6;
+            res = sizeof(uint16_t);
+            break;
+        case NETOPT_IPV6_IID:
+            return _get_iid(dev, value, max_len);
+        default:
+            res = -ENOTSUP;
+            break;
+    }
+
+    return res;
+}
+
+int _set(netdev2_t *dev, netopt_t opt, void *value, size_t value_len)
+{
+    int res = 0;
+
+    switch (opt) {
+        default:
+            return -ENOTSUP;
+    }
+
+    return res;
+}
diff --git a/drivers/encx24j600/include/encx24j600_defines.h b/drivers/encx24j600/include/encx24j600_defines.h
new file mode 100644
index 0000000000..7f96f691db
--- /dev/null
+++ b/drivers/encx24j600/include/encx24j600_defines.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2015 Ell-i open source co-operative
+ *                    Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     driver_encx24j600
+ * @{
+ *
+ * @file
+ * @brief       Register definitions for the ENCX24J600 Ethernet device
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifndef ENCX24J600_REGS_H
+#define ENCX24J600_REGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name SPI instruction set
+ * @{
+ */
+#define RCR         0x00  /* read control register */
+#define WCR         0x04  /* write control register */
+
+#define RCRU        0x20  /* read control register unbanked */
+#define WCRU        0x22  /* write control register unbanked */
+
+#define BFSU        0x24  /* set bits unbanked */
+#define BFCU        0x26  /* clear bits unbanked */
+
+#define RGPDATA     0x28  /* Read EGPDATA */
+#define WGPDATA     0x2a  /* Write EGPDATA */
+
+#define RRXDATA     0x2c  /* Read ERXDATA */
+#define WRXDATA     0x2e  /* Write ERXDATA */
+
+#define RUDADATA    0x30  /* Read EUDADATA */
+#define WUDADATA    0x32  /* Write EUDADATA */
+
+#define BFS         0x80  /* Bit Field Set */
+#define BFC         0xa0  /* Bit Field Clear */
+
+#define SETETHRST   0xca  /* System Reset */
+#define SETPKTDEC   0xcc  /* Decrements PKTCNT by setting PKTDEC (ECON1<5>) */
+#define ENABLERX    0xe8  /* Enables packet reception by setting RXEN (ECON1<0>) */
+#define DISABLERX   0xea  /* Disable packet reception by clearing RXEN (ECON1<0>) */
+#define SETEIE      0xec  /* Enable Ethernet Interrupts by setting INT (ESTAT<16>) */
+#define CLREIE      0xee  /* Disable Ethernet Interrupts by clearing INT (ESTAT<16>) */
+
+#define B0SEL       0xc0  /* select bank 0 */
+#define B1SEL       0xc2  /* select bank 0 */
+#define B2SEL       0xc4  /* select bank 0 */
+#define B3SEL       0xc6  /* select bank 0 */
+#define RBSEL       0xc8  /* Read Bank Select */
+
+#define SETTXRTS    0xd4  /* Sets TXRTS (ECON1<1>), sends an Ethernet packet */
+/** @} */
+
+/**
+ * @name 16bit Registers
+ * @{
+ */
+#define ETXST       0x00
+#define ETXLEN      0x02
+#define ERXST       0x04
+#define ERXTAIL     0x06
+#define ERXHEAD     0x08
+#define ETXSTAT     0x12
+#define ETXWIRE     0x14
+#define EUDAST      0x16
+#define ESTAT       0x1a
+#define EIR         0x1c    /* Interrupt Flag Register */
+#define ECON1       0x1e
+
+#define ERXFCON     0x34    /* Receive filter control register */
+
+#define MACON2      0x42
+#define MAMXFL      0x4a    /* MAC maximum frame length */
+
+#define MAADR3      0x60    /* MAC address byte 5&6 */
+#define MAADR2      0x62    /* MAC address byte 3&4 */
+#define MAADR1      0x64    /* MAC address byte 1&2 */
+
+#define MIWR        0x66
+#define MIREGADR    0x54
+
+#define ECON2       0x6e
+
+#define EIE         0x72    /* Interrupt Enable Register */
+
+#define EGPRDPT     0x86    /* General Purpose SRAM read pointer */
+#define EGPWRPT     0x88    /* General Purpose SRAM write pointer */
+
+#define ERXRDPT     0x8a    /* RX buffer read pointer */
+#define ERXWRPT     0x8c    /* RX buffer write pointer */
+/** @} */
+
+/**
+ * @name PHY Registers
+ *
+ * (access with phy_reg_* functions)
+ *
+ * @{
+ */
+#define PHCON1  0x00
+#define PHSTAT1 0x01
+#define PHANA   0x04
+#define PHANLPA 0x05
+#define PHANE   0x06
+#define PHCON2  0x11
+#define PHSTAT2 0x1b
+#define PHSTAT3 0x1f
+/** @} */
+
+/**
+ * @name ESTAT bits
+ * @{
+ */
+#define PHYLNK  (1<<8)
+#define CLKRDY  (1<<12)
+/** @} */
+
+/**
+ * @name ECON1 bits
+ * @{
+ */
+#define RXEN    (1<<0)
+#define TXRTS   (1<<1)
+#define DMANOCS (1<<2)
+#define DMACSSD (1<<3)
+#define DMACPY  (1<<4)
+#define DMAST   (1<<5)
+#define FCOP0   (1<<6)
+#define FCOP1   (1<<7)
+#define PKTDEC  (1<<8)
+#define AESOP0  (1<<9)
+#define AESOP1  (1<<10)
+#define AESST   (1<<11)
+#define HASHLST (1<<12)
+#define HASHOP  (1<<13)
+#define HASHEN  (1<<14)
+#define MODEXST (1<<15)
+/** @} */
+
+/**
+ * @name ECON2 bits
+ * @{
+ */
+#define ETHRST    (1<<4)
+#define AUTOFC    (1<<7)    /* automatic flow control enable bit */
+/** @} */
+
+/**
+ * @name EIR bits
+ * @{
+ */
+#define PCFULIE     (1<<0)
+#define RXABTIE     (1<<1)
+#define TXABTIE     (1<<2)
+#define TXIE        (1<<3)
+#define DMAIE       (1<<5)
+#define PKTIE       (1<<6)
+#define LINKIE      (1<<11)
+#define AESIE       (1<<12)
+#define HASHIE      (1<<13)
+#define MODEXIE     (1<<14)
+#define INTIE       (1<<15)
+/** @} */
+
+/**
+ * @name EIR bits
+ * @{
+ */
+#define PCFULIF     (1<<0)
+#define RXABTIF     (1<<1)
+#define TXABTIF     (1<<2)
+#define TXIF        (1<<3)
+#define DMAIF       (1<<5)
+#define PKTIF       (1<<6)
+#define LINKIF      (1<<11)
+#define AESIF       (1<<12)
+#define HASHIF      (1<<13)
+#define MODEXIF     (1<<14)
+#define CRYPTEN     (1<<15)
+/** @} */
+
+/**
+ * @name ERXFCON bits
+ */
+#define MCEN        (1<<1)
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* ENCX24J600_REGS_H */
+/** @} */
diff --git a/drivers/encx24j600/include/encx24j600_internal.h b/drivers/encx24j600/include/encx24j600_internal.h
new file mode 100644
index 0000000000..b718465a68
--- /dev/null
+++ b/drivers/encx24j600/include/encx24j600_internal.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 Ell-i open source co-operative
+ *                    Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup     driver_encx24j600
+ * @{
+ *
+ * @file
+ * @brief       Internal definitions for the ENCX24J600 Ethernet device
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifndef ENCX24J600_INTERNAL_H
+#define ENCX24J600_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief structure resembling format as sent by device
+ */
+typedef struct __attribute__((packed)) encx24j600_frame_hdr {
+    uint16_t rx_next_ptr;       /**< ptr to next packet whithin devices memory */
+
+    /* Receive Status Vector */
+    uint16_t frame_len;         /**< lenght of ethernet frame including 4 bytes
+                                     checksum */
+    uint32_t flags;             /**< random flag field just mentioned for the
+                                     sake of documentation completeness */
+} encx24j600_frame_hdr_t;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* ENCX24J600_INTERNAL_H */
+/** @} */
diff --git a/drivers/include/encx24j600.h b/drivers/include/encx24j600.h
new file mode 100644
index 0000000000..28d5e200a1
--- /dev/null
+++ b/drivers/include/encx24j600.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @defgroup    driver_encx24j600 ENCX24J600
+ * @ingroup     drivers
+ * @brief       Driver for the ENCX24J600 Ethernet Adapter
+ * @{
+ *
+ * @file
+ * @brief       Interface definition for the ENCX24J600 driver
+ *
+ * @author      Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifndef ENCX24J600_H
+#define ENCX24J600_H
+
+#include "mutex.h"
+#include "kernel_types.h"
+#include "periph/spi.h"
+#include "periph/gpio.h"
+#include "net/netdev2.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief encx24j600 netdev2 device
+ * @extends netdev2_t
+ */
+typedef struct {
+    netdev2_t netdev;       /**< extended netdev2 structure */
+    spi_t spi;              /**< SPI device the enc is connected to*/
+    gpio_t cs;              /**< SPI chip select pin */
+    gpio_t int_pin;         /**< SPI interrupt pin */
+    uint16_t rx_next_ptr;   /**< ptr to next packet whithin devices memory */
+    mutex_t mutex;          /**< mutex used to lock device access */
+} encx24j600_t;
+
+/**
+ * @brief Setup an encx24j600 based device state.
+ *
+ * This function sets SPI pins, initializes the device state structure.
+ * It does not initialize the device itself.
+ *
+ * @param[out]  dev     the handle of the device to initialize
+ * @param[in]   spi     SPI device the device is connected to
+ * @param[in]   cs_pin  SPI chip select pin used to select the device
+ * @param[in]   int_pin pin the device will trigger an interrupt on
+ */
+void encx24j600_setup(encx24j600_t *dev, spi_t spi, gpio_t cs_pin, gpio_t int_pin);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* ENCX24J600_H */
+/** @} */
diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c
index 32692045fd..1244f6b2c4 100644
--- a/sys/auto_init/auto_init.c
+++ b/sys/auto_init/auto_init.c
@@ -166,6 +166,11 @@ void auto_init(void)
     auto_init_at86rf2xx();
 #endif
 
+#ifdef MODULE_ENCX24J600
+    extern void auto_init_encx24j600(void);
+    auto_init_encx24j600();
+#endif
+
 #ifdef MODULE_GNRC_SLIP
     extern void auto_init_slip(void);
     auto_init_slip();
diff --git a/sys/auto_init/netif/auto_init_encx24j600.c b/sys/auto_init/netif/auto_init_encx24j600.c
new file mode 100644
index 0000000000..3236dfb02d
--- /dev/null
+++ b/sys/auto_init/netif/auto_init_encx24j600.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ *
+ */
+
+/**
+ * @ingroup auto_init_gnrc_netif
+ * @{
+ *
+ * @file
+ * @brief   Auto initialization for ENCx24j600 ethernet devices
+ *
+ * @author  Kaspar Schleiser <kaspar@schleiser.de>
+ */
+
+#ifdef MODULE_ENCX24J600
+
+#define ENABLE_DEBUG (0)
+#include "debug.h"
+
+#include "encx24j600.h"
+#include "net/gnrc/gnrc_netdev2_eth.h"
+
+static encx24j600_t encx24j600;
+
+/**
+ * @brief   Define stack parameters for the MAC layer thread
+ * @{
+ */
+#define MAC_STACKSIZE           (THREAD_STACKSIZE_DEFAULT + DEBUG_EXTRA_STACKSIZE)
+#define MAC_PRIO                (THREAD_PRIORITY_MAIN - 4)
+
+/**
+ * @brief   Stacks for the MAC layer threads
+ */
+static char _netdev2_eth_stack[MAC_STACKSIZE + DEBUG_EXTRA_STACKSIZE];
+static gnrc_netdev2_t _gnrc_encx24j600;
+
+void auto_init_encx24j600(void)
+{
+    DEBUG("auto_init_encx24j600(): initializing device...\n");
+    /* setup netdev2 device */
+    encx24j600_setup(&encx24j600, ENCX24J600_SPI, ENCX24J600_CS, ENCX24J600_INT);
+
+    /* initialize netdev2<->gnrc adapter state */
+    gnrc_netdev2_eth_init(&_gnrc_encx24j600, (netdev2_t*)&encx24j600);
+
+    /* start gnrc netdev2 thread */
+    gnrc_netdev2_init(_netdev2_eth_stack, MAC_STACKSIZE,
+            MAC_PRIO, "gnrc_encx24j600", &_gnrc_encx24j600);
+}
+
+#else
+typedef int dont_be_pedantic;
+#endif /* MODULE_ENCX24J600 */
+/** @} */
-- 
GitLab