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:
parent
659f0f2d20
commit
2a14d289e5
3 changed files with 188 additions and 51 deletions
|
@ -10,7 +10,6 @@ menuconfig ETH_ENC28J60
|
|||
bool "ENC28J60C Ethernet Controller"
|
||||
depends on NET_L2_ETHERNET
|
||||
depends on SPI
|
||||
select SPI_LEGACY_API
|
||||
default n
|
||||
help
|
||||
ENC28J60C Stand-Alone Ethernet Controller
|
||||
|
@ -84,11 +83,32 @@ config ETH_ENC28J60_0_SLAVE
|
|||
help
|
||||
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
|
||||
int "ENC28J60C SPI bus speed in Hz"
|
||||
default 128
|
||||
default 128000
|
||||
help
|
||||
This is the maximum supported SPI bus frequency.
|
||||
This is the SPI bus frequency for accessing the device.
|
||||
|
||||
config ETH_ENC28J60_0_MAC3
|
||||
hex "MAC Address Byte 3"
|
||||
|
|
|
@ -29,25 +29,55 @@ static int eth_enc28j60_soft_reset(struct device *dev)
|
|||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
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)
|
||||
{
|
||||
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 rx_buf[2];
|
||||
int ret;
|
||||
|
||||
k_sem_take(&context->spi_sem, K_FOREVER);
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_RCR | ENC28J60_REG_ECON1;
|
||||
tx_buf[1] = 0x0;
|
||||
|
||||
if (!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);
|
||||
tx_bufs[0].buf = tx_buf;
|
||||
tx_bufs[0].len = 2;
|
||||
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 {
|
||||
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;
|
||||
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);
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_WCR | (reg_addr & 0xFF);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -75,20 +114,44 @@ static void eth_enc28j60_read_reg(struct device *dev, u16_t reg_addr,
|
|||
u8_t *value)
|
||||
{
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
u8_t tx_size = 2;
|
||||
u8_t tx_buf[3];
|
||||
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)
|
||||
};
|
||||
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);
|
||||
|
||||
if (reg_addr & 0xF000) {
|
||||
tx_size = 3;
|
||||
rx_size = 3;
|
||||
}
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_RCR | (reg_addr & 0xFF);
|
||||
tx_buf[1] = 0x0;
|
||||
|
||||
if (!spi_transceive(context->spi, tx_buf, tx_size, tx_buf, tx_size)) {
|
||||
*value = tx_buf[tx_size - 1];
|
||||
rx_bufs[0].len = rx_size;
|
||||
|
||||
ret = spi_transceive(context->spi, &context->spi_cfg, &tx, &rx);
|
||||
if (!ret) {
|
||||
*value = rx_buf[rx_size - 1];
|
||||
} else {
|
||||
SYS_LOG_DBG("Failure while reading register %d", reg_addr);
|
||||
*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;
|
||||
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);
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_BFS | (reg_addr & 0xFF);
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
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);
|
||||
|
||||
tx_buf[0] = ENC28J60_SPI_BFC | (reg_addr & 0xFF);
|
||||
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);
|
||||
}
|
||||
|
@ -134,6 +217,11 @@ static void eth_enc28j60_write_mem(struct device *dev, u8_t *data_buffer,
|
|||
u16_t buf_len)
|
||||
{
|
||||
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;
|
||||
u16_t num_segments;
|
||||
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) {
|
||||
context->mem_buf[0] = ENC28J60_SPI_WBM;
|
||||
memcpy(context->mem_buf + 1, index_buf, MAX_BUFFER_LENGTH);
|
||||
spi_write(context->spi,
|
||||
context->mem_buf, MAX_BUFFER_LENGTH + 1);
|
||||
tx_bufs[0].buf = context->mem_buf;
|
||||
tx_bufs[0].len = MAX_BUFFER_LENGTH + 1;
|
||||
|
||||
spi_write(context->spi, &context->spi_cfg, &tx);
|
||||
}
|
||||
|
||||
if (num_remaining > 0) {
|
||||
context->mem_buf[0] = ENC28J60_SPI_WBM;
|
||||
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);
|
||||
|
@ -165,8 +258,14 @@ static void eth_enc28j60_read_mem(struct device *dev, u8_t *data_buffer,
|
|||
u16_t buf_len)
|
||||
{
|
||||
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_remaining;
|
||||
int ret;
|
||||
|
||||
num_segments = buf_len / MAX_BUFFER_LENGTH;
|
||||
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) {
|
||||
context->mem_buf[0] = ENC28J60_SPI_RBM;
|
||||
|
||||
if (!spi_transceive(context->spi,
|
||||
context->mem_buf, MAX_BUFFER_LENGTH + 1,
|
||||
context->mem_buf, MAX_BUFFER_LENGTH + 1)) {
|
||||
tx_bufs[0].buf = context->mem_buf;
|
||||
tx_bufs[0].len = MAX_BUFFER_LENGTH + 1;
|
||||
|
||||
ret = spi_transceive(context->spi, &context->spi_cfg, &tx, &tx);
|
||||
if (!ret) {
|
||||
if (data_buffer) {
|
||||
memcpy(data_buffer, context->mem_buf + 1,
|
||||
MAX_BUFFER_LENGTH);
|
||||
|
@ -192,9 +293,11 @@ static void eth_enc28j60_read_mem(struct device *dev, u8_t *data_buffer,
|
|||
if (num_remaining > 0) {
|
||||
context->mem_buf[0] = ENC28J60_SPI_RBM;
|
||||
|
||||
if (!spi_transceive(context->spi,
|
||||
context->mem_buf, num_remaining + 1,
|
||||
context->mem_buf, num_remaining + 1)) {
|
||||
tx_bufs[0].buf = context->mem_buf;
|
||||
tx_bufs[0].len = num_remaining + 1;
|
||||
|
||||
ret = spi_transceive(context->spi, &context->spi_cfg, &tx, &tx);
|
||||
if (!ret) {
|
||||
if (data_buffer) {
|
||||
memcpy(data_buffer, context->mem_buf + 1,
|
||||
num_remaining);
|
||||
|
@ -348,23 +451,40 @@ static int eth_enc28j60_init(struct device *dev)
|
|||
{
|
||||
const struct eth_enc28j60_config *config = dev->config->config_info;
|
||||
struct eth_enc28j60_runtime *context = dev->driver_data;
|
||||
struct spi_config spi_cfg;
|
||||
|
||||
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);
|
||||
if (!context->gpio) {
|
||||
SYS_LOG_ERR("GPIO port %s not found", config->gpio_port);
|
||||
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,
|
||||
(GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE
|
||||
| GPIO_INT_ACTIVE_LOW | GPIO_INT_DEBOUNCE))) {
|
||||
|
@ -384,27 +504,12 @@ static int eth_enc28j60_init(struct device *dev)
|
|||
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)) {
|
||||
SYS_LOG_ERR("Soft-reset failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Errata B7/2 */
|
||||
/* Errata B7/1 */
|
||||
k_busy_wait(D10D24S);
|
||||
|
||||
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.
|
||||
* 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("");
|
||||
|
||||
|
@ -658,7 +768,6 @@ static void enc28j60_thread_main(void *arg1, void *unused1, void *unused2)
|
|||
while (1) {
|
||||
k_sem_take(&context->int_sem, K_FOREVER);
|
||||
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 */
|
||||
|
@ -718,6 +827,10 @@ static const struct eth_enc28j60_config eth_enc28j60_0_config = {
|
|||
.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,
|
||||
#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,
|
||||
.timeout = CONFIG_ETH_EN28J60_TIMEOUT,
|
||||
};
|
||||
|
|
|
@ -217,6 +217,8 @@ struct eth_enc28j60_config {
|
|||
const char *gpio_port;
|
||||
u8_t gpio_pin;
|
||||
const char *spi_port;
|
||||
u8_t spi_cs_pin;
|
||||
const char *spi_cs_port;
|
||||
u32_t spi_freq;
|
||||
u8_t spi_slave;
|
||||
u8_t full_duplex;
|
||||
|
@ -230,6 +232,8 @@ struct eth_enc28j60_runtime {
|
|||
struct k_thread thread;
|
||||
struct device *gpio;
|
||||
struct device *spi;
|
||||
struct spi_cs_control spi_cs;
|
||||
struct spi_config spi_cfg;
|
||||
struct gpio_callback gpio_cb;
|
||||
u8_t mem_buf[MAX_BUFFER_LENGTH + 1];
|
||||
u8_t tx_tsv[TSV_SIZE];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue