drivers: ethernet: adin2111: add adin1110 support
Add support for ADIN1110 10BASE-T1L Ethernet MAC-PHY. The ADIN1110 is an ultra low power, single port, 10BASE-T1L transceiver design for industrial Ethernet applications and is com- pliant with the IEEE® 802.3cg-2019™ Ethernet standard for long reach, 10 Mbps single pair Ethernet (SPE). Featuring an integrated media access control (MAC) interface, the ADIN1110 enables direct connectivity with a variety of host controllers via a 4-wire serial peripheral interface (SPI). This SPI enables the use of lower power processors without an integrated MAC, which provides for the lowest overall system level power consumption. The SPI can be configured to use the Open Alliance SPI protocol or a generic SPI protocol. Documentation: https://www.analog.com/en/products/adin1110.html Signed-off-by: Antoniu Miclaus <antoniu.miclaus@analog.com>
This commit is contained in:
parent
636fd6ad07
commit
a6e3829252
5 changed files with 77 additions and 17 deletions
|
@ -4,7 +4,7 @@
|
||||||
menuconfig ETH_ADIN2111
|
menuconfig ETH_ADIN2111
|
||||||
bool "ADIN2111 2-port 10BASE-T1L Controller"
|
bool "ADIN2111 2-port 10BASE-T1L Controller"
|
||||||
default y
|
default y
|
||||||
depends on DT_HAS_ADI_ADIN2111_ENABLED
|
depends on DT_HAS_ADI_ADIN2111_ENABLED || DT_HAS_ADI_ADIN1110_ENABLED
|
||||||
select SPI
|
select SPI
|
||||||
select MDIO
|
select MDIO
|
||||||
help
|
help
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_REGISTER(eth_adin2111, CONFIG_ETHERNET_LOG_LEVEL);
|
LOG_MODULE_REGISTER(eth_adin2111, CONFIG_ETHERNET_LOG_LEVEL);
|
||||||
|
|
||||||
#define DT_DRV_COMPAT adi_adin2111
|
|
||||||
|
|
||||||
#include <zephyr/net/net_pkt.h>
|
#include <zephyr/net/net_pkt.h>
|
||||||
#include <zephyr/net/ethernet.h>
|
#include <zephyr/net/ethernet.h>
|
||||||
#include <zephyr/net/phy.h>
|
#include <zephyr/net/phy.h>
|
||||||
|
@ -269,6 +267,9 @@ static inline void adin2111_port_on_phyint(const struct device *dev)
|
||||||
static void adin2111_offload_thread(const struct device *dev)
|
static void adin2111_offload_thread(const struct device *dev)
|
||||||
{
|
{
|
||||||
struct adin2111_data *ctx = dev->data;
|
struct adin2111_data *ctx = dev->data;
|
||||||
|
const struct adin2111_port_config *pcfg = dev->config;
|
||||||
|
const struct adin2111_config *adin_cfg = pcfg->adin->config;
|
||||||
|
bool is_adin2111 = (adin_cfg->id == ADIN2111_MAC);
|
||||||
uint32_t status0;
|
uint32_t status0;
|
||||||
uint32_t status1;
|
uint32_t status1;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -312,7 +313,7 @@ static void adin2111_offload_thread(const struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle port 2 phy interrupts */
|
/* handle port 2 phy interrupts */
|
||||||
if (status1 & ADIN2111_STATUS1_PHYINT) {
|
if ((status1 & ADIN2111_STATUS1_PHYINT) && is_adin2111) {
|
||||||
adin2111_port_on_phyint(ctx->port[1]);
|
adin2111_port_on_phyint(ctx->port[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +333,7 @@ static void adin2111_offload_thread(const struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle port 2 rx */
|
/* handle port 2 rx */
|
||||||
if (status1 & ADIN2111_STATUS1_P2_RX_RDY) {
|
if ((status1 & ADIN2111_STATUS1_P2_RX_RDY) && is_adin2111) {
|
||||||
do {
|
do {
|
||||||
ret = adin2111_read_fifo(dev, 1U);
|
ret = adin2111_read_fifo(dev, 1U);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -570,9 +571,11 @@ static int adin2111_write_filter_address(const struct device *dev,
|
||||||
|
|
||||||
static int adin2111_filter_multicast(const struct device *dev)
|
static int adin2111_filter_multicast(const struct device *dev)
|
||||||
{
|
{
|
||||||
|
const struct adin2111_config *cfg = dev->config;
|
||||||
|
bool is_adin2111 = (cfg->id == ADIN2111_MAC);
|
||||||
uint8_t mm[6] = {BIT(0), 0U, 0U, 0U, 0U, 0U};
|
uint8_t mm[6] = {BIT(0), 0U, 0U, 0U, 0U, 0U};
|
||||||
uint32_t rules = ADIN2111_ADDR_APPLY2PORT1 |
|
uint32_t rules = ADIN2111_ADDR_APPLY2PORT1 |
|
||||||
ADIN2111_ADDR_APPLY2PORT2 |
|
(is_adin2111 ? ADIN2111_ADDR_APPLY2PORT2 : 0) |
|
||||||
ADIN2111_ADDR_TO_HOST |
|
ADIN2111_ADDR_TO_HOST |
|
||||||
ADIN2111_ADDR_TO_OTHER_PORT;
|
ADIN2111_ADDR_TO_OTHER_PORT;
|
||||||
|
|
||||||
|
@ -582,9 +585,11 @@ static int adin2111_filter_multicast(const struct device *dev)
|
||||||
|
|
||||||
static int adin2111_filter_broadcast(const struct device *dev)
|
static int adin2111_filter_broadcast(const struct device *dev)
|
||||||
{
|
{
|
||||||
|
const struct adin2111_config *cfg = dev->config;
|
||||||
|
bool is_adin2111 = (cfg->id == ADIN2111_MAC);
|
||||||
uint8_t mac[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU};
|
uint8_t mac[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU};
|
||||||
uint32_t rules = ADIN2111_ADDR_APPLY2PORT1 |
|
uint32_t rules = ADIN2111_ADDR_APPLY2PORT1 |
|
||||||
ADIN2111_ADDR_APPLY2PORT2 |
|
(is_adin2111 ? ADIN2111_ADDR_APPLY2PORT2 : 0) |
|
||||||
ADIN2111_ADDR_TO_HOST |
|
ADIN2111_ADDR_TO_HOST |
|
||||||
ADIN2111_ADDR_TO_OTHER_PORT;
|
ADIN2111_ADDR_TO_OTHER_PORT;
|
||||||
|
|
||||||
|
@ -727,7 +732,7 @@ static int adin2111_check_spi(const struct device *dev)
|
||||||
for (count = 0U; count < ADIN2111_DEV_AWAIT_RETRY_COUNT; ++count) {
|
for (count = 0U; count < ADIN2111_DEV_AWAIT_RETRY_COUNT; ++count) {
|
||||||
ret = eth_adin2111_reg_read(dev, ADIN2111_PHYID, &val);
|
ret = eth_adin2111_reg_read(dev, ADIN2111_PHYID, &val);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
if (val == ADIN2111_PHYID_RST_VAL) {
|
if (val == ADIN2111_PHYID_RST_VAL || val == ADIN1110_PHYID_RST_VAL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
|
@ -768,6 +773,7 @@ static int adin2111_await_device(const struct device *dev)
|
||||||
static int adin2111_init(const struct device *dev)
|
static int adin2111_init(const struct device *dev)
|
||||||
{
|
{
|
||||||
const struct adin2111_config *cfg = dev->config;
|
const struct adin2111_config *cfg = dev->config;
|
||||||
|
bool is_adin2111 = (cfg->id == ADIN2111_MAC);
|
||||||
struct adin2111_data *ctx = dev->data;
|
struct adin2111_data *ctx = dev->data;
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
|
@ -880,8 +886,8 @@ static int adin2111_init(const struct device *dev)
|
||||||
/* The setting will take effect after the ports */
|
/* The setting will take effect after the ports */
|
||||||
/* are out of software powerdown. */
|
/* are out of software powerdown. */
|
||||||
val |= (ADIN2111_CONFIG2_PORT_CUT_THRU_EN |
|
val |= (ADIN2111_CONFIG2_PORT_CUT_THRU_EN |
|
||||||
ADIN2111_CONFIG2_P1_FWD_UNK2P2 |
|
(is_adin2111 ? ADIN2111_CONFIG2_P1_FWD_UNK2P2 : 0) |
|
||||||
ADIN2111_CONFIG2_P2_FWD_UNK2P1);
|
(is_adin2111 ? ADIN2111_CONFIG2_P2_FWD_UNK2P1 : 0));
|
||||||
|
|
||||||
ret = eth_adin2111_reg_write(dev, ADIN2111_CONFIG2, val);
|
ret = eth_adin2111_reg_write(dev, ADIN2111_CONFIG2, val);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -894,8 +900,8 @@ static int adin2111_init(const struct device *dev)
|
||||||
ctx->imask1 = ~(ADIN2111_IMASK1_TX_RDY_MASK |
|
ctx->imask1 = ~(ADIN2111_IMASK1_TX_RDY_MASK |
|
||||||
ADIN2111_IMASK1_P1_RX_RDY_MASK |
|
ADIN2111_IMASK1_P1_RX_RDY_MASK |
|
||||||
ADIN2111_IMASK1_SPI_ERR_MASK |
|
ADIN2111_IMASK1_SPI_ERR_MASK |
|
||||||
ADIN2111_IMASK1_P2_RX_RDY_MASK |
|
(is_adin2111 ? ADIN2111_IMASK1_P2_RX_RDY_MASK : 0) |
|
||||||
ADIN2111_IMASK1_P2_PHYINT_MASK);
|
(is_adin2111 ? ADIN2111_IMASK1_P2_PHYINT_MASK : 0));
|
||||||
|
|
||||||
/* enable interrupts */
|
/* enable interrupts */
|
||||||
ret = eth_adin2111_reg_write(dev, ADIN2111_IMASK0, ctx->imask0);
|
ret = eth_adin2111_reg_write(dev, ADIN2111_IMASK0, ctx->imask0);
|
||||||
|
@ -956,15 +962,16 @@ static const struct ethernet_api adin2111_port_api = {
|
||||||
|
|
||||||
#define ADIN2111_SPI_OPERATION ((uint16_t)(SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8)))
|
#define ADIN2111_SPI_OPERATION ((uint16_t)(SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8)))
|
||||||
|
|
||||||
#define ADIN2111_MAC_INITIALIZE(inst) \
|
#define ADIN2111_MAC_INITIALIZE(inst, dev_id, ifaces) \
|
||||||
static uint8_t __aligned(4) adin2111_buffer_##inst[CONFIG_ETH_ADIN2111_BUFFER_SIZE]; \
|
static uint8_t __aligned(4) adin2111_buffer_##inst[CONFIG_ETH_ADIN2111_BUFFER_SIZE]; \
|
||||||
static const struct adin2111_config adin2111_config_##inst = { \
|
static const struct adin2111_config adin2111_config_##inst = { \
|
||||||
|
.id = dev_id, \
|
||||||
.spi = SPI_DT_SPEC_INST_GET(inst, ADIN2111_SPI_OPERATION, 1), \
|
.spi = SPI_DT_SPEC_INST_GET(inst, ADIN2111_SPI_OPERATION, 1), \
|
||||||
.interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \
|
.interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \
|
||||||
.reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, { 0 }), \
|
.reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, { 0 }), \
|
||||||
}; \
|
}; \
|
||||||
static struct adin2111_data adin2111_data_##inst = { \
|
static struct adin2111_data adin2111_data_##inst = { \
|
||||||
.ifaces_left_to_init = 2U, \
|
.ifaces_left_to_init = ifaces, \
|
||||||
.port = {}, \
|
.port = {}, \
|
||||||
.offload_sem = Z_SEM_INITIALIZER(adin2111_data_##inst.offload_sem, 0, 1), \
|
.offload_sem = Z_SEM_INITIALIZER(adin2111_data_##inst.offload_sem, 0, 1), \
|
||||||
.lock = Z_MUTEX_INITIALIZER(adin2111_data_##inst.lock), \
|
.lock = Z_MUTEX_INITIALIZER(adin2111_data_##inst.lock), \
|
||||||
|
@ -974,9 +981,21 @@ static const struct ethernet_api adin2111_port_api = {
|
||||||
DEVICE_DT_DEFINE(DT_DRV_INST(inst), adin2111_init, NULL, \
|
DEVICE_DT_DEFINE(DT_DRV_INST(inst), adin2111_init, NULL, \
|
||||||
&adin2111_data_##inst, &adin2111_config_##inst, \
|
&adin2111_data_##inst, &adin2111_config_##inst, \
|
||||||
POST_KERNEL, CONFIG_ETH_ADIN2111_INIT_PRIORITY, \
|
POST_KERNEL, CONFIG_ETH_ADIN2111_INIT_PRIORITY, \
|
||||||
NULL); \
|
NULL);
|
||||||
|
|
||||||
|
#define ADIN2111_MAC_INIT(inst) ADIN2111_MAC_INITIALIZE(inst, ADIN2111_MAC, 2) \
|
||||||
/* ports */ \
|
/* ports */ \
|
||||||
ADIN2111_PORT_DEVICE_INIT_INSTANCE(inst, 0, 1) \
|
ADIN2111_PORT_DEVICE_INIT_INSTANCE(inst, 0, 1) \
|
||||||
ADIN2111_PORT_DEVICE_INIT_INSTANCE(inst, 1, 2)
|
ADIN2111_PORT_DEVICE_INIT_INSTANCE(inst, 1, 2)
|
||||||
|
|
||||||
DT_INST_FOREACH_STATUS_OKAY(ADIN2111_MAC_INITIALIZE)
|
#undef DT_DRV_COMPAT
|
||||||
|
#define DT_DRV_COMPAT adi_adin2111
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(ADIN2111_MAC_INIT)
|
||||||
|
|
||||||
|
#define ADIN1110_MAC_INIT(inst) ADIN2111_MAC_INITIALIZE(inst, ADIN1110_MAC, 1) \
|
||||||
|
/* ports */ \
|
||||||
|
ADIN2111_PORT_DEVICE_INIT_INSTANCE(inst, 0, 1)
|
||||||
|
|
||||||
|
#undef DT_DRV_COMPAT
|
||||||
|
#define DT_DRV_COMPAT adi_adin1110
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(ADIN1110_MAC_INIT)
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define ADIN2111_PHYID 0x01U
|
#define ADIN2111_PHYID 0x01U
|
||||||
/* PHY Identification Register Reset Value */
|
/* PHY Identification Register Reset Value */
|
||||||
#define ADIN2111_PHYID_RST_VAL 0x0283BCA1U
|
#define ADIN2111_PHYID_RST_VAL 0x0283BCA1U
|
||||||
|
#define ADIN1110_PHYID_RST_VAL 0x0283BC91U
|
||||||
|
|
||||||
/* Reset Control and Status Register */
|
/* Reset Control and Status Register */
|
||||||
#define ADIN2111_RESET 0x03U
|
#define ADIN2111_RESET 0x03U
|
||||||
|
@ -157,7 +158,13 @@
|
||||||
/* Number of buffer bytes in TxFIFO to provide frame margin upon writes */
|
/* Number of buffer bytes in TxFIFO to provide frame margin upon writes */
|
||||||
#define ADIN2111_TX_FIFO_BUFFER_MARGIN 4U
|
#define ADIN2111_TX_FIFO_BUFFER_MARGIN 4U
|
||||||
|
|
||||||
|
enum adin2111_chips_id {
|
||||||
|
ADIN2111_MAC = 0,
|
||||||
|
ADIN1110_MAC,
|
||||||
|
};
|
||||||
|
|
||||||
struct adin2111_config {
|
struct adin2111_config {
|
||||||
|
enum adin2111_chips_id id;
|
||||||
struct spi_dt_spec spi;
|
struct spi_dt_spec spi;
|
||||||
struct gpio_dt_spec interrupt;
|
struct gpio_dt_spec interrupt;
|
||||||
struct gpio_dt_spec reset;
|
struct gpio_dt_spec reset;
|
||||||
|
|
|
@ -35,6 +35,7 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL);
|
||||||
|
|
||||||
/* ADIN2111 PHY identifier */
|
/* ADIN2111 PHY identifier */
|
||||||
#define ADIN2111_PHY_ID 0x0283BCA1U
|
#define ADIN2111_PHY_ID 0x0283BCA1U
|
||||||
|
#define ADIN1110_PHY_ID 0x0283BC91U
|
||||||
|
|
||||||
/* 10BASE-T1L PMA Status Register */
|
/* 10BASE-T1L PMA Status Register */
|
||||||
#define ADIN2111_PHY_PMA_STATUS 0x000108F7U
|
#define ADIN2111_PHY_PMA_STATUS 0x000108F7U
|
||||||
|
@ -353,7 +354,7 @@ static int phy_adin2111_init(const struct device *dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phy_id != ADIN2111_PHY_ID) {
|
if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID) {
|
||||||
LOG_ERR("PHY %u unexpected PHY ID %X", cfg->phy_addr, phy_id);
|
LOG_ERR("PHY %u unexpected PHY ID %X", cfg->phy_addr, phy_id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
33
dts/bindings/ethernet/adi,adin1110.yaml
Normal file
33
dts/bindings/ethernet/adi,adin1110.yaml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Copyright (c) 2023 Analog Devices Inc.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: |
|
||||||
|
ADIN1110 standalone 10BASE-T1L Ethernet controller with SPI interface.
|
||||||
|
|
||||||
|
An example:
|
||||||
|
|
||||||
|
adin1110: adin1110@0 {
|
||||||
|
compatible = "adi,adin1110";
|
||||||
|
reg = <0x0>;
|
||||||
|
spi-max-frequency = <25000000>;
|
||||||
|
int-gpios = <&gpioe 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
|
||||||
|
reset-gpios = <&gpioe 8 GPIO_ACTIVE_LOW>;
|
||||||
|
port1 {
|
||||||
|
local-mac-address = [ CA 2F B7 10 23 63 ];
|
||||||
|
};
|
||||||
|
mdio: mdio {
|
||||||
|
compatible = "adi,adin2111-mdio";
|
||||||
|
status = "okay";
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
phy@1 {
|
||||||
|
reg = <0x1>;
|
||||||
|
compatible = "adi,adin2111-phy";
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
compatible: "adi,adin1110"
|
||||||
|
|
||||||
|
include: adi,adin2111.yaml
|
Loading…
Add table
Add a link
Reference in a new issue