diff --git a/drivers/ethernet/eth_w5500.c b/drivers/ethernet/eth_w5500.c index 0b3febde9bf97..7e9be01e55b8e 100644 --- a/drivers/ethernet/eth_w5500.c +++ b/drivers/ethernet/eth_w5500.c @@ -216,7 +216,6 @@ static void w5500_rx(const struct device *dev) struct net_buf *pkt_buf = NULL; struct net_pkt *pkt; struct w5500_runtime *ctx = dev->data; - const struct w5500_config *config = dev->config; w5500_spi_read(dev, W5500_S0_RX_RSR, tmp, 2); rx_buf_len = sys_get_be16(tmp); @@ -231,8 +230,8 @@ static void w5500_rx(const struct device *dev) w5500_readbuf(dev, off, header, 2); rx_len = sys_get_be16(header) - 2; - pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, rx_len, - NET_AF_UNSPEC, 0, K_MSEC(config->timeout)); + pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, rx_len, NET_AF_UNSPEC, 0, + K_MSEC(CONFIG_ETH_W5500_TIMEOUT)); if (!pkt) { eth_stats_update_errors_rx(ctx->iface); return; @@ -279,21 +278,36 @@ static void w5500_update_link_status(const struct device *dev) { uint8_t phycfgr; struct w5500_runtime *ctx = dev->data; + enum phy_link_speed speed; if (w5500_spi_read(dev, W5500_PHYCFGR, &phycfgr, 1) < 0) { return; } - if (phycfgr & 0x01) { - if (ctx->link_up != true) { + if (IS_BIT_SET(phycfgr, W5500_PHYCFGR_LNK_BIT)) { + if (ctx->state.is_up != true) { LOG_INF("%s: Link up", dev->name); - ctx->link_up = true; + ctx->state.is_up = true; net_eth_carrier_on(ctx->iface); } + + speed = IS_BIT_SET(phycfgr, W5500_PHYCFGR_SPD_BIT) + ? (IS_BIT_SET(phycfgr, W5500_PHYCFGR_DPX_BIT) ? LINK_FULL_100BASE + : LINK_HALF_100BASE) + : (IS_BIT_SET(phycfgr, W5500_PHYCFGR_DPX_BIT) ? LINK_FULL_10BASE + : LINK_HALF_10BASE); + + if (ctx->state.speed != speed) { + ctx->state.speed = speed; + LOG_INF("%s: Link speed %s Mb, %s duplex", dev->name, + PHY_LINK_IS_SPEED_100M(speed) ? "100" : "10", + PHY_LINK_IS_FULL_DUPLEX(speed) ? "full" : "half"); + } } else { - if (ctx->link_up != false) { + if (ctx->state.is_up != false) { LOG_INF("%s: Link down", dev->name); - ctx->link_up = false; + ctx->state.is_up = false; + ctx->state.speed = 0; net_eth_carrier_off(ctx->iface); } } @@ -315,7 +329,7 @@ static void w5500_thread(void *p1, void *p2, void *p3) if (res == 0) { /* semaphore taken, update link status and receive packets */ - if (ctx->link_up != true) { + if (ctx->state.is_up != true) { w5500_update_link_status(dev); } @@ -459,15 +473,38 @@ static int w5500_hw_stop(const struct device *dev) return 0; } +static const struct device *w5500_get_phy(const struct device *dev) +{ + const struct w5500_config *config = dev->config; + + return config->phy_dev; +} + static const struct ethernet_api w5500_api_funcs = { .iface_api.init = w5500_iface_init, .get_capabilities = w5500_get_capabilities, .set_config = w5500_set_config, .start = w5500_hw_start, .stop = w5500_hw_stop, + .get_phy = w5500_get_phy, .send = w5500_tx, }; +static int w5500_get_link_state(const struct device *dev, + struct phy_link_state *state) +{ + struct w5500_runtime *const data = dev->data; + + state->speed = data->state.speed; + state->is_up = data->state.is_up; + + return 0; +} + +static DEVICE_API(ethphy, w5500_phy_driver_api) = { + .get_link = w5500_get_link_state, +}; + static int w5500_soft_reset(const struct device *dev) { int ret; @@ -531,8 +568,6 @@ static int w5500_init(const struct device *dev) const struct w5500_config *config = dev->config; struct w5500_runtime *ctx = dev->data; - ctx->link_up = false; - if (!spi_is_ready_dt(&config->spi)) { LOG_ERR("SPI master port %s not ready", config->spi.bus->name); return -EINVAL; @@ -600,6 +635,8 @@ static int w5500_init(const struct device *dev) return 0; } +DEVICE_DECLARE(eth_w5500_phy_0); + static struct w5500_runtime w5500_0_runtime = { #if NODE_HAS_VALID_MAC_ADDR(DT_DRV_INST(0)) .mac_addr = DT_INST_PROP(0, local_mac_address), @@ -614,10 +651,13 @@ static const struct w5500_config w5500_0_config = { .spi = SPI_DT_SPEC_INST_GET(0, SPI_WORD_SET(8)), .interrupt = GPIO_DT_SPEC_INST_GET(0, int_gpios), .reset = GPIO_DT_SPEC_INST_GET_OR(0, reset_gpios, { 0 }), - .timeout = CONFIG_ETH_W5500_TIMEOUT, + .phy_dev = DEVICE_GET(eth_w5500_phy_0), }; ETH_NET_DEVICE_DT_INST_DEFINE(0, w5500_init, NULL, &w5500_0_runtime, &w5500_0_config, CONFIG_ETH_INIT_PRIORITY, &w5500_api_funcs, NET_ETH_MTU); + +DEVICE_DEFINE(eth_w5500_phy_0, DEVICE_DT_NAME(DT_DRV_INST(0)) "_phy", NULL, NULL, &w5500_0_runtime, + &w5500_0_config, POST_KERNEL, CONFIG_ETH_INIT_PRIORITY, &w5500_phy_driver_api); diff --git a/drivers/ethernet/eth_w5500_priv.h b/drivers/ethernet/eth_w5500_priv.h index 79383d9004be3..a9e3697173b80 100644 --- a/drivers/ethernet/eth_w5500_priv.h +++ b/drivers/ethernet/eth_w5500_priv.h @@ -8,6 +8,7 @@ #include #include +#include #ifndef _W5500_ #define _W5500_ @@ -27,6 +28,10 @@ #define W5500_COMMON_REGS_LEN 0x0040 #define W5500_PHYCFGR 0x002E /* PHY Configuration register */ +#define W5500_PHYCFGR_LNK_BIT 1 /* Link status */ +#define W5500_PHYCFGR_SPD_BIT 2 /* Speed status */ +#define W5500_PHYCFGR_DPX_BIT 3 /* Duplex status */ + #define W5500_Sn_MR 0x0000 /* Sn Mode Register */ #define W5500_Sn_CR 0x0001 /* Sn Command Register */ #define W5500_Sn_IR 0x0002 /* Sn Interrupt Register */ @@ -83,7 +88,7 @@ struct w5500_config { struct spi_dt_spec spi; struct gpio_dt_spec interrupt; struct gpio_dt_spec reset; - int32_t timeout; + const struct device *phy_dev; }; struct w5500_runtime { @@ -96,7 +101,7 @@ struct w5500_runtime { struct gpio_callback gpio_cb; struct k_sem tx_sem; struct k_sem int_sem; - bool link_up; + struct phy_link_state state; uint8_t buf[NET_ETH_MAX_FRAME_SIZE]; };