Skip to content

Commit dc376a8

Browse files
spectrum70aescolar
authored andcommitted
drivers: eth: phy: adin2111: add support for adin1100 phy
Add support for similar adin1100 phy, boath are 10Base-T1L, only difference is that adin1100 connects through r/mii. Signed-off-by: Angelo Dureghello <angelo@kernel-space.org>
1 parent ac165f6 commit dc376a8

File tree

3 files changed

+189
-16
lines changed

3 files changed

+189
-16
lines changed

drivers/ethernet/phy/Kconfig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ config PHY_GENERIC_MII
3636
config PHY_ADIN2111
3737
bool "ADIN2111 PHY driver"
3838
default y
39-
depends on DT_HAS_ADI_ADIN2111_PHY_ENABLED
40-
depends on ETH_ADIN2111
41-
depends on MDIO_ADIN2111
39+
depends on DT_HAS_ADI_ADIN2111_PHY_ENABLED || DT_HAS_ADI_ADIN1100_PHY_ENABLED
4240
help
4341
Enable ADIN2111 PHY driver.
4442

drivers/ethernet/phy/phy_adin2111.c

Lines changed: 179 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
*/
77

88
#include <zephyr/logging/log.h>
9-
LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL);
109

10+
#if DT_NODE_HAS_STATUS(DT_INST(0, adi_adin2111_phy), okay)
1111
#define DT_DRV_COMPAT adi_adin2111_phy
12+
#else
13+
#define DT_DRV_COMPAT adi_adin1100_phy
14+
#endif
15+
16+
LOG_MODULE_REGISTER(DT_DRV_COMPAT, CONFIG_PHY_LOG_LEVEL);
1217

1318
#include <errno.h>
1419
#include <stdint.h>
@@ -23,20 +28,28 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL);
2328

2429
/* PHYs out of reset check retry delay */
2530
#define ADIN2111_PHY_AWAIT_DELAY_POLL_US 15U
26-
/* Number of retries for PHYs out of reset check */
27-
#define ADIN2111_PHY_AWAIT_RETRY_COUNT 200U
31+
/*
32+
* Number of retries for PHYs out of reset check,
33+
* rmii variants as ADIN11XX need 70ms maximum after hw reset to be up,
34+
* so the increasing the count for that, as default 25ms (sw reset) + 45.
35+
*/
36+
#define ADIN2111_PHY_AWAIT_RETRY_COUNT 3000U
2837

2938
/* PHY's software powerdown check retry delay */
3039
#define ADIN2111_PHY_SFT_PD_DELAY_POLL_US 15U
3140
/* Number of retries for PHY's software powerdown check */
3241
#define ADIN2111_PHY_SFT_PD_RETRY_COUNT 200U
3342

43+
/* Software reset, CLK_25 disabled time*/
44+
#define ADIN1100_PHY_SFT_RESET_MS 25U
45+
3446
/* PHYs autonegotiation complete timeout */
3547
#define ADIN2111_AN_COMPLETE_AWAIT_TIMEOUT_MS 3000U
3648

3749
/* ADIN2111 PHY identifier */
3850
#define ADIN2111_PHY_ID 0x0283BCA1U
3951
#define ADIN1110_PHY_ID 0x0283BC91U
52+
#define ADIN1100_PHY_ID 0x0283BC81U
4053

4154
/* System Interrupt Mask Register */
4255
#define ADIN2111_PHY_CRSM_IRQ_MASK 0x0020U
@@ -77,17 +90,26 @@ LOG_MODULE_REGISTER(phy_adin2111, CONFIG_PHY_LOG_LEVEL);
7790
/* LED 0 Enable */
7891
#define ADIN2111_PHY_LED_CNTRL_LED0_EN BIT(7)
7992

93+
/* MMD bridge regs */
94+
#define ADIN1100_MMD_ACCESS_CNTRL 0x0DU
95+
#define ADIN1100_MMD_ACCESS 0x0EU
96+
8097
struct phy_adin2111_config {
8198
const struct device *mdio;
8299
uint8_t phy_addr;
83100
bool led0_en;
84101
bool led1_en;
85102
bool tx_24v;
103+
bool mii;
86104
};
87105

88106
struct phy_adin2111_data {
107+
const struct device *dev;
89108
struct phy_link_state state;
90109
struct k_sem sem;
110+
struct k_work_delayable monitor_work;
111+
phy_callback_t cb;
112+
void *cb_data;
91113
};
92114

