1 /*
2 * Copyright (c) 2023 PHOENIX CONTACT Electronics GmbH
3 * Copyright 2023 NXP
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/logging/log.h>
9
10 #if DT_NODE_HAS_STATUS(DT_INST(0, adi_adin2111_phy), okay)
11 #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);
17
18 #include <errno.h>
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include <zephyr/kernel.h>
22 #include <zephyr/device.h>
23 #include <zephyr/sys/util.h>
24 #include <zephyr/net/phy.h>
25 #include <zephyr/net/mii.h>
26 #include <zephyr/net/mdio.h>
27 #include <zephyr/drivers/mdio.h>
28
29 /* PHYs out of reset check retry delay */
30 #define ADIN2111_PHY_AWAIT_DELAY_POLL_US 15U
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
37
38 /* PHY's software powerdown check retry delay */
39 #define ADIN2111_PHY_SFT_PD_DELAY_POLL_US 15U
40 /* Number of retries for PHY's software powerdown check */
41 #define ADIN2111_PHY_SFT_PD_RETRY_COUNT 200U
42
43 /* Software reset, CLK_25 disabled time*/
44 #define ADIN1100_PHY_SFT_RESET_MS 25U
45
46 /* PHYs autonegotiation complete timeout */
47 #define ADIN2111_AN_COMPLETE_AWAIT_TIMEOUT_MS 3000U
48
49 /* ADIN2111 PHY identifier */
50 #define ADIN2111_PHY_ID 0x0283BCA1U
51 #define ADIN1110_PHY_ID 0x0283BC91U
52 #define ADIN1100_PHY_ID 0x0283BC81U
53
54 /* System Interrupt Mask Register */
55 #define ADIN2111_PHY_CRSM_IRQ_MASK 0x0020U
56 /* System Interrupt Status Register */
57 #define ADIN2111_PHY_CRSM_IRQ_STATUS 0x0010U
58 /**
59 * Mask of reserved interrupts that indicates a fatal error in the system.
60 *
61 * There is inconsistency between RM and ADI driver example:
62 * - RM mask 0x6FFF
63 * - ADI driver example mask 0x2BFF
64 *
65 * The value from the example doesn't include reserved bits 10 and 14.
66 * The tests show that PHY is still functioning when bit 10 is raised.
67 *
68 * Here the value from ADI driver example is used instead of RM.
69 */
70 #define ADIN2111_PHY_CRSM_IRQ_STATUS_FATAL_ERR 0x2BFFU
71
72 /* PHY Subsystem Interrupt Mask Register */
73 #define ADIN2111_PHY_SUBSYS_IRQ_MASK 0x0021U
74 /* PHY Subsystem Interrupt Status Register */
75 #define ADIN2111_PHY_SUBSYS_IRQ_STATUS 0x0011U
76 /* Link Status Change */
77 #define ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH BIT(1)
78
79 /* Software Power-down Control Register */
80 #define ADIN2111_PHY_CRSM_SFT_PD_CNTRL 0x8812U
81 /* System Status Register */
82 #define ADIN2111_PHY_CRSM_STAT 0x8818U
83 /* Software Power-down Status */
84 #define ADIN2111_CRSM_STAT_CRSM_SFT_PD_RDY BIT(1)
85
86 /* LED Control Register */
87 #define ADIN2111_PHY_LED_CNTRL 0x8C82U
88 /* LED 1 Enable */
89 #define ADIN2111_PHY_LED_CNTRL_LED1_EN BIT(15)
90 /* LED 0 Enable */
91 #define ADIN2111_PHY_LED_CNTRL_LED0_EN BIT(7)
92
93 /* MMD bridge regs */
94 #define ADIN1100_MMD_ACCESS_CNTRL 0x0DU
95 #define ADIN1100_MMD_ACCESS 0x0EU
96
97 struct phy_adin2111_config {
98 const struct device *mdio;
99 uint8_t phy_addr;
100 bool led0_en;
101 bool led1_en;
102 bool tx_24v;
103 bool mii;
104 };
105
106 struct phy_adin2111_data {
107 const struct device *dev;
108 struct phy_link_state state;
109 struct k_sem sem;
110 struct k_work_delayable monitor_work;
111 phy_callback_t cb;
112 void *cb_data;
113 };
114
phy_adin2111_c22_read(const struct device * dev,uint16_t reg,uint16_t * val)115 static inline int phy_adin2111_c22_read(const struct device *dev, uint16_t reg,
116 uint16_t *val)
117 {
118 const struct phy_adin2111_config *const cfg = dev->config;
119
120 return mdio_read(cfg->mdio, cfg->phy_addr, reg, val);
121 }
122
phy_adin2111_c22_write(const struct device * dev,uint16_t reg,uint16_t val)123 static inline int phy_adin2111_c22_write(const struct device *dev, uint16_t reg,
124 uint16_t val)
125 {
126 const struct phy_adin2111_config *const cfg = dev->config;
127
128 return mdio_write(cfg->mdio, cfg->phy_addr, reg, val);
129 }
130
phy_adin2111_c45_setup_dev_reg(const struct device * dev,uint16_t devad,uint16_t reg)131 static int phy_adin2111_c45_setup_dev_reg(const struct device *dev, uint16_t devad,
132 uint16_t reg)
133 {
134 const struct phy_adin2111_config *cfg = dev->config;
135 int rval;
136
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));
147 }
148
phy_adin2111_c45_read(const struct device * dev,uint16_t devad,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)
151 {
152 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 }
164
165 return mdio_read_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
166 }
167
phy_adin2111_c45_write(const struct device * dev,uint16_t devad,uint16_t reg,uint16_t val)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
phy_adin2111_reg_read(const struct device * dev,uint16_t reg_addr,uint32_t * data)187 static int phy_adin2111_reg_read(const struct device *dev, uint16_t reg_addr,
188 uint32_t *data)
189 {
190 const struct phy_adin2111_config *cfg = dev->config;
191 int ret;
192
193 mdio_bus_enable(cfg->mdio);
194
195 ret = phy_adin2111_c22_read(dev, reg_addr, (uint16_t *) data);
196
197 mdio_bus_disable(cfg->mdio);
198
199 return ret;
200 }
201
phy_adin2111_reg_write(const struct device * dev,uint16_t reg_addr,uint32_t data)202 static int phy_adin2111_reg_write(const struct device *dev, uint16_t reg_addr,
203 uint32_t data)
204 {
205 const struct phy_adin2111_config *cfg = dev->config;
206 int ret;
207
208 mdio_bus_enable(cfg->mdio);
209
210 ret = phy_adin2111_c22_write(dev, reg_addr, (uint16_t) data);
211
212 mdio_bus_disable(cfg->mdio);
213
214 return ret;
215 }
216
phy_adin2111_await_phy(const struct device * dev)217 static int phy_adin2111_await_phy(const struct device *dev)
218 {
219 int ret;
220 uint32_t count;
221 uint16_t val;
222
223 /**
224 * Port 2 PHY comes out of reset after Port 1 PHY,
225 * wait until both are out of reset.
226 * Reading Port 2 PHY registers returns 0s until
227 * it comes out from reset.
228 */
229 for (count = 0U; count < ADIN2111_PHY_AWAIT_RETRY_COUNT; ++count) {
230 ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
231 ADIN2111_PHY_CRSM_IRQ_MASK, &val);
232 if (ret >= 0) {
233 if (val != 0U) {
234 break;
235 }
236 ret = -ETIMEDOUT;
237 }
238 k_sleep(K_USEC(ADIN2111_PHY_AWAIT_DELAY_POLL_US));
239 }
240
241 return ret;
242 }
243
phy_adin2111_an_state_read(const struct device * dev)244 static int phy_adin2111_an_state_read(const struct device *dev)
245 {
246 struct phy_adin2111_data *const data = dev->data;
247 uint16_t bmsr;
248 int ret;
249
250 /* read twice to get actual link status, latch low */
251 ret = phy_adin2111_c22_read(dev, MII_BMSR, &bmsr);
252 if (ret < 0) {
253 return ret;
254 }
255 ret = phy_adin2111_c22_read(dev, MII_BMSR, &bmsr);
256 if (ret < 0) {
257 return ret;
258 }
259
260 data->state.is_up = !!(bmsr & MII_BMSR_LINK_STATUS);
261
262 return 0;
263 }
264
phy_adin2111_handle_phy_irq(const struct device * dev,struct phy_link_state * state)265 int phy_adin2111_handle_phy_irq(const struct device *dev,
266 struct phy_link_state *state)
267 {
268 struct phy_adin2111_data *const data = dev->data;
269 uint16_t subsys_status;
270 int ret;
271
272 ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC2,
273 ADIN2111_PHY_SUBSYS_IRQ_STATUS,
274 &subsys_status);
275 if (ret < 0) {
276 return ret;
277 }
278
279 if ((subsys_status & ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH) == 0U) {
280 /* nothing to process */
281 return -EAGAIN;
282 }
283
284 k_sem_take(&data->sem, K_FOREVER);
285
286 ret = phy_adin2111_an_state_read(dev);
287
288 memcpy(state, &data->state, sizeof(struct phy_link_state));
289
290 k_sem_give(&data->sem);
291
292 return ret;
293 }
294
phy_adin2111_sft_pd(const struct device * dev,bool enter)295 static int phy_adin2111_sft_pd(const struct device *dev, bool enter)
296 {
297 int ret;
298 uint32_t count;
299 const uint16_t expected = enter ? ADIN2111_CRSM_STAT_CRSM_SFT_PD_RDY : 0U;
300 uint16_t val;
301
302 ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1,
303 ADIN2111_PHY_CRSM_SFT_PD_CNTRL,
304 enter ? 1U : 0U);
305 if (ret < 0) {
306 return ret;
307 }
308
309 for (count = 0U; count < ADIN2111_PHY_SFT_PD_RETRY_COUNT; ++count) {
310 ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
311 ADIN2111_PHY_CRSM_STAT, &val);
312 if (ret >= 0) {
313 if ((val & ADIN2111_CRSM_STAT_CRSM_SFT_PD_RDY) == expected) {
314 break;
315 }
316 ret = -ETIMEDOUT;
317 }
318 k_sleep(K_USEC(ADIN2111_PHY_SFT_PD_DELAY_POLL_US));
319 }
320
321 return ret;
322 }
323
phy_adin2111_id(const struct device * dev,uint32_t * phy_id)324 static int phy_adin2111_id(const struct device *dev, uint32_t *phy_id)
325 {
326 uint16_t val;
327
328 if (phy_adin2111_c22_read(dev, MII_PHYID1R, &val) < 0) {
329 return -EIO;
330 }
331
332 *phy_id = (val & UINT16_MAX) << 16;
333
334 if (phy_adin2111_c22_read(dev, MII_PHYID2R, &val) < 0) {
335 return -EIO;
336 }
337
338 *phy_id |= (val & UINT16_MAX);
339
340 return 0;
341 }
342
phy_adin2111_get_link_state(const struct device * dev,struct phy_link_state * state)343 static int phy_adin2111_get_link_state(const struct device *dev,
344 struct phy_link_state *state)
345 {
346 struct phy_adin2111_data *const data = dev->data;
347
348 k_sem_take(&data->sem, K_FOREVER);
349
350 memcpy(state, &data->state, sizeof(struct phy_link_state));
351
352 k_sem_give(&data->sem);
353
354 return 0;
355 }
356
phy_adin2111_cfg_link(const struct device * dev,enum phy_link_speed adv_speeds)357 static int phy_adin2111_cfg_link(const struct device *dev,
358 enum phy_link_speed adv_speeds)
359 {
360 ARG_UNUSED(dev);
361
362 if (!!(adv_speeds & LINK_FULL_10BASE_T)) {
363 return 0;
364 }
365
366 return -ENOTSUP;
367 }
368
phy_adin2111_reset(const struct device * dev)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
invoke_link_cb(const struct device * dev)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
update_link_state(const struct device * dev)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
monitor_work_handler(struct k_work * work)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
phy_adin2111_init(const struct device * dev)447 static int phy_adin2111_init(const struct device *dev)
448 {
449 const struct phy_adin2111_config *const cfg = dev->config;
450 struct phy_adin2111_data *const data = dev->data;
451 uint32_t phy_id;
452 uint16_t val;
453 bool tx_24v_supported = false;
454 int ret;
455
456 data->dev = dev;
457 data->state.is_up = false;
458 data->state.speed = LINK_FULL_10BASE_T;
459
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
471 ret = phy_adin2111_await_phy(dev);
472 if (ret < 0) {
473 LOG_ERR("PHY %u didn't come out of reset, %d",
474 cfg->phy_addr, ret);
475 return -ENODEV;
476 }
477
478 ret = phy_adin2111_id(dev, &phy_id);
479 if (ret < 0) {
480 LOG_ERR("Failed to read PHY %u ID, %d",
481 cfg->phy_addr, ret);
482 return -ENODEV;
483 }
484
485 if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID && phy_id != ADIN1100_PHY_ID) {
486 LOG_ERR("PHY %u unexpected PHY ID %X", cfg->phy_addr, phy_id);
487 return -EINVAL;
488 }
489
490 LOG_INF("PHY %u ID %X", cfg->phy_addr, phy_id);
491
492 /* enter software powerdown */
493 ret = phy_adin2111_sft_pd(dev, true);
494 if (ret < 0) {
495 return ret;
496 }
497
498 /* disable interrupts */
499 ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1,
500 ADIN2111_PHY_CRSM_IRQ_MASK, 0U);
501 if (ret < 0) {
502 return ret;
503 }
504
505 /* enable link status change irq */
506 ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC2,
507 ADIN2111_PHY_SUBSYS_IRQ_MASK,
508 ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH);
509 if (ret < 0) {
510 return ret;
511 }
512
513 /* clear PHY IRQ status before enabling ADIN IRQs */
514 ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
515 ADIN2111_PHY_CRSM_IRQ_STATUS, &val);
516 if (ret < 0) {
517 return ret;
518 }
519
520 if (val & ADIN2111_PHY_CRSM_IRQ_STATUS_FATAL_ERR) {
521 LOG_ERR("PHY %u CRSM reports fatal system error", cfg->phy_addr);
522 return -ENODEV;
523 }
524
525 ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC2,
526 ADIN2111_PHY_SUBSYS_IRQ_STATUS, &val);
527 if (ret < 0) {
528 return ret;
529 }
530
531 if (!cfg->led0_en || !cfg->led1_en) {
532 ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
533 ADIN2111_PHY_LED_CNTRL, &val);
534 if (ret < 0) {
535 return ret;
536 }
537 if (!cfg->led0_en) {
538 val &= ~(ADIN2111_PHY_LED_CNTRL_LED0_EN);
539 }
540 if (!cfg->led1_en) {
541 val &= ~(ADIN2111_PHY_LED_CNTRL_LED1_EN);
542 }
543 ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1,
544 ADIN2111_PHY_LED_CNTRL, val);
545 if (ret < 0) {
546 return ret;
547 }
548 }
549
550 /* check 2.4V support */
551 ret = phy_adin2111_c45_read(dev, MDIO_MMD_PMAPMD, MDIO_PMA_B10L_STAT, &val);
552 if (ret < 0) {
553 return ret;
554 }
555
556 tx_24v_supported = !!(val & MDIO_PMA_B10L_STAT_2V4_ABLE);
557
558 LOG_INF("PHY %u 2.4V mode %s", cfg->phy_addr,
559 tx_24v_supported ? "supported" : "not supported");
560
561 if (!cfg->tx_24v & tx_24v_supported) {
562 LOG_ERR("PHY %u 2.4V mode supported, but not enabled",
563 cfg->phy_addr);
564 }
565
566 /* config 2.4V auto-negotiation */
567 ret = phy_adin2111_c45_read(dev, MDIO_MMD_AN, MDIO_AN_T1_ADV_H, &val);
568 if (ret < 0) {
569 return ret;
570 }
571
572 if (tx_24v_supported) {
573 val |= MDIO_AN_T1_ADV_H_10L_TX_HI;
574 } else {
575 val &= ~MDIO_AN_T1_ADV_H_10L_TX_HI;
576 }
577
578 if (cfg->tx_24v) {
579 if (!tx_24v_supported) {
580 LOG_ERR("PHY %u 2.4V mode enabled, but not supported",
581 cfg->phy_addr);
582 return -EINVAL;
583 }
584
585 val |= MDIO_AN_T1_ADV_H_10L_TX_HI_REQ;
586 } else {
587 val &= ~MDIO_AN_T1_ADV_H_10L_TX_HI_REQ;
588 }
589
590 ret = phy_adin2111_c45_write(dev, MDIO_MMD_AN, MDIO_AN_T1_ADV_H, val);
591 if (ret < 0) {
592 return ret;
593 }
594
595 /* enable auto-negotiation */
596 ret = phy_adin2111_c45_write(dev, MDIO_MMD_AN, MDIO_AN_T1_CTRL,
597 MDIO_AN_T1_CTRL_EN);
598 if (ret < 0) {
599 return ret;
600 }
601
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
607 /**
608 * done, PHY is in software powerdown (SFT PD)
609 * exit software powerdown, PHY 1 has to exit before PHY 2
610 * correct PHY order is expected to be in DTS to guarantee that
611 */
612 return phy_adin2111_sft_pd(dev, false);
613 }
614
phy_adin2111_link_cb_set(const struct device * dev,phy_callback_t cb,void * user_data)615 static int phy_adin2111_link_cb_set(const struct device *dev, phy_callback_t cb,
616 void *user_data)
617 {
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;
629 }
630
631 static const struct ethphy_driver_api phy_adin2111_api = {
632 .get_link = phy_adin2111_get_link_state,
633 .cfg_link = phy_adin2111_cfg_link,
634 .link_cb_set = phy_adin2111_link_cb_set,
635 .read = phy_adin2111_reg_read,
636 .write = phy_adin2111_reg_write,
637 };
638
639 #define ADIN2111_PHY_INITIALIZE(n) \
640 static const struct phy_adin2111_config phy_adin2111_config_##n = { \
641 .mdio = DEVICE_DT_GET(DT_INST_BUS(n)), \
642 .phy_addr = DT_INST_REG_ADDR(n), \
643 .led0_en = DT_INST_PROP(n, led0_en), \
644 .led1_en = DT_INST_PROP(n, led1_en), \
645 .tx_24v = !(DT_INST_PROP(n, disable_tx_mode_24v)), \
646 IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(adi_adin1100_phy), \
647 (.mii = 1)) \
648 }; \
649 static struct phy_adin2111_data phy_adin2111_data_##n = { \
650 .sem = Z_SEM_INITIALIZER(phy_adin2111_data_##n.sem, 1, 1), \
651 }; \
652 DEVICE_DT_INST_DEFINE(n, &phy_adin2111_init, NULL, \
653 &phy_adin2111_data_##n, &phy_adin2111_config_##n, \
654 POST_KERNEL, CONFIG_PHY_INIT_PRIORITY, \
655 &phy_adin2111_api);
656
657 DT_INST_FOREACH_STATUS_OKAY(ADIN2111_PHY_INITIALIZE)
658