1 // SPDX-License-Identifier: GPL-2.0
2 /* Driver for the Texas Instruments DP83TG720 PHY
3 * Copyright (c) 2023 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>
4 */
5 #include <linux/bitfield.h>
6 #include <linux/ethtool_netlink.h>
7 #include <linux/jiffies.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/phy.h>
11 #include <linux/random.h>
12
13 #include "open_alliance_helpers.h"
14
15 /*
16 * DP83TG720S_POLL_ACTIVE_LINK - Polling interval in milliseconds when the link
17 * is active.
18 * DP83TG720S_POLL_NO_LINK_MIN - Minimum polling interval in milliseconds when
19 * the link is down.
20 * DP83TG720S_POLL_NO_LINK_MAX - Maximum polling interval in milliseconds when
21 * the link is down.
22 *
23 * These values are not documented or officially recommended by the vendor but
24 * were determined through empirical testing. They achieve a good balance in
25 * minimizing the number of reset retries while ensuring reliable link recovery
26 * within a reasonable timeframe.
27 */
28 #define DP83TG720S_POLL_ACTIVE_LINK 1000
29 #define DP83TG720S_POLL_NO_LINK_MIN 100
30 #define DP83TG720S_POLL_NO_LINK_MAX 1000
31
32 #define DP83TG720S_PHY_ID 0x2000a284
33
34 /* MDIO_MMD_VEND2 registers */
35 #define DP83TG720S_MII_REG_10 0x10
36 #define DP83TG720S_STS_MII_INT BIT(7)
37 #define DP83TG720S_LINK_STATUS BIT(0)
38
39 /* TDR Configuration Register (0x1E) */
40 #define DP83TG720S_TDR_CFG 0x1e
41 /* 1b = TDR start, 0b = No TDR */
42 #define DP83TG720S_TDR_START BIT(15)
43 /* 1b = TDR auto on link down, 0b = Manual TDR start */
44 #define DP83TG720S_CFG_TDR_AUTO_RUN BIT(14)
45 /* 1b = TDR done, 0b = TDR in progress */
46 #define DP83TG720S_TDR_DONE BIT(1)
47 /* 1b = TDR fail, 0b = TDR success */
48 #define DP83TG720S_TDR_FAIL BIT(0)
49
50 #define DP83TG720S_PHY_RESET 0x1f
51 #define DP83TG720S_HW_RESET BIT(15)
52
53 #define DP83TG720S_LPS_CFG3 0x18c
54 /* Power modes are documented as bit fields but used as values */
55 /* Power Mode 0 is Normal mode */
56 #define DP83TG720S_LPS_CFG3_PWR_MODE_0 BIT(0)
57
58 /* Open Aliance 1000BaseT1 compatible HDD.TDR Fault Status Register */
59 #define DP83TG720S_TDR_FAULT_STATUS 0x30f
60
61 /* Register 0x0301: TDR Configuration 2 */
62 #define DP83TG720S_TDR_CFG2 0x301
63
64 /* Register 0x0303: TDR Configuration 3 */
65 #define DP83TG720S_TDR_CFG3 0x303
66
67 /* Register 0x0304: TDR Configuration 4 */
68 #define DP83TG720S_TDR_CFG4 0x304
69
70 /* Register 0x0405: Unknown Register */
71 #define DP83TG720S_UNKNOWN_0405 0x405
72
73 #define DP83TG720S_LINK_QUAL_3 0x547
74 #define DP83TG720S_LINK_LOSS_CNT_MASK GENMASK(15, 10)
75
76 /* Register 0x0576: TDR Master Link Down Control */
77 #define DP83TG720S_TDR_MASTER_LINK_DOWN 0x576
78
79 #define DP83TG720S_RGMII_DELAY_CTRL 0x602
80 /* In RGMII mode, Enable or disable the internal delay for RXD */
81 #define DP83TG720S_RGMII_RX_CLK_SEL BIT(1)
82 /* In RGMII mode, Enable or disable the internal delay for TXD */
83 #define DP83TG720S_RGMII_TX_CLK_SEL BIT(0)
84
85 /*
86 * DP83TG720S_PKT_STAT_x registers correspond to similarly named registers
87 * in the datasheet (PKT_STAT_1 through PKT_STAT_6). These registers store
88 * 32-bit or 16-bit counters for TX and RX statistics and must be read in
89 * sequence to ensure the counters are cleared correctly.
90 *
91 * - DP83TG720S_PKT_STAT_1: Contains TX packet count bits [15:0].
92 * - DP83TG720S_PKT_STAT_2: Contains TX packet count bits [31:16].
93 * - DP83TG720S_PKT_STAT_3: Contains TX error packet count.
94 * - DP83TG720S_PKT_STAT_4: Contains RX packet count bits [15:0].
95 * - DP83TG720S_PKT_STAT_5: Contains RX packet count bits [31:16].
96 * - DP83TG720S_PKT_STAT_6: Contains RX error packet count.
97 *
98 * Keeping the register names as defined in the datasheet helps maintain
99 * clarity and alignment with the documentation.
100 */
101 #define DP83TG720S_PKT_STAT_1 0x639
102 #define DP83TG720S_PKT_STAT_2 0x63a
103 #define DP83TG720S_PKT_STAT_3 0x63b
104 #define DP83TG720S_PKT_STAT_4 0x63c
105 #define DP83TG720S_PKT_STAT_5 0x63d
106 #define DP83TG720S_PKT_STAT_6 0x63e
107
108 /* Register 0x083F: Unknown Register */
109 #define DP83TG720S_UNKNOWN_083F 0x83f
110
111 #define DP83TG720S_SQI_REG_1 0x871
112 #define DP83TG720S_SQI_OUT_WORST GENMASK(7, 5)
113 #define DP83TG720S_SQI_OUT GENMASK(3, 1)
114
115 #define DP83TG720_SQI_MAX 7
116
117 struct dp83tg720_stats {
118 u64 link_loss_cnt;
119 u64 tx_pkt_cnt;
120 u64 tx_err_pkt_cnt;
121 u64 rx_pkt_cnt;
122 u64 rx_err_pkt_cnt;
123 };
124
125 struct dp83tg720_priv {
126 struct dp83tg720_stats stats;
127 };
128
129 /**
130 * dp83tg720_update_stats - Update the PHY statistics for the DP83TD510 PHY.
131 * @phydev: Pointer to the phy_device structure.
132 *
133 * The function reads the PHY statistics registers and updates the statistics
134 * structure.
135 *
136 * Returns: 0 on success or a negative error code on failure.
137 */
dp83tg720_update_stats(struct phy_device * phydev)138 static int dp83tg720_update_stats(struct phy_device *phydev)
139 {
140 struct dp83tg720_priv *priv = phydev->priv;
141 u32 count;
142 int ret;
143
144 /* Read the link loss count */
145 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_LINK_QUAL_3);
146 if (ret < 0)
147 return ret;
148 /* link_loss_cnt */
149 count = FIELD_GET(DP83TG720S_LINK_LOSS_CNT_MASK, ret);
150 priv->stats.link_loss_cnt += count;
151
152 /* The DP83TG720S_PKT_STAT registers are divided into two groups:
153 * - Group 1 (TX stats): DP83TG720S_PKT_STAT_1 to DP83TG720S_PKT_STAT_3
154 * - Group 2 (RX stats): DP83TG720S_PKT_STAT_4 to DP83TG720S_PKT_STAT_6
155 *
156 * Registers in each group are cleared only after reading them in a
157 * plain sequence (e.g., 1, 2, 3 for Group 1 or 4, 5, 6 for Group 2).
158 * Any deviation from the sequence, such as reading 1, 2, 1, 2, 3, will
159 * prevent the group from being cleared. Additionally, the counters
160 * for a group are frozen as soon as the first register in that group
161 * is accessed.
162 */
163 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_1);
164 if (ret < 0)
165 return ret;
166 /* tx_pkt_cnt_15_0 */
167 count = ret;
168
169 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_2);
170 if (ret < 0)
171 return ret;
172 /* tx_pkt_cnt_31_16 */
173 count |= ret << 16;
174 priv->stats.tx_pkt_cnt += count;
175
176 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_3);
177 if (ret < 0)
178 return ret;
179 /* tx_err_pkt_cnt */
180 priv->stats.tx_err_pkt_cnt += ret;
181
182 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_4);
183 if (ret < 0)
184 return ret;
185 /* rx_pkt_cnt_15_0 */
186 count = ret;
187
188 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_5);
189 if (ret < 0)
190 return ret;
191 /* rx_pkt_cnt_31_16 */
192 count |= ret << 16;
193 priv->stats.rx_pkt_cnt += count;
194
195 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_PKT_STAT_6);
196 if (ret < 0)
197 return ret;
198 /* rx_err_pkt_cnt */
199 priv->stats.rx_err_pkt_cnt += ret;
200
201 return 0;
202 }
203
dp83tg720_get_link_stats(struct phy_device * phydev,struct ethtool_link_ext_stats * link_stats)204 static void dp83tg720_get_link_stats(struct phy_device *phydev,
205 struct ethtool_link_ext_stats *link_stats)
206 {
207 struct dp83tg720_priv *priv = phydev->priv;
208
209 link_stats->link_down_events = priv->stats.link_loss_cnt;
210 }
211
dp83tg720_get_phy_stats(struct phy_device * phydev,struct ethtool_eth_phy_stats * eth_stats,struct ethtool_phy_stats * stats)212 static void dp83tg720_get_phy_stats(struct phy_device *phydev,
213 struct ethtool_eth_phy_stats *eth_stats,
214 struct ethtool_phy_stats *stats)
215 {
216 struct dp83tg720_priv *priv = phydev->priv;
217
218 stats->tx_packets = priv->stats.tx_pkt_cnt;
219 stats->tx_errors = priv->stats.tx_err_pkt_cnt;
220 stats->rx_packets = priv->stats.rx_pkt_cnt;
221 stats->rx_errors = priv->stats.rx_err_pkt_cnt;
222 }
223
224 /**
225 * dp83tg720_cable_test_start - Start the cable test for the DP83TG720 PHY.
226 * @phydev: Pointer to the phy_device structure.
227 *
228 * This sequence is based on the documented procedure for the DP83TG720 PHY.
229 *
230 * Returns: 0 on success, a negative error code on failure.
231 */
dp83tg720_cable_test_start(struct phy_device * phydev)232 static int dp83tg720_cable_test_start(struct phy_device *phydev)
233 {
234 int ret;
235
236 /* Initialize the PHY to run the TDR test as described in the
237 * "DP83TG720S-Q1: Configuring for Open Alliance Specification
238 * Compliance (Rev. B)" application note.
239 * Most of the registers are not documented. Some of register names
240 * are guessed by comparing the register offsets with the DP83TD510E.
241 */
242
243 /* Force master link down */
244 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
245 DP83TG720S_TDR_MASTER_LINK_DOWN, 0x0400);
246 if (ret)
247 return ret;
248
249 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG2,
250 0xa008);
251 if (ret)
252 return ret;
253
254 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG3,
255 0x0928);
256 if (ret)
257 return ret;
258
259 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG4,
260 0x0004);
261 if (ret)
262 return ret;
263
264 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_UNKNOWN_0405,
265 0x6400);
266 if (ret)
267 return ret;
268
269 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_UNKNOWN_083F,
270 0x3003);
271 if (ret)
272 return ret;
273
274 /* Start the TDR */
275 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG,
276 DP83TG720S_TDR_START);
277 if (ret)
278 return ret;
279
280 return 0;
281 }
282
283 /**
284 * dp83tg720_cable_test_get_status - Get the status of the cable test for the
285 * DP83TG720 PHY.
286 * @phydev: Pointer to the phy_device structure.
287 * @finished: Pointer to a boolean that indicates whether the test is finished.
288 *
289 * The function sets the @finished flag to true if the test is complete.
290 *
291 * Returns: 0 on success or a negative error code on failure.
292 */
dp83tg720_cable_test_get_status(struct phy_device * phydev,bool * finished)293 static int dp83tg720_cable_test_get_status(struct phy_device *phydev,
294 bool *finished)
295 {
296 int ret, stat;
297
298 *finished = false;
299
300 /* Read the TDR status */
301 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_TDR_CFG);
302 if (ret < 0)
303 return ret;
304
305 /* Check if the TDR test is done */
306 if (!(ret & DP83TG720S_TDR_DONE))
307 return 0;
308
309 /* Check for TDR test failure */
310 if (!(ret & DP83TG720S_TDR_FAIL)) {
311 int location;
312
313 /* Read fault status */
314 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,
315 DP83TG720S_TDR_FAULT_STATUS);
316 if (ret < 0)
317 return ret;
318
319 /* Get fault type */
320 stat = oa_1000bt1_get_ethtool_cable_result_code(ret);
321
322 /* Determine fault location */
323 location = oa_1000bt1_get_tdr_distance(ret);
324 if (location > 0)
325 ethnl_cable_test_fault_length(phydev,
326 ETHTOOL_A_CABLE_PAIR_A,
327 location);
328 } else {
329 /* Active link partner or other issues */
330 stat = ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
331 }
332
333 *finished = true;
334
335 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, stat);
336
337 /* save the current stats before resetting the PHY */
338 ret = dp83tg720_update_stats(phydev);
339 if (ret)
340 return ret;
341
342 return phy_init_hw(phydev);
343 }
344
dp83tg720_config_aneg(struct phy_device * phydev)345 static int dp83tg720_config_aneg(struct phy_device *phydev)
346 {
347 int ret;
348
349 /* Autoneg is not supported and this PHY supports only one speed.
350 * We need to care only about master/slave configuration if it was
351 * changed by user.
352 */
353 ret = genphy_c45_pma_baset1_setup_master_slave(phydev);
354 if (ret)
355 return ret;
356
357 /* Re-read role configuration to make changes visible even if
358 * the link is in administrative down state.
359 */
360 return genphy_c45_pma_baset1_read_master_slave(phydev);
361 }
362
dp83tg720_read_status(struct phy_device * phydev)363 static int dp83tg720_read_status(struct phy_device *phydev)
364 {
365 u16 phy_sts;
366 int ret;
367
368 phydev->pause = 0;
369 phydev->asym_pause = 0;
370
371 /* Most of Clause 45 registers are not present, so we can't use
372 * genphy_c45_read_status() here.
373 */
374 phy_sts = phy_read(phydev, DP83TG720S_MII_REG_10);
375 phydev->link = !!(phy_sts & DP83TG720S_LINK_STATUS);
376 if (!phydev->link) {
377 /* save the current stats before resetting the PHY */
378 ret = dp83tg720_update_stats(phydev);
379 if (ret)
380 return ret;
381
382 /* According to the "DP83TC81x, DP83TG72x Software
383 * Implementation Guide", the PHY needs to be reset after a
384 * link loss or if no link is created after at least 100ms.
385 *
386 * Currently we are polling with the PHY_STATE_TIME (1000ms)
387 * interval, which is still enough for not automotive use cases.
388 */
389 ret = phy_init_hw(phydev);
390 if (ret)
391 return ret;
392
393 /* Sleep 600ms for PHY stabilization post-reset.
394 * Empirically chosen value (not documented).
395 * Helps reduce reset bounces with link partners having similar
396 * issues.
397 */
398 msleep(600);
399
400 /* After HW reset we need to restore master/slave configuration.
401 * genphy_c45_pma_baset1_read_master_slave() call will be done
402 * by the dp83tg720_config_aneg() function.
403 */
404 ret = dp83tg720_config_aneg(phydev);
405 if (ret)
406 return ret;
407
408 phydev->speed = SPEED_UNKNOWN;
409 phydev->duplex = DUPLEX_UNKNOWN;
410 } else {
411 /* PMA/PMD control 1 register (Register 1.0) is present, but it
412 * doesn't contain the link speed information.
413 * So genphy_c45_read_pma() can't be used here.
414 */
415 ret = genphy_c45_pma_baset1_read_master_slave(phydev);
416 if (ret)
417 return ret;
418
419 phydev->duplex = DUPLEX_FULL;
420 phydev->speed = SPEED_1000;
421 }
422
423 return 0;
424 }
425
dp83tg720_get_sqi(struct phy_device * phydev)426 static int dp83tg720_get_sqi(struct phy_device *phydev)
427 {
428 int ret;
429
430 if (!phydev->link)
431 return 0;
432
433 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_SQI_REG_1);
434 if (ret < 0)
435 return ret;
436
437 return FIELD_GET(DP83TG720S_SQI_OUT, ret);
438 }
439
dp83tg720_get_sqi_max(struct phy_device * phydev)440 static int dp83tg720_get_sqi_max(struct phy_device *phydev)
441 {
442 return DP83TG720_SQI_MAX;
443 }
444
dp83tg720_config_rgmii_delay(struct phy_device * phydev)445 static int dp83tg720_config_rgmii_delay(struct phy_device *phydev)
446 {
447 u16 rgmii_delay_mask;
448 u16 rgmii_delay = 0;
449
450 switch (phydev->interface) {
451 case PHY_INTERFACE_MODE_RGMII:
452 rgmii_delay = 0;
453 break;
454 case PHY_INTERFACE_MODE_RGMII_ID:
455 rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL |
456 DP83TG720S_RGMII_TX_CLK_SEL;
457 break;
458 case PHY_INTERFACE_MODE_RGMII_RXID:
459 rgmii_delay = DP83TG720S_RGMII_RX_CLK_SEL;
460 break;
461 case PHY_INTERFACE_MODE_RGMII_TXID:
462 rgmii_delay = DP83TG720S_RGMII_TX_CLK_SEL;
463 break;
464 default:
465 return 0;
466 }
467
468 rgmii_delay_mask = DP83TG720S_RGMII_RX_CLK_SEL |
469 DP83TG720S_RGMII_TX_CLK_SEL;
470
471 return phy_modify_mmd(phydev, MDIO_MMD_VEND2,
472 DP83TG720S_RGMII_DELAY_CTRL, rgmii_delay_mask,
473 rgmii_delay);
474 }
475
dp83tg720_config_init(struct phy_device * phydev)476 static int dp83tg720_config_init(struct phy_device *phydev)
477 {
478 int ret;
479
480 /* Software Restart is not enough to recover from a link failure.
481 * Using Hardware Reset instead.
482 */
483 ret = phy_write(phydev, DP83TG720S_PHY_RESET, DP83TG720S_HW_RESET);
484 if (ret)
485 return ret;
486
487 /* Wait until MDC can be used again.
488 * The wait value of one 1ms is documented in "DP83TG720S-Q1 1000BASE-T1
489 * Automotive Ethernet PHY with SGMII and RGMII" datasheet.
490 */
491 usleep_range(1000, 2000);
492
493 if (phy_interface_is_rgmii(phydev)) {
494 ret = dp83tg720_config_rgmii_delay(phydev);
495 if (ret)
496 return ret;
497 }
498
499 /* In case the PHY is bootstrapped in managed mode, we need to
500 * wake it.
501 */
502 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TG720S_LPS_CFG3,
503 DP83TG720S_LPS_CFG3_PWR_MODE_0);
504 if (ret)
505 return ret;
506
507 /* Make role configuration visible for ethtool on init and after
508 * rest.
509 */
510 return genphy_c45_pma_baset1_read_master_slave(phydev);
511 }
512
dp83tg720_probe(struct phy_device * phydev)513 static int dp83tg720_probe(struct phy_device *phydev)
514 {
515 struct device *dev = &phydev->mdio.dev;
516 struct dp83tg720_priv *priv;
517
518 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
519 if (!priv)
520 return -ENOMEM;
521
522 phydev->priv = priv;
523
524 return 0;
525 }
526
527 /**
528 * dp83tg720_get_next_update_time - Determine the next update time for PHY
529 * state
530 * @phydev: Pointer to the phy_device structure
531 *
532 * This function addresses a limitation of the DP83TG720 PHY, which cannot
533 * reliably detect or report a stable link state. To recover from such
534 * scenarios, the PHY must be periodically reset when the link is down. However,
535 * if the link partner also runs Linux with the same driver, synchronized reset
536 * intervals can lead to a deadlock where the link never establishes due to
537 * simultaneous resets on both sides.
538 *
539 * To avoid this, the function implements randomized polling intervals when the
540 * link is down. It ensures that reset intervals are desynchronized by
541 * introducing a random delay between a configured minimum and maximum range.
542 * When the link is up, a fixed polling interval is used to minimize overhead.
543 *
544 * This mechanism guarantees that the link will reestablish within 10 seconds
545 * in the worst-case scenario.
546 *
547 * Return: Time (in jiffies) until the next update event for the PHY state
548 * machine.
549 */
dp83tg720_get_next_update_time(struct phy_device * phydev)550 static unsigned int dp83tg720_get_next_update_time(struct phy_device *phydev)
551 {
552 unsigned int next_time_jiffies;
553
554 if (phydev->link) {
555 /* When the link is up, use a fixed 1000ms interval
556 * (in jiffies)
557 */
558 next_time_jiffies =
559 msecs_to_jiffies(DP83TG720S_POLL_ACTIVE_LINK);
560 } else {
561 unsigned int min_jiffies, max_jiffies, rand_jiffies;
562
563 /* When the link is down, randomize interval between min/max
564 * (in jiffies)
565 */
566 min_jiffies = msecs_to_jiffies(DP83TG720S_POLL_NO_LINK_MIN);
567 max_jiffies = msecs_to_jiffies(DP83TG720S_POLL_NO_LINK_MAX);
568
569 rand_jiffies = min_jiffies +
570 get_random_u32_below(max_jiffies - min_jiffies + 1);
571 next_time_jiffies = rand_jiffies;
572 }
573
574 /* Ensure the polling time is at least one jiffy */
575 return max(next_time_jiffies, 1U);
576 }
577
578 static struct phy_driver dp83tg720_driver[] = {
579 {
580 PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID),
581 .name = "TI DP83TG720S",
582
583 .flags = PHY_POLL_CABLE_TEST,
584 .probe = dp83tg720_probe,
585 .config_aneg = dp83tg720_config_aneg,
586 .read_status = dp83tg720_read_status,
587 .get_features = genphy_c45_pma_read_ext_abilities,
588 .config_init = dp83tg720_config_init,
589 .get_sqi = dp83tg720_get_sqi,
590 .get_sqi_max = dp83tg720_get_sqi_max,
591 .cable_test_start = dp83tg720_cable_test_start,
592 .cable_test_get_status = dp83tg720_cable_test_get_status,
593 .get_link_stats = dp83tg720_get_link_stats,
594 .get_phy_stats = dp83tg720_get_phy_stats,
595 .update_stats = dp83tg720_update_stats,
596 .get_next_update_time = dp83tg720_get_next_update_time,
597
598 .suspend = genphy_suspend,
599 .resume = genphy_resume,
600 } };
601 module_phy_driver(dp83tg720_driver);
602
603 static const struct mdio_device_id __maybe_unused dp83tg720_tbl[] = {
604 { PHY_ID_MATCH_MODEL(DP83TG720S_PHY_ID) },
605 { }
606 };
607 MODULE_DEVICE_TABLE(mdio, dp83tg720_tbl);
608
609 MODULE_DESCRIPTION("Texas Instruments DP83TG720S PHY driver");
610 MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");
611 MODULE_LICENSE("GPL");
612