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