driver: ENC28J60 Ethernet SPI module
Adds the ENC28J60 Ethernet module driver. Origin: Original JIRA: ZEP-291 Change-Id: I2b5790ecb251f9059f172bcaafadef24bd27207a Signed-off-by: Juan Manuel Cruz <juan.m.cruz.alcaraz@intel.com>
This commit is contained in:
parent
538d8d184d
commit
184a399f61
6 changed files with 1058 additions and 0 deletions
|
@ -91,3 +91,5 @@ config ETH_DW_0_IRQ_PRI
|
|||
IRQ priority
|
||||
|
||||
endif # ETH_DW
|
||||
|
||||
source "drivers/ethernet/Kconfig.enc28j60"
|
||||
|
|
103
drivers/ethernet/Kconfig.enc28j60
Normal file
103
drivers/ethernet/Kconfig.enc28j60
Normal file
|
@ -0,0 +1,103 @@
|
|||
# Kconfig - ETH_ENC28J60 Ethernet driver configuration options
|
||||
|
||||
#
|
||||
# Copyright (c) 2015 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
menuconfig ETH_ENC28J60
|
||||
bool "ENC28J60C Ethernet Controller"
|
||||
depends on ETHERNET
|
||||
depends on SPI
|
||||
default n
|
||||
help
|
||||
ENC28J60C Stand-Alone Ethernet Controller
|
||||
with SPI Interface
|
||||
|
||||
config ETH_ENC28J60_0
|
||||
bool "ENC28J60C Ethernet port 0"
|
||||
depends on ETH_ENC28J60
|
||||
default n
|
||||
help
|
||||
Include port 0 driver
|
||||
|
||||
if ETH_ENC28J60 && ETH_ENC28J60_0
|
||||
config ETH_ENC28J60_0_NAME
|
||||
string "Driver's name"
|
||||
default "ETH_0"
|
||||
|
||||
config ETH_ENC28J60_0_INIT_PRIORITY
|
||||
int
|
||||
prompt "ENC28J60C init priority"
|
||||
default 80
|
||||
help
|
||||
Device driver initialization priority.
|
||||
Since the device is connected to SPI bus, its driver has
|
||||
to be initialized after the SPI one.
|
||||
|
||||
config ETH_ENC28J60_0_GPIO_PORT_NAME
|
||||
string "GPIO controller port name"
|
||||
default "GPIO_0"
|
||||
help
|
||||
GPIO port name through which ENC28J60C interruption is received.
|
||||
|
||||
config ETH_ENC28J60_0_GPIO_PIN
|
||||
int "ENC28J60C INT GPIO PIN"
|
||||
default 24
|
||||
help
|
||||
GPIO pin number used to conect INT
|
||||
|
||||
config ETH_ENC28J60_0_SPI_PORT_NAME
|
||||
string "SPI master controller port name"
|
||||
default "SPI_0"
|
||||
help
|
||||
Master I2C port name through which ENC28J60C chip is accessed.
|
||||
|
||||
config ETH_ENC28J60_0_SLAVE
|
||||
hex "ETH_ENC28J60 SPI slave select pin"
|
||||
default 1
|
||||
help
|
||||
ENC28J60C chip select pin.
|
||||
|
||||
config ETH_ENC28J60_0_SPI_BUS_FREQ
|
||||
int "ENC28J60C SPI bus speed in Hz"
|
||||
default 128
|
||||
help
|
||||
This is the maximum supported SPI bus frequency.
|
||||
|
||||
config ETH_ENC28J60_0_MAC3
|
||||
hex "MAC Address Byte 3"
|
||||
default 0
|
||||
help
|
||||
MACADDR<0:23> are Microchip's OUI.
|
||||
This is the byte 3 of the MAC address.
|
||||
MACADDR<31:24>
|
||||
|
||||
config ETH_ENC28J60_0_MAC4
|
||||
hex "MAC Address Byte 4"
|
||||
default 0
|
||||
help
|
||||
MACADDR<0:23> are Microchip's OUI.
|
||||
This is the byte 4 of the MAC address.
|
||||
MACADDR<40:32>
|
||||
|
||||
config ETH_ENC28J60_0_MAC5
|
||||
hex "MAC Address Byte 5"
|
||||
default 0
|
||||
help
|
||||
MACADDR<0:23> are Microchip's OUI.
|
||||
This is the byte 5 of the MAC address.
|
||||
MACADDR<48:41>
|
||||
|
||||
endif #ETH_ENC28J60 && ETH_ENC28J60_0
|
|
@ -5,3 +5,4 @@ ccflags-y += -I${srctree}/net/ip
|
|||
ccflags-y += -I${srctree}
|
||||
|
||||
obj-$(CONFIG_ETH_DW) += eth_dw.o
|
||||
obj-$(CONFIG_ETH_ENC28J60) += eth_enc28j60.o
|
||||
|
|
619
drivers/ethernet/eth_enc28j60.c
Normal file
619
drivers/ethernet/eth_enc28j60.c
Normal file
|
@ -0,0 +1,619 @@
|
|||
/* ENC28J60 Stand-alone Ethernet Controller with SPI
|
||||
*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <net/ip/net_driver_ethernet.h>
|
||||
#include <zephyr.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <gpio.h>
|
||||
#include <spi.h>
|
||||
#include <eth.h>
|
||||
|
||||
#include "eth_enc28j60_priv.h"
|
||||
|
||||
#define D10D24S 11
|
||||
#define MAX_BUFFER_LENGTH 100
|
||||
|
||||
static int eth_net_tx(struct net_buf *buf);
|
||||
static void enc28j60_fiber_main(int arg1, int unused);
|
||||
|
||||
static int eth_enc28j60_soft_reset(struct device *dev)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t tx_buf[2] = {ENC28J60_SPI_SC, 0xFF};
|
||||
|
||||
return spi_write(context->spi, tx_buf, 2);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_set_bank(struct device *dev, uint16_t reg_addr)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t tx_buf[2];
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_RCR | ENC28J60_REG_ECON1;
|
||||
tx_buf[1] = 0x0;
|
||||
|
||||
spi_transceive(context->spi, tx_buf, 2, tx_buf, 2);
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_WCR | ENC28J60_REG_ECON1;
|
||||
tx_buf[1] = (tx_buf[1] & 0xFC) | ((reg_addr >> 8) & 0x0F);
|
||||
|
||||
spi_write(context->spi, tx_buf, 2);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_write_reg(struct device *dev, uint16_t reg_addr,
|
||||
uint8_t value)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t tx_buf[2];
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_WCR | (reg_addr & 0xFF);
|
||||
tx_buf[1] = value;
|
||||
|
||||
spi_write(context->spi, tx_buf, 2);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_read_reg(struct device *dev, uint16_t reg_addr,
|
||||
uint8_t *value)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t tx_size = 2;
|
||||
uint8_t tx_buf[3];
|
||||
|
||||
if (reg_addr & 0xF000) {
|
||||
tx_size = 3;
|
||||
}
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_RCR | (reg_addr & 0xFF);
|
||||
tx_buf[1] = 0x0;
|
||||
|
||||
spi_transceive(context->spi, tx_buf, tx_size, tx_buf, tx_size);
|
||||
|
||||
*value = tx_buf[tx_size - 1];
|
||||
}
|
||||
|
||||
static void eth_enc28j60_set_eth_reg(struct device *dev, uint16_t reg_addr,
|
||||
uint8_t value)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t tx_buf[2];
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_BFS | (reg_addr & 0xFF);
|
||||
tx_buf[1] = value;
|
||||
|
||||
spi_write(context->spi, tx_buf, 2);
|
||||
}
|
||||
|
||||
|
||||
static void eth_enc28j60_clear_eth_reg(struct device *dev, uint16_t reg_addr,
|
||||
uint8_t value)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t tx_buf[2];
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_BFC | (reg_addr & 0xFF);
|
||||
tx_buf[1] = value;
|
||||
|
||||
spi_write(context->spi, tx_buf, 2);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_write_mem(struct device *dev, uint8_t *data_buffer,
|
||||
uint8_t buf_len)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t tx_buf[MAX_BUFFER_LENGTH + 1];
|
||||
uint8_t *index_buf;
|
||||
uint16_t num_segments;
|
||||
uint16_t num_remanents;
|
||||
|
||||
index_buf = data_buffer;
|
||||
num_segments = buf_len / MAX_BUFFER_LENGTH;
|
||||
num_remanents = buf_len - MAX_BUFFER_LENGTH * num_segments;
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_WBM;
|
||||
|
||||
for (int i = 0; i < num_segments;
|
||||
++i, index_buf += i * MAX_BUFFER_LENGTH) {
|
||||
|
||||
memcpy(tx_buf + 1, index_buf, MAX_BUFFER_LENGTH);
|
||||
|
||||
spi_write(context->spi, tx_buf, MAX_BUFFER_LENGTH + 1);
|
||||
|
||||
}
|
||||
memcpy(tx_buf + 1, index_buf, num_remanents);
|
||||
|
||||
spi_write(context->spi, tx_buf, num_remanents + 1);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_read_mem(struct device *dev, uint8_t *data_buffer,
|
||||
uint8_t buf_len)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t *index_buf;
|
||||
uint8_t tx_buf[MAX_BUFFER_LENGTH + 1];
|
||||
uint16_t num_segments;
|
||||
uint16_t num_remanents;
|
||||
|
||||
index_buf = data_buffer;
|
||||
num_segments = buf_len / MAX_BUFFER_LENGTH;
|
||||
num_remanents = buf_len - MAX_BUFFER_LENGTH * num_segments;
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_RBM;
|
||||
|
||||
for (int i = 0; i < num_segments;
|
||||
++i, index_buf += i * MAX_BUFFER_LENGTH) {
|
||||
|
||||
spi_transceive(context->spi, tx_buf, MAX_BUFFER_LENGTH + 1,
|
||||
tx_buf, MAX_BUFFER_LENGTH + 1);
|
||||
|
||||
memcpy(index_buf, tx_buf + 1, MAX_BUFFER_LENGTH);
|
||||
}
|
||||
|
||||
spi_transceive(context->spi, tx_buf, num_remanents + 1,
|
||||
tx_buf, num_remanents + 1);
|
||||
|
||||
memcpy(index_buf, tx_buf + 1, num_remanents);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_read_phy(struct device *dev, uint16_t reg_addr,
|
||||
int16_t *data)
|
||||
{
|
||||
uint8_t rl, rh;
|
||||
uint8_t data_mistat;
|
||||
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_MIREGADR);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MIREGADR, reg_addr);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MICMD,
|
||||
ENC28J60_BIT_MICMD_MIIRD);
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_MISTAT);
|
||||
|
||||
do {
|
||||
/* wait 10.24 useconds */
|
||||
sys_thread_busy_wait(D10D24S);
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_MISTAT,
|
||||
&data_mistat);
|
||||
} while ((data_mistat & ENC28J60_BIT_MISTAT_BUSY));
|
||||
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_MIREGADR);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MICMD, 0x00);
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_MIRDL, &rl);
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_MIRDH, &rh);
|
||||
*data = rl | ((uint16_t)rh << 8);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_write_phy(struct device *dev, uint16_t reg_addr,
|
||||
int16_t data)
|
||||
{
|
||||
uint8_t data_mistat;
|
||||
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_MIREGADR);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MIREGADR, reg_addr);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MIWRL, data & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MIWRH, data >> 8);
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_MISTAT);
|
||||
|
||||
do {
|
||||
/* wait 10.24 useconds */
|
||||
sys_thread_busy_wait(D10D24S);
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_MISTAT,
|
||||
&data_mistat);
|
||||
} while ((data_mistat & ENC28J60_BIT_MISTAT_BUSY));
|
||||
}
|
||||
|
||||
static void eth_enc28j60_gpio_callback(struct device *dev,
|
||||
struct gpio_callback *cb,
|
||||
uint32_t pins)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context =
|
||||
CONTAINER_OF(cb, struct eth_enc28j60_runtime, gpio_cb);
|
||||
|
||||
nano_fiber_sem_give(&context->int_sem);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_init_buffers(struct device *dev)
|
||||
{
|
||||
uint8_t data_estat;
|
||||
|
||||
/* Reception buffers initialization */
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_ERXSTL);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXSTL,
|
||||
ENC28J60_RXSTART & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXSTH,
|
||||
ENC28J60_RXSTART >> 8);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXRDPTL,
|
||||
ENC28J60_RXSTART & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXRDPTH,
|
||||
ENC28J60_RXSTART >> 8);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXNDL,
|
||||
ENC28J60_RXEND & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXNDH,
|
||||
ENC28J60_RXEND >> 8);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXSTL,
|
||||
ENC28J60_TXSTART & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXSTH,
|
||||
ENC28J60_TXSTART >> 8);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXNDL,
|
||||
ENC28J60_TXEND & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXNDH,
|
||||
ENC28J60_TXEND >> 8);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERDPTL,
|
||||
ENC28J60_RXSTART & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERDPTH,
|
||||
ENC28J60_RXSTART >> 8);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_EWRPTL,
|
||||
ENC28J60_TXSTART & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_EWRPTH,
|
||||
ENC28J60_TXSTART >> 8);
|
||||
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_ERXFCON);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXFCON,
|
||||
ENC28J60_RECEIVE_FILTERS);
|
||||
|
||||
/* Waiting for OST */
|
||||
do {
|
||||
/* wait 10.24 useconds */
|
||||
sys_thread_busy_wait(D10D24S);
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_ESTAT, &data_estat);
|
||||
} while (!(data_estat & ENC28J60_BIT_ESTAT_CLKRDY));
|
||||
}
|
||||
|
||||
static void eth_enc28j60_init_mac(struct device *dev)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t data_macon;
|
||||
uint8_t mac_address[6];
|
||||
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_MACON1);
|
||||
|
||||
/* Set MARXEN to enable MAC to receive frames */
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_MACON1, &data_macon);
|
||||
data_macon |= ENC28J60_BIT_MACON1_MARXEN | ENC28J60_BIT_MACON1_RXPAUS
|
||||
| ENC28J60_BIT_MACON1_TXPAUS;
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MACON1, data_macon);
|
||||
|
||||
data_macon = ENC28J60_MAC_CONFIG;
|
||||
|
||||
if (context->full_duplex) {
|
||||
data_macon |= ENC28J60_BIT_MACON3_FULDPX;
|
||||
}
|
||||
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MACON3, data_macon);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAIPGL, ENC28J60_MAC_NBBIPGL);
|
||||
|
||||
if (context->full_duplex) {
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAIPGH,
|
||||
ENC28J60_MAC_NBBIPGH);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MABBIPG,
|
||||
ENC28J60_MAC_BBIPG_FD);
|
||||
} else {
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MABBIPG,
|
||||
ENC28J60_MAC_BBIPG_HD);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MACON4, 1 << 6);
|
||||
}
|
||||
|
||||
/* Configure MAC address */
|
||||
mac_address[0] = MICROCHIP_OUI_B0;
|
||||
mac_address[1] = MICROCHIP_OUI_B1;
|
||||
mac_address[2] = MICROCHIP_OUI_B2;
|
||||
mac_address[3] = CONFIG_ETH_ENC28J60_0_MAC3;
|
||||
mac_address[4] = CONFIG_ETH_ENC28J60_0_MAC4;
|
||||
mac_address[5] = CONFIG_ETH_ENC28J60_0_MAC5;
|
||||
net_set_mac(mac_address, sizeof(mac_address));
|
||||
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAADR0,
|
||||
CONFIG_ETH_ENC28J60_0_MAC5);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAADR1,
|
||||
CONFIG_ETH_ENC28J60_0_MAC4);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAADR2,
|
||||
CONFIG_ETH_ENC28J60_0_MAC3);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAADR3, MICROCHIP_OUI_B2);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAADR4, MICROCHIP_OUI_B1);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_MAADR5, MICROCHIP_OUI_B0);
|
||||
}
|
||||
|
||||
static void eth_enc28j60_init_phy(struct device *dev)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
|
||||
if (context->full_duplex) {
|
||||
eth_enc28j60_write_phy(dev, ENC28J60_PHY_PHCON1,
|
||||
ENC28J60_BIT_PHCON1_PDPXMD);
|
||||
eth_enc28j60_write_phy(dev, ENC28J60_PHY_PHCON2, 0x0);
|
||||
} else {
|
||||
eth_enc28j60_write_phy(dev, ENC28J60_PHY_PHCON1, 0x0);
|
||||
eth_enc28j60_write_phy(dev, ENC28J60_PHY_PHCON2,
|
||||
ENC28J60_BIT_PHCON2_HDLDIS);
|
||||
}
|
||||
}
|
||||
|
||||
static int eth_enc28j60_init(struct device *dev)
|
||||
{
|
||||
struct eth_enc28j60_config *config = dev->config->config_info;
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
struct spi_config spi_cfg;
|
||||
uint16_t data_phy;
|
||||
|
||||
context->gpio = device_get_binding((char *)config->gpio_port);
|
||||
if (!context->gpio) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
context->spi = device_get_binding((char *)config->spi_port);
|
||||
if (!context->spi) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize GPIO */
|
||||
if (gpio_pin_configure(context->gpio, config->gpio_pin,
|
||||
(GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE
|
||||
| GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpio_init_callback(&(context->gpio_cb), eth_enc28j60_gpio_callback,
|
||||
BIT(config->gpio_pin));
|
||||
|
||||
if (gpio_add_callback(context->gpio, &(context->gpio_cb))) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (gpio_pin_enable_callback(context->gpio, config->gpio_pin)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Initialize SPI:
|
||||
* Mode: 0/0; Size: 8 bits; MSB
|
||||
*/
|
||||
spi_cfg.config = 8 << 4;
|
||||
spi_cfg.max_sys_freq = config->spi_freq;
|
||||
|
||||
if (spi_configure(context->spi, &spi_cfg) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (spi_slave_select(context->spi, config->spi_slave) < 0) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (eth_enc28j60_soft_reset(dev)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Errata B7/2 */
|
||||
sys_thread_busy_wait(D10D24S);
|
||||
|
||||
/* Select half-duplex/full-duplex from LED configuration */
|
||||
eth_enc28j60_read_phy(dev, ENC28J60_PHY_PHCON1, &data_phy);
|
||||
data_phy &= ENC28J60_BIT_PHCON1_PDPXMD;
|
||||
context->full_duplex = !!(data_phy);
|
||||
|
||||
eth_enc28j60_init_buffers(dev);
|
||||
eth_enc28j60_init_mac(dev);
|
||||
eth_enc28j60_init_phy(dev);
|
||||
|
||||
/* Enable interruptions */
|
||||
eth_enc28j60_set_eth_reg(dev, ENC28J60_REG_EIE, ENC28J60_BIT_EIE_INTIE);
|
||||
eth_enc28j60_set_eth_reg(dev, ENC28J60_REG_EIE, ENC28J60_BIT_EIE_TXIE);
|
||||
eth_enc28j60_set_eth_reg(dev, ENC28J60_REG_EIE, ENC28J60_BIT_EIE_PKTIE);
|
||||
|
||||
/* Enable Reception */
|
||||
eth_enc28j60_set_eth_reg(dev, ENC28J60_REG_ECON1,
|
||||
ENC28J60_BIT_ECON1_RXEN);
|
||||
|
||||
/* Register tx callback into IP stack */
|
||||
net_driver_ethernet_register_tx(eth_net_tx);
|
||||
|
||||
/* Initialize semaphores */
|
||||
nano_sem_init(&context->tx_sem);
|
||||
nano_sem_init(&context->int_sem);
|
||||
|
||||
/* Start interruption-poll fiber */
|
||||
fiber_start(context->fiber_stack, ENC28J60_FIBER_STACK_SIZE,
|
||||
enc28j60_fiber_main, (int)dev, 0,
|
||||
ENC28J60_FIBER_PRIORITY, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eth_enc28j60_tx(struct device *dev, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint16_t tx_bufaddr = ENC28J60_TXSTART;
|
||||
uint8_t per_packet_control;
|
||||
uint16_t tx_bufaddr_end;
|
||||
uint8_t tx_end;
|
||||
|
||||
nano_fiber_sem_take(&context->tx_sem, TICKS_UNLIMITED);
|
||||
|
||||
/* Latest errata sheet: DS80349C
|
||||
* always reset transmit logic (Errata Issue 12)
|
||||
* the Microchip TCP/IP stack implementation used to first check
|
||||
* whether TXERIF is set and only then reset the transmit logic
|
||||
* but this has been changed in later versions; possibly they
|
||||
* have a reason for this; they don't mention this in the errata
|
||||
* sheet
|
||||
*/
|
||||
eth_enc28j60_set_eth_reg(dev, ENC28J60_REG_ECON1,
|
||||
ENC28J60_BIT_ECON1_TXRST);
|
||||
eth_enc28j60_clear_eth_reg(dev, ENC28J60_REG_ECON1,
|
||||
ENC28J60_BIT_ECON1_TXRST);
|
||||
|
||||
/* Write the buffer content into the transmission buffer */
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_ETXSTL);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_EWRPTL, tx_bufaddr & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_EWRPTH, tx_bufaddr >> 8);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXSTL, tx_bufaddr & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXSTH, tx_bufaddr >> 8);
|
||||
|
||||
/* Write the data into the buffer */
|
||||
per_packet_control = ENC28J60_PPCTL_BYTE;
|
||||
eth_enc28j60_write_mem(dev, &per_packet_control, 1);
|
||||
eth_enc28j60_write_mem(dev, buf, len);
|
||||
|
||||
tx_bufaddr_end = tx_bufaddr + len;
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXNDL,
|
||||
tx_bufaddr_end & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ETXNDH, tx_bufaddr_end >> 8);
|
||||
|
||||
/* Clear transmit interruption flag */
|
||||
eth_enc28j60_clear_eth_reg(dev, ENC28J60_REG_EIR,
|
||||
ENC28J60_BIT_EIR_TXIF
|
||||
| ENC28J60_BIT_EIR_TXERIF);
|
||||
/* Signal ENC28J60 to send the buffer */
|
||||
eth_enc28j60_set_eth_reg(dev, ENC28J60_REG_ECON1,
|
||||
ENC28J60_BIT_ECON1_TXRTS);
|
||||
|
||||
do {
|
||||
/* wait 10.24 useconds */
|
||||
sys_thread_busy_wait(D10D24S);
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &tx_end);
|
||||
tx_end &= ENC28J60_BIT_EIR_TXIF;
|
||||
} while (!tx_end);
|
||||
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &tx_end);
|
||||
|
||||
nano_sem_give(&context->tx_sem);
|
||||
|
||||
if (tx_end & ENC28J60_BIT_ESTAT_TXABRT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eth_enc28j60_rx(struct device *dev)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
uint8_t rx_flag;
|
||||
|
||||
/* Check if there are received frames in buffer */
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &rx_flag);
|
||||
|
||||
rx_flag &= ENC28J60_BIT_EIR_PKTIF;
|
||||
while (rx_flag) {
|
||||
struct net_buf *buf;
|
||||
uint8_t np[2];
|
||||
uint8_t *reception_buf;
|
||||
uint16_t frm_len = 0;
|
||||
uint16_t next_packet;
|
||||
|
||||
/* Read address for next packet */
|
||||
eth_enc28j60_read_mem(dev, np, 2);
|
||||
next_packet = np[0] | (uint16_t)np[1] << 8;
|
||||
|
||||
/* Read reception status vector */
|
||||
eth_enc28j60_read_mem(dev, context->rx_rsv, 4);
|
||||
|
||||
/* Get the frame length from the rx status vector */
|
||||
frm_len = (context->rx_rsv[1] << 8) | context->rx_rsv[0];
|
||||
|
||||
if (frm_len > UIP_BUFSIZE) {
|
||||
return -EIO;
|
||||
}
|
||||
/* Get the frame from the buffer */
|
||||
buf = ip_buf_get_reserve_rx(0);
|
||||
reception_buf = net_buf_add(buf, frm_len);
|
||||
|
||||
eth_enc28j60_read_mem(dev, reception_buf, frm_len);
|
||||
uip_len(buf) = frm_len;
|
||||
|
||||
/* Register the buffer frame with the IP stack */
|
||||
net_driver_ethernet_recv(buf);
|
||||
|
||||
/* Free buffer memory and decrement rx counter */
|
||||
eth_enc28j60_set_bank(dev, ENC28J60_REG_ERXRDPTL);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXRDPTL,
|
||||
next_packet & 0xFF);
|
||||
eth_enc28j60_write_reg(dev, ENC28J60_REG_ERXRDPTH,
|
||||
next_packet >> 8);
|
||||
eth_enc28j60_set_eth_reg(dev, ENC28J60_REG_ECON2,
|
||||
ENC28J60_BIT_ECON2_PKTDEC);
|
||||
|
||||
/* Call receive callback */
|
||||
if (context->receive_callback) {
|
||||
context->receive_callback(reception_buf, frm_len);
|
||||
}
|
||||
|
||||
/* Check if there are frames to clean from the buffer */
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &rx_flag);
|
||||
rx_flag &= ENC28J60_BIT_EIR_PKTIF;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void eth_enc28j60_reg_cb(struct device *dev,
|
||||
void (*cb)(uint8_t *buffer, uint16_t len))
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
|
||||
context->receive_callback = cb;
|
||||
}
|
||||
|
||||
static void enc28j60_fiber_main(int arg1, int unused)
|
||||
{
|
||||
struct device *dev = (struct device *)arg1;
|
||||
struct eth_enc28j60_runtime *context;
|
||||
uint8_t int_stat;
|
||||
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
context = dev->driver_data;
|
||||
|
||||
while (1) {
|
||||
nano_fiber_sem_take(&context->int_sem, TICKS_UNLIMITED);
|
||||
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &int_stat);
|
||||
|
||||
if (int_stat & ENC28J60_BIT_EIR_PKTIF) {
|
||||
eth_enc28j60_rx(dev);
|
||||
/* Clear rx interruption flag */
|
||||
eth_enc28j60_clear_eth_reg(dev, ENC28J60_REG_EIR,
|
||||
ENC28J60_BIT_EIR_PKTIF
|
||||
| ENC28J60_BIT_EIR_RXERIF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct eth_driver_api api_funcs = {
|
||||
.send = eth_enc28j60_tx,
|
||||
.register_callback = eth_enc28j60_reg_cb,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ETH_ENC28J60_0
|
||||
static struct eth_enc28j60_runtime eth_enc28j60_0_runtime = {
|
||||
.receive_callback = NULL,
|
||||
};
|
||||
|
||||
static struct eth_enc28j60_config eth_enc28j60_0_config = {
|
||||
.gpio_port = CONFIG_ETH_ENC28J60_0_GPIO_PORT_NAME,
|
||||
.gpio_pin = CONFIG_ETH_ENC28J60_0_GPIO_PIN,
|
||||
.spi_port = CONFIG_ETH_ENC28J60_0_SPI_PORT_NAME,
|
||||
.spi_freq = CONFIG_ETH_ENC28J60_0_SPI_BUS_FREQ,
|
||||
.spi_slave = CONFIG_ETH_ENC28J60_0_SLAVE,
|
||||
};
|
||||
|
||||
DEVICE_AND_API_INIT(eth_enc28j60_0, CONFIG_ETH_ENC28J60_0_NAME,
|
||||
ð_enc28j60_init, ð_enc28j60_0_runtime,
|
||||
ð_enc28j60_0_config, SECONDARY,
|
||||
CONFIG_ETH_ENC28J60_0_INIT_PRIORITY, &api_funcs);
|
||||
|
||||
static int eth_net_tx(struct net_buf *buf)
|
||||
{
|
||||
return eth_enc28j60_tx(DEVICE_GET(eth_enc28j60_0),
|
||||
uip_buf(buf), uip_len(buf));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ETH_ENC28J60_0 */
|
248
drivers/ethernet/eth_enc28j60_priv.h
Normal file
248
drivers/ethernet/eth_enc28j60_priv.h
Normal file
|
@ -0,0 +1,248 @@
|
|||
/* ENC28J60 Stand-alone Ethernet Controller with SPI
|
||||
*
|
||||
* Copyright (c) 2016 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <nanokernel.h>
|
||||
#include <gpio.h>
|
||||
|
||||
#ifndef _ENC28J60_
|
||||
#define _ENC28J60_
|
||||
|
||||
/* Any Bank Registers */
|
||||
#define ENC28J60_REG_EIE 0x1B
|
||||
#define ENC28J60_REG_EIR 0x1C
|
||||
#define ENC28J60_REG_ESTAT 0x1D
|
||||
#define ENC28J60_REG_ECON2 0x1E
|
||||
#define ENC28J60_REG_ECON1 0x1F
|
||||
|
||||
/* Register Encoding
|
||||
* Byte 3 : 0x0 ETH Register
|
||||
* 0x1 MAC Register
|
||||
* 0x2 MII Register
|
||||
* Byte 2 : Bank number
|
||||
* Byte 1-0: Register address
|
||||
*/
|
||||
|
||||
/* Bank 0 Registers */
|
||||
#define ENC28J60_REG_ERDPTL 0x0000
|
||||
#define ENC28J60_REG_ERDPTH 0x0001
|
||||
#define ENC28J60_REG_EWRPTL 0x0002
|
||||
#define ENC28J60_REG_EWRPTH 0x0003
|
||||
#define ENC28J60_REG_ETXSTL 0x0004
|
||||
#define ENC28J60_REG_ETXSTH 0x0005
|
||||
#define ENC28J60_REG_ETXNDL 0x0006
|
||||
#define ENC28J60_REG_ETXNDH 0x0007
|
||||
#define ENC28J60_REG_ERXSTL 0x0008
|
||||
#define ENC28J60_REG_ERXSTH 0x0009
|
||||
#define ENC28J60_REG_ERXNDL 0x000A
|
||||
#define ENC28J60_REG_ERXNDH 0x000B
|
||||
#define ENC28J60_REG_ERXRDPTL 0x000C
|
||||
#define ENC28J60_REG_ERXRDPTH 0x000D
|
||||
#define ENC28J60_REG_ERXWRPTL 0x000E
|
||||
#define ENC28J60_REG_ERXWRPTH 0x000F
|
||||
#define ENC28J60_REG_EDMASTL 0x0010
|
||||
#define ENC28J60_REG_EDMASTH 0x0011
|
||||
#define ENC28J60_REG_EDMANDL 0x0012
|
||||
#define ENC28J60_REG_EDMANDH 0x0013
|
||||
#define ENC28J60_REG_EDMADSTL 0x0014
|
||||
#define ENC28J60_REG_EDMADSTH 0x0015
|
||||
#define ENC28J60_REG_EDMACSL 0x0016
|
||||
#define ENC28J60_REG_EDMACSH 0x0017
|
||||
|
||||
/* Bank 1 Registers */
|
||||
#define ENC28J60_REG_EHT0 0x0100
|
||||
#define ENC28J60_REG_EHT1 0x0101
|
||||
#define ENC28J60_REG_EHT2 0x0102
|
||||
#define ENC28J60_REG_EHT3 0x0103
|
||||
#define ENC28J60_REG_EHT4 0x0104
|
||||
#define ENC28J60_REG_EHT5 0x0105
|
||||
#define ENC28J60_REG_EHT6 0x0106
|
||||
#define ENC28J60_REG_EHT7 0x0107
|
||||
#define ENC28J60_REG_EPMM0 0x0108
|
||||
#define ENC28J60_REG_EPMM1 0x0109
|
||||
#define ENC28J60_REG_EPMM2 0x010A
|
||||
#define ENC28J60_REG_EPMM3 0x010B
|
||||
#define ENC28J60_REG_EPMM4 0x010C
|
||||
#define ENC28J60_REG_EPMM5 0x010D
|
||||
#define ENC28J60_REG_EPMM6 0x010E
|
||||
#define ENC28J60_REG_EPMM7 0x010F
|
||||
#define ENC28J60_REG_EPMCSL 0x0110
|
||||
#define ENC28J60_REG_EPMCSH 0x0111
|
||||
#define ENC28J60_REG_EPMOL 0x0114
|
||||
#define ENC28J60_REG_EPMOH 0x0115
|
||||
#define ENC28J60_REG_EWOLIE 0x0116
|
||||
#define ENC28J60_REG_EWOLIR 0x0117
|
||||
#define ENC28J60_REG_ERXFCON 0x0118
|
||||
#define ENC28J60_REG_EPKTCNT 0x0119
|
||||
|
||||
/* Bank 2 Registers */
|
||||
#define ENC28J60_REG_MACON1 0x1200
|
||||
#define ENC28J60_REG_MACON3 0x1202
|
||||
#define ENC28J60_REG_MACON4 0x1203
|
||||
#define ENC28J60_REG_MABBIPG 0x1204
|
||||
#define ENC28J60_REG_MAIPGL 0x1206
|
||||
#define ENC28J60_REG_MAIPGH 0x1207
|
||||
#define ENC28J60_REG_MACLCON1 0x1208
|
||||
#define ENC28J60_REG_MACLCON2 0x1209
|
||||
#define ENC28J60_REG_MAMXFLL 0x120A
|
||||
#define ENC28J60_REG_MAMXFLH 0x120B
|
||||
#define ENC28J60_REG_MAPHSUP 0x120C
|
||||
#define ENC28J60_REG_MICON 0x2211
|
||||
#define ENC28J60_REG_MICMD 0x2212
|
||||
#define ENC28J60_REG_MIREGADR 0x2214
|
||||
#define ENC28J60_REG_MIWRL 0x2216
|
||||
#define ENC28J60_REG_MIWRH 0x2217
|
||||
#define ENC28J60_REG_MIRDL 0x2218
|
||||
#define ENC28J60_REG_MIRDH 0x2219
|
||||
|
||||
/* Bank 3 Registers */
|
||||
#define ENC28J60_REG_MAADR1 0x1300
|
||||
#define ENC28J60_REG_MAADR0 0x1301
|
||||
#define ENC28J60_REG_MAADR3 0x1302
|
||||
#define ENC28J60_REG_MAADR2 0x1303
|
||||
#define ENC28J60_REG_MAADR5 0x1304
|
||||
#define ENC28J60_REG_MAADR4 0x1305
|
||||
#define ENC28J60_REG_EBSTSD 0x0306
|
||||
#define ENC28J60_REG_EBSTCON 0x0307
|
||||
#define ENC28J60_REG_EBSTCSL 0x0308
|
||||
#define ENC28J60_REG_EBSTCSH 0x0309
|
||||
#define ENC28J60_REG_MISTAT 0x230A
|
||||
#define ENC28J60_REG_EREVID 0x0312
|
||||
#define ENC28J60_REG_ECOCON 0x0315
|
||||
#define ENC28J60_REG_EFLOCON 0x0317
|
||||
#define ENC28J60_REG_EPAUSL 0x0318
|
||||
#define ENC28J60_REG_EPAUSH 0x0319
|
||||
|
||||
/* PHY Registers */
|
||||
#define ENC28J60_PHY_PHCON1 0x00
|
||||
#define ENC28J60_PHY_PHSTAT1 0x01
|
||||
#define ENC28J60_PHY_PHID1 0x02
|
||||
#define ENC28J60_PHY_PHID2 0x03
|
||||
#define ENC28J60_PHY_PHCON2 0x10
|
||||
#define ENC28J60_PHY_PHSTAT2 0x11
|
||||
#define ENC28J60_PHY_PHIE 0x12
|
||||
#define ENC28J60_PHY_PHIR 0x13
|
||||
#define ENC28J60_PHY_PHLCON 0x14
|
||||
|
||||
/* SPI Instruction Opcodes */
|
||||
#define ENC28J60_SPI_RCR (0x0)
|
||||
#define ENC28J60_SPI_RBM (0x3A)
|
||||
#define ENC28J60_SPI_WCR (0x2 << 5)
|
||||
#define ENC28J60_SPI_WBM (0x7A)
|
||||
#define ENC28J60_SPI_BFS (0x4 << 5)
|
||||
#define ENC28J60_SPI_BFC (0x5 << 5)
|
||||
#define ENC28J60_SPI_SC (0xFF)
|
||||
|
||||
/* Significant bits */
|
||||
#define ENC28J60_BIT_MICMD_MIIRD (0x01)
|
||||
#define ENC28J60_BIT_MISTAT_BUSY (0x01)
|
||||
#define ENC28J60_BIT_ESTAT_CLKRDY (0x01)
|
||||
#define ENC28J60_BIT_MACON1_MARXEN (0x01)
|
||||
#define ENC28J60_BIT_MACON1_RXPAUS (0x04)
|
||||
#define ENC28J60_BIT_MACON1_TXPAUS (0x08)
|
||||
#define ENC28J60_BIT_MACON1_MARXEN (0x01)
|
||||
#define ENC28J60_BIT_MACON2_MARST (0x80)
|
||||
#define ENC28J60_BIT_MACON3_FULDPX (0x01)
|
||||
#define ENC28J60_BIT_ECON1_TXRST (0x80)
|
||||
#define ENC28J60_BIT_ECON1_TXRTS (0x08)
|
||||
#define ENC28J60_BIT_ECON1_RXEN (0x02)
|
||||
#define ENC28J60_BIT_ECON2_PKTDEC (0x40)
|
||||
#define ENC28J60_BIT_EIR_PKTIF (0x40)
|
||||
#define ENC28J60_BIT_EIE_TXIE (0x08)
|
||||
#define ENC28J60_BIT_EIE_PKTIE (0x40)
|
||||
#define ENC28J60_BIT_EIE_INTIE (0x80)
|
||||
#define ENC28J60_BIT_EIR_PKTIF (0x40)
|
||||
#define ENC28J60_BIT_EIR_DMAIF (0x20)
|
||||
#define ENC28J60_BIT_EIR_LINKIF (0x10)
|
||||
#define ENC28J60_BIT_EIR_TXIF (0x08)
|
||||
#define ENC28J60_BIT_EIR_WOLIF (0x04)
|
||||
#define ENC28J60_BIT_EIR_TXERIF (0x02)
|
||||
#define ENC28J60_BIT_EIR_RXERIF (0x01)
|
||||
#define ENC28J60_BIT_ESTAT_TXABRT (0x02)
|
||||
#define ENC28J60_BIT_ESTAT_LATECOL (0x10)
|
||||
#define ENC28J60_BIT_PHCON1_PDPXMD (0x0100)
|
||||
#define ENC28J60_BIT_PHCON2_HDLDIS (0x0001)
|
||||
|
||||
/* Driver Static Configuration */
|
||||
|
||||
/* Receive filters enabled:
|
||||
* - Unicast
|
||||
* - Broadcast
|
||||
* - CRC Check
|
||||
*/
|
||||
#define ENC28J60_RECEIVE_FILTERS 0xA1
|
||||
|
||||
/* MAC configuration:
|
||||
* - Automatic Padding
|
||||
* - Automatic CRC
|
||||
* - Frame Length Checking
|
||||
*/
|
||||
#define ENC28J60_MAC_CONFIG 0xF2
|
||||
#define ENC28J60_MAC_BBIPG_HD 0x12
|
||||
#define ENC28J60_MAC_BBIPG_FD 0x15
|
||||
#define ENC28J60_MAC_NBBIPGL 0x12
|
||||
#define ENC28J60_MAC_NBBIPGH 0x0C
|
||||
#define ENC28J60_PHY_LEDCONF 0x3422
|
||||
/* Status Vector size plus per packet control byte: 8 bytes */
|
||||
#define ENC28J60_SV_SIZE 8
|
||||
/* Per Packet Control Byte configured to follow MACON3 configuration */
|
||||
#define ENC28J60_PPCTL_BYTE 0x0
|
||||
|
||||
/* Start of RX buffer, (must be zero, Rev. B4 Errata point 5) */
|
||||
#define ENC28J60_RXSTART 0x0000
|
||||
/* End of RX buffer, room for 2 packets */
|
||||
#define ENC28J60_RXEND 0x0BFF
|
||||
|
||||
/* Start of TX buffer, room for 1 packet */
|
||||
#define ENC28J60_TXSTART 0x0C00
|
||||
/* End of TX buffer */
|
||||
#define ENC28J60_TXEND 0x11FF
|
||||
|
||||
/* Status vectors array size */
|
||||
#define TSV_SIZE 7
|
||||
#define RSV_SIZE 4
|
||||
|
||||
/* Fiber Configuration */
|
||||
#define ENC28J60_FIBER_STACK_SIZE 256
|
||||
#define ENC28J60_FIBER_PRIORITY 100
|
||||
|
||||
/* Microchip's OUI*/
|
||||
#define MICROCHIP_OUI_B0 0x00
|
||||
#define MICROCHIP_OUI_B1 0x04
|
||||
#define MICROCHIP_OUI_B2 0xA3
|
||||
|
||||
struct eth_enc28j60_config {
|
||||
const char *gpio_port;
|
||||
uint8_t gpio_pin;
|
||||
const char *spi_port;
|
||||
uint32_t spi_freq;
|
||||
uint8_t spi_slave;
|
||||
};
|
||||
|
||||
struct eth_enc28j60_runtime {
|
||||
char __stack fiber_stack[ENC28J60_FIBER_STACK_SIZE];
|
||||
struct device *gpio;
|
||||
struct device *spi;
|
||||
struct gpio_callback gpio_cb;
|
||||
char full_duplex;
|
||||
uint8_t tx_tsv[TSV_SIZE];
|
||||
uint8_t rx_rsv[RSV_SIZE];
|
||||
struct nano_sem tx_sem;
|
||||
struct nano_sem int_sem;
|
||||
void (*receive_callback)(uint8_t *buffer, uint16_t len);
|
||||
};
|
||||
|
||||
#endif /*_ENC28J60_*/
|
85
include/eth.h
Normal file
85
include/eth.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* @brief Ethernet public API header file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __INCLUDE_ETH_H__
|
||||
#define __INCLUDE_ETH_H__
|
||||
|
||||
#include <device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Ethernet driver API
|
||||
*
|
||||
* This structure holds all API function pointers.
|
||||
*/
|
||||
struct eth_driver_api {
|
||||
int (*send)(struct device *dev, uint8_t *buffer, uint16_t len);
|
||||
void (*register_callback)(struct device *dev,
|
||||
void (*cb)(uint8_t *buffer, uint16_t len));
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Sends a frame to ethernet hardware
|
||||
*
|
||||
* This routine writes a buffer to be sent through the ethernet hardware.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
* @param buffer Byte array to be sent through the device
|
||||
* @param len Length of the array
|
||||
*
|
||||
* @return Error code
|
||||
*/
|
||||
static inline int eth_send(struct device *dev, uint8_t *buffer, uint16_t len)
|
||||
{
|
||||
struct eth_driver_api *api;
|
||||
|
||||
api = (struct eth_driver_api *)dev->driver_api;
|
||||
return api->send(dev, buffer, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register callback for received frame
|
||||
*
|
||||
* This routine writes a buffer to be sent through the ethernet hardware.
|
||||
*
|
||||
* @param dev Pointer to the device structure for the driver instance.
|
||||
* @param cb Callback function to be registered in the driver.
|
||||
*
|
||||
* @return Error code
|
||||
*/
|
||||
static inline void eth_register_callback(struct device *dev,
|
||||
void (*cb)(uint8_t *buffer, uint16_t len))
|
||||
{
|
||||
struct eth_driver_api *api;
|
||||
|
||||
api = (struct eth_driver_api *)dev->driver_api;
|
||||
api->register_callback(dev, cb);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__INCLUDE_ETH_H__*/
|
Loading…
Add table
Add a link
Reference in a new issue