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:
Antoniu Miclaus 2023-07-20 11:48:05 +03:00 committed by Carles Cufí
commit a6e3829252
5 changed files with 77 additions and 17 deletions

View file

@ -4,7 +4,7 @@
menuconfig ETH_ADIN2111
bool "ADIN2111 2-port 10BASE-T1L Controller"
default y
depends on DT_HAS_ADI_ADIN2111_ENABLED
depends on DT_HAS_ADI_ADIN2111_ENABLED || DT_HAS_ADI_ADIN1110_ENABLED
select SPI
select MDIO
help

View file

@ -7,8 +7,6 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(eth_adin2111, CONFIG_ETHERNET_LOG_LEVEL);
#define DT_DRV_COMPAT adi_adin2111
#include <zephyr/net/net_pkt.h>
#include <zephyr/net/ethernet.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)
{
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 status1;
int ret;
@ -312,7 +313,7 @@ static void adin2111_offload_thread(const struct device *dev)
}
/* handle port 2 phy interrupts */
if (status1 & ADIN2111_STATUS1_PHYINT) {
if ((status1 & ADIN2111_STATUS1_PHYINT) && is_adin2111) {
adin2111_port_on_phyint(ctx->port[1]);
}
@ -332,7 +333,7 @@ static void adin2111_offload_thread(const struct device *dev)
}
/* handle port 2 rx */
if (status1 & ADIN2111_STATUS1_P2_RX_RDY) {
if ((status1 & ADIN2111_STATUS1_P2_RX_RDY) && is_adin2111) {
do {
ret = adin2111_read_fifo(dev, 1U);
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)
{
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};
uint32_t rules = ADIN2111_ADDR_APPLY2PORT1 |
ADIN2111_ADDR_APPLY2PORT2 |
(is_adin2111 ? ADIN2111_ADDR_APPLY2PORT2 : 0) |
ADIN2111_ADDR_TO_HOST |
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)
{
const struct adin2111_config *cfg = dev->config;
bool is_adin2111 = (cfg->id == ADIN2111_MAC);
uint8_t mac[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU};
uint32_t rules = ADIN2111_ADDR_APPLY2PORT1 |
ADIN2111_ADDR_APPLY2PORT2 |
(is_adin2111 ? ADIN2111_ADDR_APPLY2PORT2 : 0) |
ADIN2111_ADDR_TO_HOST |
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) {
ret = eth_adin2111_reg_read(dev, ADIN2111_PHYID, &val);
if (ret >= 0) {
if (val == ADIN2111_PHYID_RST_VAL) {
if (val == ADIN2111_PHYID_RST_VAL || val == ADIN1110_PHYID_RST_VAL) {
break;
}
ret = -ETIMEDOUT;
@ -768,6 +773,7 @@ static int adin2111_await_device(const struct device *dev)
static int adin2111_init(const struct device *dev)
{
const struct adin2111_config *cfg = dev->config;
bool is_adin2111 = (cfg->id == ADIN2111_MAC);
struct adin2111_data *ctx = dev->data;
int ret;
uint32_t val;
@ -880,8 +886,8 @@ static int adin2111_init(const struct device *dev)
/* The setting will take effect after the ports */
/* are out of software powerdown. */
val |= (ADIN2111_CONFIG2_PORT_CUT_THRU_EN |
ADIN2111_CONFIG2_P1_FWD_UNK2P2 |
ADIN2111_CONFIG2_P2_FWD_UNK2P1);
(is_adin2111 ? ADIN2111_CONFIG2_P1_FWD_UNK2P2 : 0) |
(is_adin2111 ? ADIN2111_CONFIG2_P2_FWD_UNK2P1 : 0));
ret = eth_adin2111_reg_write(dev, ADIN2111_CONFIG2, val);
if (ret < 0) {
@ -894,8 +900,8 @@ static int adin2111_init(const struct device *dev)
ctx->imask1 = ~(ADIN2111_IMASK1_TX_RDY_MASK |
ADIN2111_IMASK1_P1_RX_RDY_MASK |
ADIN2111_IMASK1_SPI_ERR_MASK |
ADIN2111_IMASK1_P2_RX_RDY_MASK |
ADIN2111_IMASK1_P2_PHYINT_MASK);
(is_adin2111 ? ADIN2111_IMASK1_P2_RX_RDY_MASK : 0) |
(is_adin2111 ? ADIN2111_IMASK1_P2_PHYINT_MASK : 0));
/* enable interrupts */
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_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 const struct adin2111_config adin2111_config_##inst = { \
.id = dev_id, \
.spi = SPI_DT_SPEC_INST_GET(inst, ADIN2111_SPI_OPERATION, 1), \
.interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \
.reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, { 0 }), \
}; \
static struct adin2111_data adin2111_data_##inst = { \
.ifaces_left_to_init = 2U, \
.ifaces_left_to_init = ifaces, \
.port = {}, \
.offload_sem = Z_SEM_INITIALIZER(adin2111_data_##inst.offload_sem, 0, 1), \
.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, \
&adin2111_data_##inst, &adin2111_config_##inst, \
POST_KERNEL, CONFIG_ETH_ADIN2111_INIT_PRIORITY, \
NULL); \
NULL);
#define ADIN2111_MAC_INIT(inst) ADIN2111_MAC_INITIALIZE(inst, ADIN2111_MAC, 2) \
/* ports */ \
ADIN2111_PORT_DEVICE_INIT_INSTANCE(inst, 0, 1) \
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)

View file

@ -20,6 +20,7 @@
#define ADIN2111_PHYID 0x01U
/* PHY Identification Register Reset Value */
#define ADIN2111_PHYID_RST_VAL 0x0283BCA1U
#define ADIN1110_PHYID_RST_VAL 0x0283BC91U
/* Reset Control and Status Register */
#define ADIN2111_RESET 0x03U
@ -157,7 +158,13 @@
/* Number of buffer bytes in TxFIFO to provide frame margin upon writes */
#define ADIN2111_TX_FIFO_BUFFER_MARGIN 4U
enum adin2111_chips_id {
ADIN2111_MAC = 0,
ADIN1110_MAC,
};
struct adin2111_config {
enum adin2111_chips_id id;
struct spi_dt_spec spi;
struct gpio_dt_spec interrupt;
struct gpio_dt_spec reset;

View file

@ -35,6 +35,7 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL);
/* ADIN2111 PHY identifier */
#define ADIN2111_PHY_ID 0x0283BCA1U
#define ADIN1110_PHY_ID 0x0283BC91U
/* 10BASE-T1L PMA Status Register */
#define ADIN2111_PHY_PMA_STATUS 0x000108F7U
@ -353,7 +354,7 @@ static int phy_adin2111_init(const struct device *dev)
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);
return -EINVAL;
}

View 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