drivers/ethernet: Switch enc28j60 to new SPI API

Let's use the new SPI API and ditch the old one.

Signed-off-by: Matthias Boesl <matthias.boesl@gmail.com>
Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
This commit is contained in:
Matthias Boesl 2017-09-05 19:08:06 +02:00 committed by Carles Cufí
commit 2a14d289e5
3 changed files with 188 additions and 51 deletions

View file

@ -10,7 +10,6 @@ menuconfig ETH_ENC28J60
bool "ENC28J60C Ethernet Controller" bool "ENC28J60C Ethernet Controller"
depends on NET_L2_ETHERNET depends on NET_L2_ETHERNET
depends on SPI depends on SPI
select SPI_LEGACY_API
default n default n
help help
ENC28J60C Stand-Alone Ethernet Controller ENC28J60C Stand-Alone Ethernet Controller
@ -84,11 +83,32 @@ config ETH_ENC28J60_0_SLAVE
help help
ENC28J60C chip select pin. ENC28J60C chip select pin.
config ETH_ENC28J60_0_GPIO_SPI_CS
bool "Manage SPI CS throug a GPIO pin"
default n
help
This option is useful if one needs to manage SPI CS through a GPIO
pin to by-pass the SPI controller's CS logic.
config ETH_ENC28J60_0_SPI_CS_PORT_NAME
string "SPI cs port name"
default ""
depends on ETH_ENC28J60_0_GPIO_SPI_CS
help
Master SPI port name through which ENC28J60C chip is accessed.
config ETH_ENC28J60_0_SPI_CS_PIN
int "SPI CS pin"
default 0
depends on ETH_ENC28J60_0_GPIO_SPI_CS
help
CS pin used for the SPI device
config ETH_ENC28J60_0_SPI_BUS_FREQ config ETH_ENC28J60_0_SPI_BUS_FREQ
int "ENC28J60C SPI bus speed in Hz" int "ENC28J60C SPI bus speed in Hz"
default 128 default 128000
help help
This is the maximum supported SPI bus frequency. This is the SPI bus frequency for accessing the device.
config ETH_ENC28J60_0_MAC3 config ETH_ENC28J60_0_MAC3
hex "MAC Address Byte 3" hex "MAC Address Byte 3"

View file