93115
static inline int phy_adin2111_c22_read(const struct device *dev, uint16_t reg,
@@ -106,22 +128,62 @@ static inline int phy_adin2111_c22_write(const struct device *dev, uint16_t reg,
106128
return mdio_write(cfg->mdio, cfg->phy_addr, reg, val);
107129
}
108130

109-
static inline int phy_adin2111_c45_write(const struct device *dev, uint16_t devad,
110-
uint16_t reg, uint16_t val)
131+
static int phy_adin2111_c45_setup_dev_reg(const struct device *dev, uint16_t devad,
132+
uint16_t reg)
111133
{
112134
const struct phy_adin2111_config *cfg = dev->config;
135+
int rval;
113136

114-
return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
137+
rval = mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS_CNTRL, devad);
138+
if (rval < 0) {
139+
return rval;
140+
}
141+
rval = mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, reg);
142+
if (rval < 0) {
143+
return rval;
144+
}
145+
146+
return mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS_CNTRL, devad | BIT(14));
115147
}
116148

117-
static inline int phy_adin2111_c45_read(const struct device *dev, uint16_t devad,
118-
uint16_t reg, uint16_t *val)
149+
static int phy_adin2111_c45_read(const struct device *dev, uint16_t devad,
150+
uint16_t reg, uint16_t *val)
119151
{
120152
const struct phy_adin2111_config *cfg = dev->config;
153+
int rval;
154+
155+
if (cfg->mii) {
156+
/* Using C22 -> devad bridge */
157+
rval = phy_adin2111_c45_setup_dev_reg(dev, devad, reg);
158+
if (rval < 0) {
159+
return rval;
160+
}
161+
162+
return mdio_read(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, val);
163+
}
121164

122165
return mdio_read_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
123166
}
124167

