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 LOG_MODULE_REGISTER(DT_DRV_COMPAT, CONFIG_PHY_LOG_LEVEL);
11 
12 #include <errno.h>
13 #include <stdint.h>
14 #include <stdbool.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/device.h>
17 #include <zephyr/sys/util.h>
18 #include <zephyr/net/phy.h>
19 #include <zephyr/net/mii.h>
20 #include <zephyr/net/mdio.h>
21 #include <zephyr/drivers/mdio.h>
22 
23 /* PHYs out of reset check retry delay */
24 #define ADIN2111_PHY_AWAIT_DELAY_POLL_US			15U
25 /*
26  * Number of retries for PHYs out of reset check,
27  * rmii variants as ADIN11XX need 70ms maximum after hw reset to be up,
28  * so the increasing the count for that, as default 25ms (sw reset) + 45.
29  */
30 #define ADIN2111_PHY_AWAIT_RETRY_COUNT				3000U
31 
32 /* PHY's software powerdown check retry delay */
33 #define ADIN2111_PHY_SFT_PD_DELAY_POLL_US			15U
34 /* Number of retries for PHY's software powerdown check */
35 #define ADIN2111_PHY_SFT_PD_RETRY_COUNT				200U
36 
37 /* Software reset, CLK_25 disabled time*/
38 #define ADIN1100_PHY_SFT_RESET_MS				25U
39 
40 /* PHYs autonegotiation complete timeout */
41 #define ADIN2111_AN_COMPLETE_AWAIT_TIMEOUT_MS			3000U
42 
43 /* ADIN2111 PHY identifier */
44 #define ADIN2111_PHY_ID						0x0283BCA1U
45 #define ADIN1110_PHY_ID						0x0283BC91U
46 #define ADIN1100_PHY_ID						0x0283BC81U
47 
48 /* System Interrupt Mask Register */
49 #define ADIN2111_PHY_CRSM_IRQ_MASK				0x0020U
50 /* System Interrupt Status Register */
51 #define ADIN2111_PHY_CRSM_IRQ_STATUS				0x0010U
52 /**
53  * Mask of reserved interrupts that indicates a fatal error in the system.
54  *
55  * There is inconsistency between RM and ADI driver example:
56  *   - RM mask 0x6FFF
57  *   - ADI driver example mask 0x2BFF
58  *
59  * The value from the example doesn't include reserved bits 10 and 14.
60  * The tests show that PHY is still functioning when bit 10 is raised.
61  *
62  * Here the value from ADI driver example is used instead of RM.
63  */
64 #define ADIN2111_PHY_CRSM_IRQ_STATUS_FATAL_ERR			0x2BFFU
65 
66 /* PHY Subsystem Interrupt Mask Register */
67 #define ADIN2111_PHY_SUBSYS_IRQ_MASK				0x0021U
68 /* PHY Subsystem Interrupt Status Register */
69 #define ADIN2111_PHY_SUBSYS_IRQ_STATUS				0x0011U
70 /* Link Status Change */
71 #define ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH	BIT(1)
72 
73 /* Software Power-down Control Register */
74 #define ADIN2111_PHY_CRSM_SFT_PD_CNTRL				0x8812U
75 /* System Status Register */
76 #define ADIN2111_PHY_CRSM_STAT					0x8818U
77 /* Software Power-down Status */
78 #define ADIN2111_CRSM_STAT_CRSM_SFT_PD_RDY			BIT(1)
79 
80 /* LED Control Register */
81 #define ADIN2111_PHY_LED_CNTRL					0x8C82U
82 /* LED 1 Enable */
83 #define ADIN2111_PHY_LED_CNTRL_LED1_EN				BIT(15)
84 /* LED 0 Enable */
85 #define ADIN2111_PHY_LED_CNTRL_LED0_EN				BIT(7)
86 
87 /* MMD bridge regs */
88 #define ADIN1100_MMD_ACCESS_CNTRL				0x0DU
89 #define ADIN1100_MMD_ACCESS					0x0EU
90 
91 struct phy_adin2111_config {
92 	const struct device *mdio;
93 	uint8_t phy_addr;
94 	bool led0_en;
95 	bool led1_en;
96 	bool tx_24v;
97 	bool mii;
98 };
99 
100 struct phy_adin2111_data {
101 	const struct device *dev;
102 	struct phy_link_state state;
103 	struct k_sem sem;
104 	struct k_work_delayable monitor_work;
105 	phy_callback_t cb;
106 	void *cb_data;
107 };
108 
phy_adin2111_c22_read(const struct device * dev,uint16_t reg,uint16_t * val)109 static inline int phy_adin2111_c22_read(const struct device *dev, uint16_t reg,
110 					uint16_t *val)
111 {
112 	const struct phy_adin2111_config *const cfg = dev->config;
113 
114 	return mdio_read(cfg->mdio, cfg->phy_addr, reg, val);
115 }
116 
phy_adin2111_c22_write(const struct device * dev,uint16_t reg,uint16_t val)117 static inline int phy_adin2111_c22_write(const struct device *dev, uint16_t reg,
118 					 uint16_t val)
119 {
120 	const struct phy_adin2111_config *const cfg = dev->config;
121 
122 	return mdio_write(cfg->mdio, cfg->phy_addr, reg, val);
123 }
124 
phy_adin2111_c45_setup_dev_reg(const struct device * dev,uint16_t devad,uint16_t reg)125 static int phy_adin2111_c45_setup_dev_reg(const struct device *dev, uint16_t devad,
126 					  uint16_t reg)
127 {
128 	const struct phy_adin2111_config *cfg = dev->config;
129 	int rval;
130 
131 	rval = mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS_CNTRL, devad);
132 	if (rval < 0) {
133 		return rval;
134 	}
135 	rval = mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, reg);
136 	if (rval < 0) {
137 		return rval;
138 	}
139 
140 	return mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS_CNTRL, devad | BIT(14));
141 }
142 
phy_adin2111_c45_read(const struct device * dev,uint16_t devad,uint16_t reg,uint16_t * val)143 static int phy_adin2111_c45_read(const struct device *dev, uint16_t devad,
144 				 uint16_t reg, uint16_t *val)
145 {
146 	const struct phy_adin2111_config *cfg = dev->config;
147 	int rval;
148 
149 	if (cfg->mii) {
150 		/* Using C22 -> devad bridge */
151 		rval = phy_adin2111_c45_setup_dev_reg(dev, devad, reg);
152 		if (rval < 0) {
153 			return rval;
154 		}
155 
156 		return mdio_read(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, val);
157 	}
158 
159 	return mdio_read_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
160 }
161 
phy_adin2111_c45_write(const struct device * dev,uint16_t devad,uint16_t reg,uint16_t val)162 static int phy_adin2111_c45_write(const struct device *dev, uint16_t devad,
163 				  uint16_t reg, uint16_t val)
164 {
165 	const struct phy_adin2111_config *cfg = dev->config;
166 	int rval;
167 
168 	if (cfg->mii) {
169 		/* Using C22 -> devad bridge */
170 		rval = phy_adin2111_c45_setup_dev_reg(dev, devad, reg);
171 		if (rval < 0) {
172 			return rval;
173 		}
174 
175 		return mdio_write(cfg->mdio, cfg->phy_addr, ADIN1100_MMD_ACCESS, val);
176 	}
177 
178 	return mdio_write_c45(cfg->mdio, cfg->phy_addr, devad, reg, val);
179 }
180 
phy_adin2111_reg_read(const struct device * dev,uint16_t reg_addr,uint32_t * data)181 static int phy_adin2111_reg_read(const struct device *dev, uint16_t reg_addr,
182 				 uint32_t *data)
183 {
184 	const struct phy_adin2111_config *cfg = dev->config;
185 	int ret;
186 
187 	mdio_bus_enable(cfg->mdio);
188 
189 	ret = phy_adin2111_c22_read(dev, reg_addr, (uint16_t *) data);
190 
191 	mdio_bus_disable(cfg->mdio);
192 
193 	return ret;
194 }
195 
phy_adin2111_reg_write(const struct device * dev,uint16_t reg_addr,uint32_t data)196 static int phy_adin2111_reg_write(const struct device *dev, uint16_t reg_addr,
197 				  uint32_t data)
198 {
199 	const struct phy_adin2111_config *cfg = dev->config;
200 	int ret;
201 
202 	mdio_bus_enable(cfg->mdio);
203 
204 	ret = phy_adin2111_c22_write(dev, reg_addr, (uint16_t) data);
205 
206 	mdio_bus_disable(cfg->mdio);
207 
208 	return ret;
209 }
210 
phy_adin2111_await_phy(const struct device * dev)211 static int phy_adin2111_await_phy(const struct device *dev)
212 {
213 	int ret;
214 	uint32_t count;
215 	uint16_t val;
216 
217 	/**
218 	 * Port 2 PHY comes out of reset after Port 1 PHY,
219 	 * wait until both are out of reset.
220 	 * Reading Port 2 PHY registers returns 0s until
221 	 * it comes out from reset.
222 	 */
223 	for (count = 0U; count < ADIN2111_PHY_AWAIT_RETRY_COUNT; ++count) {
224 		ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
225 					    ADIN2111_PHY_CRSM_IRQ_MASK, &val);
226 		if (ret >= 0) {
227 			if (val != 0U) {
228 				break;
229 			}
230 			ret = -ETIMEDOUT;
231 		}
232 		k_sleep(K_USEC(ADIN2111_PHY_AWAIT_DELAY_POLL_US));
233 	}
234 
235 	return ret;
236 }
237 
phy_adin2111_an_state_read(const struct device * dev)238 static int phy_adin2111_an_state_read(const struct device *dev)
239 {
240 	struct phy_adin2111_data *const data = dev->data;
241 	uint16_t bmsr;
242 	int ret;
243 
244 	/* read twice to get actual link status, latch low */
245 	ret = phy_adin2111_c22_read(dev, MII_BMSR, &bmsr);
246 	if (ret < 0) {
247 		return ret;
248 	}
249 	ret = phy_adin2111_c22_read(dev, MII_BMSR, &bmsr);
250 	if (ret < 0) {
251 		return ret;
252 	}
253 
254 	data->state.is_up = !!(bmsr & MII_BMSR_LINK_STATUS);
255 
256 	return 0;
257 }
258 
phy_adin2111_handle_phy_irq(const struct device * dev,struct phy_link_state * state)259 int phy_adin2111_handle_phy_irq(const struct device *dev,
260 				struct phy_link_state *state)
261 {
262 	struct phy_adin2111_data *const data = dev->data;
263 	uint16_t subsys_status;
264 	int ret;
265 
266 	ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC2,
267 				    ADIN2111_PHY_SUBSYS_IRQ_STATUS,
268 				    &subsys_status);
269 	if (ret < 0) {
270 		return ret;
271 	}
272 
273 	if ((subsys_status & ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH) == 0U) {
274 		/* nothing to process */
275 		return -EAGAIN;
276 	}
277 
278 	k_sem_take(&data->sem, K_FOREVER);
279 
280 	ret = phy_adin2111_an_state_read(dev);
281 
282 	memcpy(state, &data->state, sizeof(struct phy_link_state));
283 
284 	k_sem_give(&data->sem);
285 
286 	return ret;
287 }
288 
phy_adin2111_sft_pd(const struct device * dev,bool enter)289 static int phy_adin2111_sft_pd(const struct device *dev, bool enter)
290 {
291 	int ret;
292 	uint32_t count;
293 	const uint16_t expected = enter ? ADIN2111_CRSM_STAT_CRSM_SFT_PD_RDY : 0U;
294 	uint16_t val;
295 
296 	ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1,
297 				     ADIN2111_PHY_CRSM_SFT_PD_CNTRL,
298 				     enter ? 1U : 0U);
299 	if (ret < 0) {
300 		return ret;
301 	}
302 
303 	for (count = 0U; count < ADIN2111_PHY_SFT_PD_RETRY_COUNT; ++count) {
304 		ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
305 					    ADIN2111_PHY_CRSM_STAT, &val);
306 		if (ret >= 0) {
307 			if ((val & ADIN2111_CRSM_STAT_CRSM_SFT_PD_RDY) == expected) {
308 				break;
309 			}
310 			ret = -ETIMEDOUT;
311 		}
312 		k_sleep(K_USEC(ADIN2111_PHY_SFT_PD_DELAY_POLL_US));
313 	}
314 
315 	return ret;
316 }
317 
phy_adin2111_id(const struct device * dev,uint32_t * phy_id)318 static int phy_adin2111_id(const struct device *dev, uint32_t *phy_id)
319 {
320 	uint16_t val;
321 
322 	if (phy_adin2111_c22_read(dev, MII_PHYID1R, &val) < 0) {
323 		return -EIO;
324 	}
325 
326 	*phy_id = (val & UINT16_MAX) << 16;
327 
328 	if (phy_adin2111_c22_read(dev, MII_PHYID2R, &val) < 0) {
329 		return -EIO;
330 	}
331 
332 	*phy_id |= (val & UINT16_MAX);
333 
334 	return 0;
335 }
336 
phy_adin2111_get_link_state(const struct device * dev,struct phy_link_state * state)337 static int phy_adin2111_get_link_state(const struct device *dev,
338 				       struct phy_link_state *state)
339 {
340 	struct phy_adin2111_data *const data = dev->data;
341 
342 	k_sem_take(&data->sem, K_FOREVER);
343 
344 	memcpy(state, &data->state, sizeof(struct phy_link_state));
345 
346 	k_sem_give(&data->sem);
347 
348 	return 0;
349 }
350 
phy_adin2111_cfg_link(const struct device * dev,enum phy_link_speed adv_speeds)351 static int phy_adin2111_cfg_link(const struct device *dev,
352 				 enum phy_link_speed adv_speeds)
353 {
354 	ARG_UNUSED(dev);
355 
356 	if (!!(adv_speeds & LINK_FULL_10BASE_T)) {
357 		return 0;
358 	}
359 
360 	return -ENOTSUP;
361 }
362 
phy_adin2111_reset(const struct device * dev)363 static int phy_adin2111_reset(const struct device *dev)
364 {
365 	int ret;
366 
367 	ret = phy_adin2111_c22_write(dev, MII_BMCR, MII_BMCR_RESET);
368 	if (ret < 0) {
369 		return ret;
370 	}
371 
372 	k_msleep(ADIN1100_PHY_SFT_RESET_MS);
373 
374 	return 0;
375 }
376 
invoke_link_cb(const struct device * dev)377 static void invoke_link_cb(const struct device *dev)
378 {
379 	struct phy_adin2111_data *const data = dev->data;
380 	struct phy_link_state state;
381 
382 	if (data->cb == NULL) {
383 		return;
384 	}
385 
386 	data->cb(dev, &state, data->cb_data);
387 }
388 
update_link_state(const struct device * dev)389 static int update_link_state(const struct device *dev)
390 {
391 	struct phy_adin2111_data *const data = dev->data;
392 	const struct phy_adin2111_config *config = dev->config;
393 	struct phy_link_state old_state;
394 	uint16_t bmsr;
395 	int ret;
396 
397 	ret = phy_adin2111_c22_read(dev, MII_BMSR, &bmsr);
398 	if (ret < 0) {
399 		return ret;
400 	}
401 
402 	old_state = data->state;
403 	data->state.is_up = !!(bmsr & MII_BMSR_LINK_STATUS);
404 
405 	if (old_state.speed != data->state.speed || old_state.is_up != data->state.is_up) {
406 
407 		LOG_INF("PHY (%d) Link is %s", config->phy_addr, data->state.is_up ? "up" : "down");
408 
409 		if (data->state.is_up == false) {
410 			return 0;
411 		}
412 
413 		invoke_link_cb(dev);
414 
415 		LOG_INF("PHY (%d) Link speed %s Mb, %s duplex\n", config->phy_addr,
416 			(PHY_LINK_IS_SPEED_100M(data->state.speed) ? "100" : "10"),
417 			PHY_LINK_IS_FULL_DUPLEX(data->state.speed) ? "full" : "half");
418 	}
419 
420 	return 0;
421 }
422 
monitor_work_handler(struct k_work * work)423 static void monitor_work_handler(struct k_work *work)
424 {
425 	struct k_work_delayable *dwork = k_work_delayable_from_work(work);
426 	struct phy_adin2111_data *const data =
427 		CONTAINER_OF(dwork, struct phy_adin2111_data, monitor_work);
428 	const struct device *dev = data->dev;
429 	int rc;
430 
431 	k_sem_take(&data->sem, K_FOREVER);
432 
433 	rc = update_link_state(dev);
434 
435 	k_sem_give(&data->sem);
436 
437 	/* Submit delayed work */
438 	k_work_reschedule(&data->monitor_work, K_MSEC(CONFIG_PHY_MONITOR_PERIOD));
439 }
440 
phy_adin2111_init(const struct device * dev)441 static int phy_adin2111_init(const struct device *dev)
442 {
443 	const struct phy_adin2111_config *const cfg = dev->config;
444 	struct phy_adin2111_data *const data = dev->data;
445 	uint32_t phy_id;
446 	uint16_t val;
447 	bool tx_24v_supported = false;
448 	int ret;
449 
450 	data->dev = dev;
451 	data->state.is_up = false;
452 	data->state.speed = LINK_FULL_10BASE_T;
453 
454 	/*
455 	 * For adin1100 and further mii stuff,
456 	 * reset may not be performed from the mac layer, doing a clean reset here.
457 	 */
458 	if (cfg->mii) {
459 		ret = phy_adin2111_reset(dev);
460 		if (ret < 0) {
461 			return ret;
462 		}
463 	}
464 
465 	ret = phy_adin2111_await_phy(dev);
466 	if (ret < 0) {
467 		LOG_ERR("PHY %u didn't come out of reset, %d",
468 			cfg->phy_addr, ret);
469 		return -ENODEV;
470 	}
471 
472 	ret = phy_adin2111_id(dev, &phy_id);
473 	if (ret < 0) {
474 		LOG_ERR("Failed to read PHY %u ID, %d",
475 			cfg->phy_addr, ret);
476 		return -ENODEV;
477 	}
478 
479 	if (phy_id != ADIN2111_PHY_ID && phy_id != ADIN1110_PHY_ID && phy_id != ADIN1100_PHY_ID) {
480 		LOG_ERR("PHY %u unexpected PHY ID %X", cfg->phy_addr, phy_id);
481 		return -EINVAL;
482 	}
483 
484 	LOG_INF("PHY %u ID %X", cfg->phy_addr, phy_id);
485 
486 	/* enter software powerdown */
487 	ret = phy_adin2111_sft_pd(dev, true);
488 	if (ret < 0) {
489 		return ret;
490 	}
491 
492 	/* disable interrupts */
493 	ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1,
494 				     ADIN2111_PHY_CRSM_IRQ_MASK, 0U);
495 	if (ret < 0) {
496 		return ret;
497 	}
498 
499 	/* enable link status change irq */
500 	ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC2,
501 				     ADIN2111_PHY_SUBSYS_IRQ_MASK,
502 				     ADIN2111_PHY_SUBSYS_IRQ_STATUS_LINK_STAT_CHNG_LH);
503 	if (ret < 0) {
504 		return ret;
505 	}
506 
507 	/* clear PHY IRQ status before enabling ADIN IRQs */
508 	ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
509 				    ADIN2111_PHY_CRSM_IRQ_STATUS, &val);
510 	if (ret < 0) {
511 		return ret;
512 	}
513 
514 	if (val & ADIN2111_PHY_CRSM_IRQ_STATUS_FATAL_ERR) {
515 		LOG_ERR("PHY %u CRSM reports fatal system error", cfg->phy_addr);
516 		return -ENODEV;
517 	}
518 
519 	ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC2,
520 				    ADIN2111_PHY_SUBSYS_IRQ_STATUS, &val);
521 	if (ret < 0) {
522 		return ret;
523 	}
524 
525 	if (!cfg->led0_en || !cfg->led1_en) {
526 		ret = phy_adin2111_c45_read(dev, MDIO_MMD_VENDOR_SPECIFIC1,
527 					    ADIN2111_PHY_LED_CNTRL, &val);
528 		if (ret < 0) {
529 			return ret;
530 		}
531 		if (!cfg->led0_en) {
532 			val &= ~(ADIN2111_PHY_LED_CNTRL_LED0_EN);
533 		}
534 		if (!cfg->led1_en) {
535 			val &= ~(ADIN2111_PHY_LED_CNTRL_LED1_EN);
536 		}
537 		ret = phy_adin2111_c45_write(dev, MDIO_MMD_VENDOR_SPECIFIC1,
538 					     ADIN2111_PHY_LED_CNTRL, val);
539 		if (ret < 0) {
540 			return ret;
541 		}
542 	}
543 
544 	/* check 2.4V support */
545 	ret = phy_adin2111_c45_read(dev, MDIO_MMD_PMAPMD, MDIO_PMA_B10L_STAT, &val);
546 	if (ret < 0) {
547 		return ret;
548 	}
549 
550 	tx_24v_supported = !!(val & MDIO_PMA_B10L_STAT_2V4_ABLE);
551 
552 	LOG_INF("PHY %u 2.4V mode %s", cfg->phy_addr,
553 		tx_24v_supported ? "supported" : "not supported");
554 
555 	if (!cfg->tx_24v & tx_24v_supported) {
556 		LOG_ERR("PHY %u 2.4V mode supported, but not enabled",
557 			cfg->phy_addr);
558 	}
559 
560 	/* config 2.4V auto-negotiation */
561 	ret = phy_adin2111_c45_read(dev, MDIO_MMD_AN, MDIO_AN_T1_ADV_H, &val);
562 	if (ret < 0) {
563 		return ret;
564 	}
565 
566 	if (tx_24v_supported) {
567 		val |= MDIO_AN_T1_ADV_H_10L_TX_HI;
568 	} else {
569 		val &= ~MDIO_AN_T1_ADV_H_10L_TX_HI;
570 	}
571 
572 	if (cfg->tx_24v) {
573 		if (!tx_24v_supported) {
574 			LOG_ERR("PHY %u 2.4V mode enabled, but not supported",
575 				cfg->phy_addr);
576 			return -EINVAL;
577 		}
578 
579 		val |= MDIO_AN_T1_ADV_H_10L_TX_HI_REQ;
580 	} else {
581 		val &= ~MDIO_AN_T1_ADV_H_10L_TX_HI_REQ;
582 	}
583 
584 	ret = phy_adin2111_c45_write(dev, MDIO_MMD_AN, MDIO_AN_T1_ADV_H, val);
585 	if (ret < 0) {
586 		return ret;
587 	}
588 
589 	/* enable auto-negotiation */
590 	ret = phy_adin2111_c45_write(dev, MDIO_MMD_AN, MDIO_AN_T1_CTRL,
591 				     MDIO_AN_T1_CTRL_EN);
592 	if (ret < 0) {
593 		return ret;
594 	}
595 
596 	if (cfg->mii) {
597 		k_work_init_delayable(&data->monitor_work, monitor_work_handler);
598 		monitor_work_handler(&data->monitor_work.work);
599 	}
600 
601 	/**
602 	 * done, PHY is in software powerdown (SFT PD)
603 	 * exit software powerdown, PHY 1 has to exit before PHY 2
604 	 * correct PHY order is expected to be in DTS to guarantee that
605 	 */
606 	return phy_adin2111_sft_pd(dev, false);
607 }
608 
phy_adin2111_link_cb_set(const struct device * dev,phy_callback_t cb,void * user_data)609 static int phy_adin2111_link_cb_set(const struct device *dev, phy_callback_t cb,
610 				    void *user_data)
611 {
612 	struct phy_adin2111_data *const data = dev->data;
613 
614 	data->cb = cb;
615 	data->cb_data = user_data;
616 
617 	/* Invoke the callback to notify the caller of the current
618 	 * link status.
619 	 */
620 	invoke_link_cb(dev);
621 
622 	return 0;
623 }
624 
625 static DEVICE_API(ethphy, phy_adin2111_api) = {
626 	.get_link = phy_adin2111_get_link_state,
627 	.cfg_link = phy_adin2111_cfg_link,
628 	.link_cb_set = phy_adin2111_link_cb_set,
629 	.read = phy_adin2111_reg_read,
630 	.write = phy_adin2111_reg_write,
631 };
632 
633 #define ADIN2111_PHY_INITIALIZE(n, model)						\
634 	static const struct phy_adin2111_config phy_adin##model##_config_##n = {	\
635 		.mdio = DEVICE_DT_GET(DT_INST_BUS(n)),					\
636 		.phy_addr = DT_INST_REG_ADDR(n),					\
637 		.led0_en = DT_INST_PROP(n, led0_en),					\
638 		.led1_en = DT_INST_PROP(n, led1_en),					\
639 		.tx_24v = !(DT_INST_PROP(n, disable_tx_mode_24v)),			\
640 		IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(adi_adin1100_phy),			\
641 		(.mii = 1))								\
642 	};										\
643 	static struct phy_adin2111_data phy_adin##model##_data_##n = {			\
644 		.sem = Z_SEM_INITIALIZER(phy_adin##model##_data_##n.sem, 1, 1),		\
645 	};										\
646 	DEVICE_DT_INST_DEFINE(n, &phy_adin2111_init, NULL,				\
647 			      &phy_adin##model##_data_##n,				\
648 			      &phy_adin##model##_config_##n,				\
649 			      POST_KERNEL, CONFIG_PHY_INIT_PRIORITY,			\
650 			      &phy_adin2111_api);
651 
652 #define DT_DRV_COMPAT adi_adin2111_phy
653 DT_INST_FOREACH_STATUS_OKAY_VARGS(ADIN2111_PHY_INITIALIZE, 2111)
654 #undef DT_DRV_COMPAT
655 #define DT_DRV_COMPAT adi_adin1100_phy
656 DT_INST_FOREACH_STATUS_OKAY_VARGS(ADIN2111_PHY_INITIALIZE, 1100)
657 #undef DT_DRV_COMPAT
658