@ -29,25 +29,55 @@ static int eth_enc28j60_soft_reset(struct device *dev)
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
u8_t tx_buf[2] = {ENC28J60_SPI_SC, 0xFF}; u8_t tx_buf[2] = {ENC28J60_SPI_SC, 0xFF};
const struct spi_buf tx_bufs[] = {
{
.buf = tx_buf,
.len = 1,
},
};
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
return spi_write(context->spi, tx_buf, 2); return spi_write(context->spi, &context->spi_cfg, &tx);
} }
static void eth_enc28j60_set_bank(struct device *dev, u16_t reg_addr) static void eth_enc28j60_set_bank(struct device *dev, u16_t reg_addr)
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
struct spi_buf tx_bufs[1];
struct spi_buf rx_bufs[1];
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
const struct spi_buf_set rx = {
.buffers = rx_bufs,
.count = ARRAY_SIZE(rx_bufs)
};
u8_t tx_buf[2]; u8_t tx_buf[2];
u8_t rx_buf[2];
int ret;
k_sem_take(&context->spi_sem, K_FOREVER); k_sem_take(&context->spi_sem, K_FOREVER);
tx_buf[0] = ENC28J60_SPI_RCR | ENC28J60_REG_ECON1; tx_buf[0] = ENC28J60_SPI_RCR | ENC28J60_REG_ECON1;
tx_buf[1] = 0x0; tx_buf[1] = 0x0;
if (!spi_transceive(context->spi, tx_buf, 2, tx_buf, 2)) { tx_bufs[0].buf = tx_buf;
tx_buf[0] = ENC28J60_SPI_WCR | ENC28J60_REG_ECON1; tx_bufs[0].len = 2;
tx_buf[1] = (tx_buf[1] & 0xFC) | ((reg_addr >> 8) & 0x0F); rx_bufs[0].buf = rx_buf;
rx_bufs[0].len = 2;
spi_write(context->spi, tx_buf, 2); ret = spi_transceive(context->spi, &context->spi_cfg, &tx, &rx);
if (!ret) {
tx_buf[0] = ENC28J60_SPI_WCR | ENC28J60_REG_ECON1;
tx_buf[1] = (rx_buf[1] & 0xFC) | ((reg_addr >> 8) & 0x0F);
tx_bufs[0].buf = tx_buf;
tx_bufs[0].len = 2;
spi_write(context->spi, &context->spi_cfg, &tx);
} else { } else {
SYS_LOG_DBG("Failure while setting bank to %d", reg_addr); SYS_LOG_DBG("Failure while setting bank to %d", reg_addr);
} }
@ -60,14 +90,23 @@ static void eth_enc28j60_write_reg(struct device *dev, u16_t reg_addr,
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
u8_t tx_buf[2]; u8_t tx_buf[2];
const struct spi_buf tx_bufs[] = {
{
.buf = tx_buf,
.len = 2
}
};
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
k_sem_take(&context->spi_sem, K_FOREVER); k_sem_take(&context->spi_sem, K_FOREVER);
tx_buf[0] = ENC28J60_SPI_WCR | (reg_addr & 0xFF); tx_buf[0] = ENC28J60_SPI_WCR | (reg_addr & 0xFF);
tx_buf[1] = value; tx_buf[1] = value;
spi_write(context->spi, tx_buf, 2); spi_write(context->spi, &context->spi_cfg, &tx);
k_sem_give(&context->spi_sem); k_sem_give(&context->spi_sem);
} }
@ -75,20 +114,44 @@ static void eth_enc28j60_read_reg(struct device *dev, u16_t reg_addr,
u8_t *value) u8_t *value)
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
u8_t tx_size = 2; u8_t tx_buf[2];
u8_t tx_buf[3]; const struct spi_buf tx_bufs[1] = {
{
.buf = tx_buf,
.len = 2
}
};
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
u8_t rx_buf[3];
struct spi_buf rx_bufs[1] = {
{
.buf = rx_buf,
}
};
const struct spi_buf_set rx = {
.buffers = rx_bufs,
.count = ARRAY_SIZE(rx_bufs)
};
u8_t rx_size = 2;
int ret;
k_sem_take(&context->spi_sem, K_FOREVER); k_sem_take(&context->spi_sem, K_FOREVER);
if (reg_addr & 0xF000) { if (reg_addr & 0xF000) {
tx_size = 3; rx_size = 3;
} }
tx_buf[0] = ENC28J60_SPI_RCR | (reg_addr & 0xFF); tx_buf[0] = ENC28J60_SPI_RCR | (reg_addr & 0xFF);
tx_buf[1] = 0x0; tx_buf[1] = 0x0;
if (!spi_transceive(context->spi, tx_buf, tx_size, tx_buf, tx_size)) { rx_bufs[0].len = rx_size;
*value = tx_buf[tx_size - 1];
ret = spi_transceive(context->spi, &context->spi_cfg, &tx, &rx);
if (!ret) {
*value = rx_buf[rx_size - 1];
} else { } else {
SYS_LOG_DBG("Failure while reading register %d", reg_addr); SYS_LOG_DBG("Failure while reading register %d", reg_addr);
*value = 0; *value = 0;
@ -102,13 +165,23 @@ static void eth_enc28j60_set_eth_reg(struct device *dev, u16_t reg_addr,
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
u8_t tx_buf[2]; u8_t tx_buf[2];
const struct spi_buf tx_bufs[1] = {
{
.buf = tx_buf,
.len = 2
}
};
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
k_sem_take(&context->spi_sem, K_FOREVER); k_sem_take(&context->spi_sem, K_FOREVER);
tx_buf[0] = ENC28J60_SPI_BFS | (reg_addr & 0xFF); tx_buf[0] = ENC28J60_SPI_BFS | (reg_addr & 0xFF);
tx_buf[1] = value; tx_buf[1] = value;
spi_write(context->spi, tx_buf, 2); spi_write(context->spi, &context->spi_cfg, &tx);
k_sem_give(&context->spi_sem); k_sem_give(&context->spi_sem);
} }
@ -119,13 +192,23 @@ static void eth_enc28j60_clear_eth_reg(struct device *dev, u16_t reg_addr,
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
u8_t tx_buf[2]; u8_t tx_buf[2];
const struct spi_buf tx_bufs[1] = {
{
.buf = tx_buf,
.len = ARRAY_SIZE(tx_bufs)
}
};
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
k_sem_take(&context->spi_sem, K_FOREVER); k_sem_take(&context->spi_sem, K_FOREVER);
tx_buf[0] = ENC28J60_SPI_BFC | (reg_addr & 0xFF); tx_buf[0] = ENC28J60_SPI_BFC | (reg_addr & 0xFF);
tx_buf[1] = value; tx_buf[1] = value;
spi_write(context->spi, tx_buf, 2); spi_write(context->spi, &context->spi_cfg, &tx);
k_sem_give(&context->spi_sem); k_sem_give(&context->spi_sem);
} }
@ -134,6 +217,11 @@ static void eth_enc28j60_write_mem(struct device *dev, u8_t *data_buffer,
u16_t buf_len) u16_t buf_len)
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
struct spi_buf tx_bufs[1];
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
u8_t *index_buf; u8_t *index_buf;
u16_t num_segments; u16_t num_segments;
u16_t num_remaining; u16_t num_remaining;
@ -148,14 +236,19 @@ static void eth_enc28j60_write_mem(struct device *dev, u8_t *data_buffer,
++i, index_buf += MAX_BUFFER_LENGTH) { ++i, index_buf += MAX_BUFFER_LENGTH) {
context->mem_buf[0] = ENC28J60_SPI_WBM; context->mem_buf[0] = ENC28J60_SPI_WBM;
memcpy(context->mem_buf + 1, index_buf, MAX_BUFFER_LENGTH); memcpy(context->mem_buf + 1, index_buf, MAX_BUFFER_LENGTH);
spi_write(context->spi, tx_bufs[0].buf = context->mem_buf;
context->mem_buf, MAX_BUFFER_LENGTH + 1); tx_bufs[0].len = MAX_BUFFER_LENGTH + 1;
spi_write(context->spi, &context->spi_cfg, &tx);
} }
if (num_remaining > 0) { if (num_remaining > 0) {
context->mem_buf[0] = ENC28J60_SPI_WBM; context->mem_buf[0] = ENC28J60_SPI_WBM;
memcpy(context->mem_buf + 1, index_buf, num_remaining); memcpy(context->mem_buf + 1, index_buf, num_remaining);
spi_write(context->spi, context->mem_buf, num_remaining + 1); tx_bufs[0].buf = context->mem_buf;
tx_bufs[0].len = num_remaining + 1;
spi_write(context->spi, &context->spi_cfg, &tx);
} }
k_sem_give(&context->spi_sem); k_sem_give(&context->spi_sem);
@ -165,8 +258,14 @@ static void eth_enc28j60_read_mem(struct device *dev, u8_t *data_buffer,
u16_t buf_len) u16_t buf_len)
{ {
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
struct spi_buf tx_bufs[1];
const struct spi_buf_set tx = {
.buffers = tx_bufs,
.count = ARRAY_SIZE(tx_bufs)
};
u16_t num_segments; u16_t num_segments;
u16_t num_remaining; u16_t num_remaining;
int ret;
num_segments = buf_len / MAX_BUFFER_LENGTH; num_segments = buf_len / MAX_BUFFER_LENGTH;
num_remaining = buf_len - MAX_BUFFER_LENGTH * num_segments; num_remaining = buf_len - MAX_BUFFER_LENGTH * num_segments;
@ -177,9 +276,11 @@ static void eth_enc28j60_read_mem(struct device *dev, u8_t *data_buffer,
++i, data_buffer += MAX_BUFFER_LENGTH) { ++i, data_buffer += MAX_BUFFER_LENGTH) {
context->mem_buf[0] = ENC28J60_SPI_RBM; context->mem_buf[0] = ENC28J60_SPI_RBM;
if (!spi_transceive(context->spi, tx_bufs[0].buf = context->mem_buf;
context->mem_buf, MAX_BUFFER_LENGTH + 1, tx_bufs[0].len = MAX_BUFFER_LENGTH + 1;
context->mem_buf, MAX_BUFFER_LENGTH + 1)) {
ret = spi_transceive(context->spi, &context->spi_cfg, &tx, &tx);
if (!ret) {
if (data_buffer) { if (data_buffer) {
memcpy(data_buffer, context->mem_buf + 1, memcpy(data_buffer, context->mem_buf + 1,
MAX_BUFFER_LENGTH); MAX_BUFFER_LENGTH);
@ -192,9 +293,11 @@ static void eth_enc28j60_read_mem(struct device *dev, u8_t *data_buffer,
if (num_remaining > 0) { if (num_remaining > 0) {
context->mem_buf[0] = ENC28J60_SPI_RBM; context->mem_buf[0] = ENC28J60_SPI_RBM;
if (!spi_transceive(context->spi, tx_bufs[0].buf = context->mem_buf;
context->mem_buf, num_remaining + 1, tx_bufs[0].len = num_remaining + 1;
context->mem_buf, num_remaining + 1)) {
ret = spi_transceive(context->spi, &context->spi_cfg, &tx, &tx);
if (!ret) {
if (data_buffer) { if (data_buffer) {
memcpy(data_buffer, context->mem_buf + 1, memcpy(data_buffer, context->mem_buf + 1,
num_remaining); num_remaining);
@ -348,23 +451,40 @@ static int eth_enc28j60_init(struct device *dev)
{ {
const struct eth_enc28j60_config *config = dev->config->config_info; const struct eth_enc28j60_config *config = dev->config->config_info;
struct eth_enc28j60_runtime *context = dev->driver_data; struct eth_enc28j60_runtime *context = dev->driver_data;
struct spi_config spi_cfg;
k_sem_init(&context->spi_sem, 1, UINT_MAX); k_sem_init(&context->spi_sem, 1, UINT_MAX);
/* SPI config */
context->spi_cfg.operation = SPI_WORD_SET(8);
context->spi_cfg.frequency = config->spi_freq;
context->spi_cfg.slave = config->spi_slave;
context->spi = device_get_binding((char *)config->spi_port);
if (!context->spi) {
SYS_LOG_ERR("SPI master port %s not found", config->spi_port);
return -EINVAL;
}
#ifdef CONFIG_ETH_ENC28J60_0_GPIO_SPI_CS
context->spi_cs.gpio_dev =
device_get_binding((char *)config->spi_cs_port);
if (!context->spi_cs.gpio_dev) {
SYS_LOG_ERR("SPI CS port %s not found", config->spi_cs_port);
return -EINVAL;
}
context->spi_cs.gpio_pin = config->spi_cs_pin;
context->spi_cfg.cs = &context->spi_cs;
#endif /* CONFIG_ETH_ENC28J60_0_GPIO_SPI_CS */
/* Initialize GPIO */
context->gpio = device_get_binding((char *)config->gpio_port); context->gpio = device_get_binding((char *)config->gpio_port);
if (!context->gpio) { if (!context->gpio) {
SYS_LOG_ERR("GPIO port %s not found", config->gpio_port); SYS_LOG_ERR("GPIO port %s not found", config->gpio_port);
return -EINVAL; return -EINVAL;
} }
context->spi = device_get_binding((char *)config->spi_port);
if (!context->spi) {
SYS_LOG_ERR("SPI master port %s not found", config->spi_port);
return -EINVAL;
}
/* Initialize GPIO */
if (gpio_pin_configure(context->gpio, config->gpio_pin, if (gpio_pin_configure(context->gpio, config->gpio_pin,
(GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE (GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE
| GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE))) { | GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE))) {
@ -384,27 +504,12 @@ static int eth_enc28j60_init(struct device *dev)
return -EINVAL; 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) {
SYS_LOG_ERR("Failed to configure SPI");
return -EIO;
}
if (spi_slave_select(context->spi, config->spi_slave) < 0) {
return -EIO;
}
if (eth_enc28j60_soft_reset(dev)) { if (eth_enc28j60_soft_reset(dev)) {
SYS_LOG_ERR("Soft-reset failed"); SYS_LOG_ERR("Soft-reset failed");
return -EIO; return -EIO;
} }
/* Errata B7/2 */ /* Errata B7/1 */
k_busy_wait(D10D24S); k_busy_wait(D10D24S);
eth_enc28j60_init_buffers(dev); eth_enc28j60_init_buffers(dev);
@ -528,6 +633,11 @@ static int eth_enc28j60_rx(struct device *dev)
* does not reliably/accurately report the status of pending packet. * does not reliably/accurately report the status of pending packet.
* Use EPKTCNT register instead. * Use EPKTCNT register instead.
*/ */
eth_enc28j60_set_bank(dev, ENC28J60_REG_EPKTCNT);
eth_enc28j60_read_reg(dev, ENC28J60_REG_EPKTCNT, &counter);
if (!counter) {
return 0;
}
SYS_LOG_DBG(""); SYS_LOG_DBG("");
@ -658,7 +768,6 @@ static void enc28j60_thread_main(void *arg1, void *unused1, void *unused2)
while (1) { while (1) {
k_sem_take(&context->int_sem, K_FOREVER); k_sem_take(&context->int_sem, K_FOREVER);
eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &int_stat); eth_enc28j60_read_reg(dev, ENC28J60_REG_EIR, &int_stat);
if (int_stat & ENC28J60_BIT_EIR_PKTIF) { if (int_stat & ENC28J60_BIT_EIR_PKTIF) {
eth_enc28j60_rx(dev); eth_enc28j60_rx(dev);
/* Clear rx interruption flag */ /* Clear rx interruption flag */
@ -718,6 +827,10 @@ static const struct eth_enc28j60_config eth_enc28j60_0_config = {
.spi_port = CONFIG_ETH_ENC28J60_0_SPI_PORT_NAME, .spi_port = CONFIG_ETH_ENC28J60_0_SPI_PORT_NAME,
.spi_freq = CONFIG_ETH_ENC28J60_0_SPI_BUS_FREQ, .spi_freq = CONFIG_ETH_ENC28J60_0_SPI_BUS_FREQ,
.spi_slave = CONFIG_ETH_ENC28J60_0_SLAVE, .spi_slave = CONFIG_ETH_ENC28J60_0_SLAVE,
#ifdef CONFIG_ETH_ENC28J60_0_GPIO_SPI_CS
.spi_cs_port = CONFIG_ETH_ENC28J60_0_SPI_CS_PORT_NAME,
.spi_cs_pin = CONFIG_ETH_ENC28J60_0_SPI_CS_PIN,
#endif /* CONFIG_ETH_ENC28J60_0_GPIO_SPI_CS */
.full_duplex = CONFIG_ETH_EN28J60_0_FULL_DUPLEX, .full_duplex = CONFIG_ETH_EN28J60_0_FULL_DUPLEX,
.timeout = CONFIG_ETH_EN28J60_TIMEOUT, .timeout = CONFIG_ETH_EN28J60_TIMEOUT,
}; };

View file

@ -217,6 +217,8 @@ struct eth_enc28j60_config {
const char *gpio_port; const char *gpio_port;
u8_t gpio_pin; u8_t gpio_pin;
const char *spi_port; const char *spi_port;
u8_t spi_cs_pin;
const char *spi_cs_port;
u32_t spi_freq; u32_t spi_freq;
u8_t spi_slave; u8_t spi_slave;
u8_t full_duplex; u8_t full_duplex;
@ -230,6 +232,8 @@ struct eth_enc28j60_runtime {
struct k_thread thread; struct k_thread thread;
struct device *gpio; struct device *gpio;
struct device *spi; struct device *spi;
struct spi_cs_control spi_cs;
struct spi_config spi_cfg;
struct gpio_callback gpio_cb; struct gpio_callback gpio_cb;
u8_t mem_buf[MAX_BUFFER_LENGTH + 1]; u8_t mem_buf[MAX_BUFFER_LENGTH + 1];
u8_t tx_tsv[TSV_SIZE]; u8_t tx_tsv[TSV_SIZE];