168+
static int phy_adin2111_c45_write(const struct device *dev, uint16_t devad,
169+
uint16_t reg, uint16_t val)
170+
{
171+
const struct phy_adin2111_config *cfg = dev->config;
172+
int rval;
173+
174+
if (cfg->mii) {
175+
/* Using C22 -> devad bridge */
176+
rval = phy_adin2111_c45_setup_dev_reg(dev, devad, reg);
177+
if (rval < 0) {
178+
return rval;
179+
}
180+
181+
return mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, val);
182+
}
183+
184+
return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
185+
}
186+
125187
static int phy_adin2111_reg_read(const struct device *dev, uint16_t reg_addr,
126188
uint32_t *data)
127189
{
@@ -304,6 +366,84 @@ static int phy_adin2111_cfg_link(const struct device *dev,
304366
return -ENOTSUP;
305367
}
306368

369+
static int phy_adin2111_reset(const struct device *dev)
370+
{
371+
int ret;
372+
373+
ret = phy_adin2111_c22_write(dev, MII_BMCR, MII_BMCR_RESET);
374+
if (ret < 0) {
375+
return ret;
376+
}
377+
378+
k_msleep(ADIN1100_PHY_SFT_RESET_MS);
379+
380+
return 0;
381+
}
382+
383+
static void invoke_link_cb(const struct device *dev)
384+
{
385+
struct phy_adin2111_data *const data = dev->data;
386+
struct phy_link_state state;
387+
388+
if (data->cb == NULL) {
389+
return;
390+
}
391+
392+
data->cb(dev, &state, data->cb_data);
393+
}
394+
395+
static int update_link_state(const struct device *dev)
396+
{
397+
struct phy_adin2111_data *const data = dev->data;
398+
const struct phy_adin2111_config *config = dev->config;
399+
struct phy_link_state old_state;
400+
uint16_t bmsr;
401+
int ret;
402+
403+
ret = phy_adin2111_c22_read(dev, MII_BMSR, &bmsr);
404+
if (ret < 0) {
405+
return ret;
406+
}
407+
408+
old_state = data->state;
409+
data->state.is_up = !!(bmsr & MII_BMSR_LINK_STATUS);
410+
411+
if (old_state.speed != data->state.speed || old_state.is_up != data->state.is_up) {
412+
413+
LOG_INF("PHY (%d) Link is %s", config->phy_addr, data->state.is_up ? "up" : "down");
414+
415+
if (data->state.is_up == false) {
416+
return 0;
417+
}
418+
419+
invoke_link_cb(dev);
420+
421+
LOG_INF("PHY (%d) Link speed %s Mb, %s duplex\n", config->phy_addr,
422+
(PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" : "10"),
423+
PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half");
424+
}
425+
426+
return 0;
427+
}
428+
429+
static void monitor_work_handler(struct k_work *work)
430+
{
431+
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
432+
struct phy_adin2111_data *const data =
433+
CONTAINER_OF(dwork, struct phy_adin2111_data, monitor_work);
434+
const struct device *dev = data->dev;
435+
int rc;
436+
437+
k_sem_take(&data->sem, K_FOREVER);
438+
439+
rc = update_link_state(dev);
440+
441+
k_sem_give(&data->sem);
442+
443+
/* Submit delayed work */
444+
k_work_reschedule(&data->monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD));
445+
}
446+
307447
static int phy_adin2111_init(const struct device *dev)
308448
{
309449
const struct phy_adin2111_config *const cfg = dev->config;
@@ -313,9 +453,21 @@ static int phy_adin2111_init(const struct device *dev)
313453
bool tx_24v_supported = false;
314454
int ret;
315455

456+
data->dev = dev;
316457
data->state.is_up = false;
317458
data->state.speed = LINK_FULL_10BASE_T;
318459

460+
/*
461+
* For adin1100 and further mii stuff,
462+
* reset may not be performed from the mac layer, doing a clean reset here.
463+
*/
464+
if (cfg->mii) {
465+
ret = phy_adin2111_reset(dev);
466+
if (ret < 0) {
467+
return ret;
468+
}
469+
}
470+
319471
ret = phy_adin2111_await_phy(dev);
320472
if (ret < 0) {
321473
LOG_ERR("PHY %u didn't come out of reset, %d",
@@ -330,7 +482,7 @@ static int phy_adin2111_init(const struct device *dev)
330482
return -ENODEV;
331483
}
332484

333-
if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID) {
485+
if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID && phy_id != ADIN1100_PHY_ID) {
334486
LOG_ERR("PHY %u unexpected PHY ID %X", cfg->phy_addr, phy_id);
335487
return -EINVAL;
336488
}
@@ -447,6 +599,11 @@ static int phy_adin2111_init(const struct device *dev)
447599
return ret;
448600
}
449601

602+
if (cfg->mii) {
603+
k_work_init_delayable(&data->monitor_work, monitor_work_handler);
604+
monitor_work_handler(&data->monitor_work.work);
605+
}
606+
450607
/**
451608
* done, PHY is in software powerdown (SFT PD)
452609
* exit software powerdown, PHY 1 has to exit before PHY 2
@@ -458,10 +615,17 @@ static int phy_adin2111_init(const struct device *dev)
458615
static int phy_adin2111_link_cb_set(const struct device *dev, phy_callback_t cb,
459616
void *user_data)
460617
{
461-
ARG_UNUSED(dev);
462-
ARG_UNUSED(cb);
463-
ARG_UNUSED(user_data);
464-
return -ENOTSUP;
618+
struct phy_adin2111_data *const data = dev->data;
619+
620+
data->cb = cb;
621+
data->cb_data = user_data;
622+
623+
/* Invoke the callback to notify the caller of the current
624+
* link status.
625+
*/
626+
invoke_link_cb(dev);
627+
628+
return 0;
465629
}
466630

467631
static const struct ethphy_driver_api phy_adin2111_api = {
@@ -479,6 +643,8 @@ static const struct ethphy_driver_api phy_adin2111_api = {
479643
.led0_en = DT_INST_PROP(n, led0_en), \
480644
.led1_en = DT_INST_PROP(n, led1_en), \
481645
.tx_24v = !(DT_INST_PROP(n, disable_tx_mode_24v)), \
646+
IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(adi_adin1100_phy), \
647+
(.mii = 1)) \
482648
}; \
483649
static struct phy_adin2111_data phy_adin2111_data_##n = { \
484650
.sem = Z_SEM_INITIALIZER(phy_adin2111_data_##n.sem, 1, 1), \
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (c) 2024 Analog Devices, Inc.
2+
# Copyright (c) 2024 BayLibre, SAS
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
description: ADIN1100 PHY
6+
7+
compatible: "adi,adin1100-phy"
8+
9+
include: adi,adin2111-phy.yaml

0 commit comments

Comments
 (0)