617 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Driver for the Texas Instruments DP83TD510 PHY3 * Copyright (c) 2022 Pengutronix, Oleksij Rempel <kernel@pengutronix.de>4 */5 6#include <linux/bitfield.h>7#include <linux/ethtool_netlink.h>8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/phy.h>11 12#define DP83TD510E_PHY_ID 0x2000018113 14/* MDIO_MMD_VEND2 registers */15#define DP83TD510E_PHY_STS 0x1016/* Bit 7 - mii_interrupt, active high. Clears on read.17 * Note: Clearing does not necessarily deactivate IRQ pin if interrupts pending.18 * This differs from the DP83TD510E datasheet (2020) which states this bit19 * clears on write 0.20 */21#define DP83TD510E_STS_MII_INT BIT(7)22#define DP83TD510E_LINK_STATUS BIT(0)23 24#define DP83TD510E_GEN_CFG 0x1125#define DP83TD510E_GENCFG_INT_POLARITY BIT(3)26#define DP83TD510E_GENCFG_INT_EN BIT(1)27#define DP83TD510E_GENCFG_INT_OE BIT(0)28 29#define DP83TD510E_INTERRUPT_REG_1 0x1230#define DP83TD510E_INT1_LINK BIT(13)31#define DP83TD510E_INT1_LINK_EN BIT(5)32 33#define DP83TD510E_CTRL 0x1f34#define DP83TD510E_CTRL_HW_RESET BIT(15)35#define DP83TD510E_CTRL_SW_RESET BIT(14)36 37#define DP83TD510E_AN_STAT_1 0x60c38#define DP83TD510E_MASTER_SLAVE_RESOL_FAIL BIT(15)39 40#define DP83TD510E_MSE_DETECT 0xa8541 42#define DP83TD510_SQI_MAX 743 44/* Register values are converted to SNR(dB) as suggested by45 * "Application Report - DP83TD510E Cable Diagnostics Toolkit":46 * SNR(dB) = -10 * log10 (VAL/2^17) - 1.76 dB.47 * SQI ranges are implemented according to "OPEN ALLIANCE - Advanced diagnostic48 * features for 100BASE-T1 automotive Ethernet PHYs"49 */50static const u16 dp83td510_mse_sqi_map[] = {51 0x0569, /* < 18dB */52 0x044c, /* 18dB =< SNR < 19dB */53 0x0369, /* 19dB =< SNR < 20dB */54 0x02b6, /* 20dB =< SNR < 21dB */55 0x0227, /* 21dB =< SNR < 22dB */56 0x01b6, /* 22dB =< SNR < 23dB */57 0x015b, /* 23dB =< SNR < 24dB */58 0x0000 /* 24dB =< SNR */59};60 61struct dp83td510_priv {62 bool alcd_test_active;63};64 65/* Time Domain Reflectometry (TDR) Functionality of DP83TD510 PHY66 *67 * I assume that this PHY is using a variation of Spread Spectrum Time Domain68 * Reflectometry (SSTDR) rather than the commonly used TDR found in many PHYs.69 * Here are the following observations which likely confirm this:70 * - The DP83TD510 PHY transmits a modulated signal of configurable length71 * (default 16000 µs) instead of a single pulse pattern, which is typical72 * for traditional TDR.73 * - The pulse observed on the wire, triggered by the HW RESET register, is not74 * part of the cable testing process.75 *76 * I assume that SSTDR seems to be a logical choice for the 10BaseT1L77 * environment due to improved noise resistance, making it suitable for78 * environments with significant electrical noise, such as long 10BaseT1L cable79 * runs.80 *81 * Configuration Variables:82 * The SSTDR variation used in this PHY involves more configuration variables83 * that can dramatically affect the functionality and precision of cable84 * testing. Since most of these configuration options are either not well85 * documented or documented with minimal details, the following sections86 * describe my understanding and observations of these variables and their87 * impact on TDR functionality.88 *89 * Timeline:90 * ,<--cfg_pre_silence_time91 * | ,<-SSTDR Modulated Transmission92 * | | ,<--cfg_post_silence_time93 * | | | ,<--Force Link Mode94 * |<--'-->|<-------'------->|<--'-->|<--------'------->|95 *96 * - cfg_pre_silence_time: Optional silence time before TDR transmission starts.97 * - SSTDR Modulated Transmission: Transmission duration configured by98 * cfg_tdr_tx_duration and amplitude configured by cfg_tdr_tx_type.99 * - cfg_post_silence_time: Silence time after TDR transmission.100 * - Force Link Mode: If nothing is configured after cfg_post_silence_time,101 * the PHY continues in force link mode without autonegotiation.102 */103 104#define DP83TD510E_TDR_CFG 0x1e105#define DP83TD510E_TDR_START BIT(15)106#define DP83TD510E_TDR_DONE BIT(1)107#define DP83TD510E_TDR_FAIL BIT(0)108 109#define DP83TD510E_TDR_CFG1 0x300110/* cfg_tdr_tx_type: Transmit voltage level for TDR.111 * 0 = 1V, 1 = 2.4V112 * Note: Using different voltage levels may not work113 * in all configuration variations. For example, setting114 * 2.4V may give different cable length measurements.115 * Other settings may be needed to make it work properly.116 */117#define DP83TD510E_TDR_TX_TYPE BIT(12)118#define DP83TD510E_TDR_TX_TYPE_1V 0119#define DP83TD510E_TDR_TX_TYPE_2_4V 1120/* cfg_post_silence_time: Time after the TDR sequence. Since we force master mode121 * for the TDR will proceed with forced link state after this time. For Linux122 * it is better to set max value to avoid false link state detection.123 */124#define DP83TD510E_TDR_CFG1_POST_SILENCE_TIME GENMASK(3, 2)125#define DP83TD510E_TDR_CFG1_POST_SILENCE_TIME_0MS 0126#define DP83TD510E_TDR_CFG1_POST_SILENCE_TIME_10MS 1127#define DP83TD510E_TDR_CFG1_POST_SILENCE_TIME_100MS 2128#define DP83TD510E_TDR_CFG1_POST_SILENCE_TIME_1000MS 3129/* cfg_pre_silence_time: Time before the TDR sequence. It should be enough to130 * settle down all pulses and reflections. Since for 10BASE-T1L we have131 * maximum 2000m cable length, we can set it to 1ms.132 */133#define DP83TD510E_TDR_CFG1_PRE_SILENCE_TIME GENMASK(1, 0)134#define DP83TD510E_TDR_CFG1_PRE_SILENCE_TIME_0MS 0135#define DP83TD510E_TDR_CFG1_PRE_SILENCE_TIME_10MS 1136#define DP83TD510E_TDR_CFG1_PRE_SILENCE_TIME_100MS 2137#define DP83TD510E_TDR_CFG1_PRE_SILENCE_TIME_1000MS 3138 139#define DP83TD510E_TDR_CFG2 0x301140#define DP83TD510E_TDR_END_TAP_INDEX_1 GENMASK(14, 8)141#define DP83TD510E_TDR_END_TAP_INDEX_1_DEF 36142#define DP83TD510E_TDR_START_TAP_INDEX_1 GENMASK(6, 0)143#define DP83TD510E_TDR_START_TAP_INDEX_1_DEF 4144 145#define DP83TD510E_TDR_CFG3 0x302146/* cfg_tdr_tx_duration: Duration of the TDR transmission in microseconds.147 * This value sets the duration of the modulated signal used for TDR148 * measurements.149 * - Default: 16000 µs150 * - Observation: A minimum duration of 6000 µs is recommended to ensure151 * accurate detection of cable faults. Durations shorter than 6000 µs may152 * result in incomplete data, especially for shorter cables (e.g., 20 meters),153 * leading to false "OK" results. Longer durations (e.g., 6000 µs or more)154 * provide better accuracy, particularly for detecting open circuits.155 */156#define DP83TD510E_TDR_TX_DURATION_US GENMASK(15, 0)157#define DP83TD510E_TDR_TX_DURATION_US_DEF 16000158 159#define DP83TD510E_TDR_FAULT_CFG1 0x303160#define DP83TD510E_TDR_FLT_LOC_OFFSET_1 GENMASK(14, 8)161#define DP83TD510E_TDR_FLT_LOC_OFFSET_1_DEF 4162#define DP83TD510E_TDR_FLT_INIT_1 GENMASK(7, 0)163#define DP83TD510E_TDR_FLT_INIT_1_DEF 62164 165#define DP83TD510E_TDR_FAULT_STAT 0x30c166#define DP83TD510E_TDR_PEAK_DETECT BIT(11)167#define DP83TD510E_TDR_PEAK_SIGN BIT(10)168#define DP83TD510E_TDR_PEAK_LOCATION GENMASK(9, 0)169 170/* Not documented registers and values but recommended according to171 * "DP83TD510E Cable Diagnostics Toolkit revC"172 */173#define DP83TD510E_UNKN_030E 0x30e174#define DP83TD510E_030E_VAL 0x2520175 176#define DP83TD510E_ALCD_STAT 0xa9f177#define DP83TD510E_ALCD_COMPLETE BIT(15)178#define DP83TD510E_ALCD_CABLE_LENGTH GENMASK(10, 0)179 180static int dp83td510_config_intr(struct phy_device *phydev)181{182 int ret;183 184 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {185 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,186 DP83TD510E_INTERRUPT_REG_1,187 DP83TD510E_INT1_LINK_EN);188 if (ret)189 return ret;190 191 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,192 DP83TD510E_GEN_CFG,193 DP83TD510E_GENCFG_INT_POLARITY |194 DP83TD510E_GENCFG_INT_EN |195 DP83TD510E_GENCFG_INT_OE);196 } else {197 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2,198 DP83TD510E_INTERRUPT_REG_1, 0x0);199 if (ret)200 return ret;201 202 ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,203 DP83TD510E_GEN_CFG,204 DP83TD510E_GENCFG_INT_EN);205 if (ret)206 return ret;207 }208 209 return ret;210}211 212static irqreturn_t dp83td510_handle_interrupt(struct phy_device *phydev)213{214 int ret;215 216 /* Read the current enabled interrupts */217 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_INTERRUPT_REG_1);218 if (ret < 0) {219 phy_error(phydev);220 return IRQ_NONE;221 } else if (!(ret & DP83TD510E_INT1_LINK_EN) ||222 !(ret & DP83TD510E_INT1_LINK)) {223 return IRQ_NONE;224 }225 226 phy_trigger_machine(phydev);227 228 return IRQ_HANDLED;229}230 231static int dp83td510_read_status(struct phy_device *phydev)232{233 u16 phy_sts;234 int ret;235 236 phydev->speed = SPEED_UNKNOWN;237 phydev->duplex = DUPLEX_UNKNOWN;238 phydev->pause = 0;239 phydev->asym_pause = 0;240 linkmode_zero(phydev->lp_advertising);241 242 phy_sts = phy_read(phydev, DP83TD510E_PHY_STS);243 244 phydev->link = !!(phy_sts & DP83TD510E_LINK_STATUS);245 if (phydev->link) {246 /* This PHY supports only one link mode: 10BaseT1L_Full */247 phydev->duplex = DUPLEX_FULL;248 phydev->speed = SPEED_10;249 250 if (phydev->autoneg == AUTONEG_ENABLE) {251 ret = genphy_c45_read_lpa(phydev);252 if (ret)253 return ret;254 255 phy_resolve_aneg_linkmode(phydev);256 }257 }258 259 if (phydev->autoneg == AUTONEG_ENABLE) {260 ret = genphy_c45_baset1_read_status(phydev);261 if (ret < 0)262 return ret;263 264 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,265 DP83TD510E_AN_STAT_1);266 if (ret < 0)267 return ret;268 269 if (ret & DP83TD510E_MASTER_SLAVE_RESOL_FAIL)270 phydev->master_slave_state = MASTER_SLAVE_STATE_ERR;271 } else {272 return genphy_c45_pma_baset1_read_master_slave(phydev);273 }274 275 return 0;276}277 278static int dp83td510_config_aneg(struct phy_device *phydev)279{280 bool changed = false;281 int ret;282 283 ret = genphy_c45_pma_baset1_setup_master_slave(phydev);284 if (ret < 0)285 return ret;286 287 if (phydev->autoneg == AUTONEG_DISABLE)288 return genphy_c45_an_disable_aneg(phydev);289 290 ret = genphy_c45_an_config_aneg(phydev);291 if (ret < 0)292 return ret;293 if (ret > 0)294 changed = true;295 296 return genphy_c45_check_and_restart_aneg(phydev, changed);297}298 299static int dp83td510_get_sqi(struct phy_device *phydev)300{301 int sqi, ret;302 u16 mse_val;303 304 if (!phydev->link)305 return 0;306 307 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_MSE_DETECT);308 if (ret < 0)309 return ret;310 311 mse_val = 0xFFFF & ret;312 for (sqi = 0; sqi < ARRAY_SIZE(dp83td510_mse_sqi_map); sqi++) {313 if (mse_val >= dp83td510_mse_sqi_map[sqi])314 return sqi;315 }316 317 return -EINVAL;318}319 320static int dp83td510_get_sqi_max(struct phy_device *phydev)321{322 return DP83TD510_SQI_MAX;323}324 325/**326 * dp83td510_cable_test_start - Start the cable test for the DP83TD510 PHY.327 * @phydev: Pointer to the phy_device structure.328 *329 * This sequence is implemented according to the "Application Note DP83TD510E330 * Cable Diagnostics Toolkit revC".331 *332 * Returns: 0 on success, a negative error code on failure.333 */334static int dp83td510_cable_test_start(struct phy_device *phydev)335{336 struct dp83td510_priv *priv = phydev->priv;337 int ret;338 339 /* If link partner is active, we won't be able to use TDR, since340 * we can't force link partner to be silent. The autonegotiation341 * pulses will be too frequent and the TDR sequence will be342 * too long. So, TDR will always fail. Since the link is established343 * we already know that the cable is working, so we can get some344 * extra information line the cable length using ALCD.345 */346 if (phydev->link) {347 priv->alcd_test_active = true;348 return 0;349 }350 351 priv->alcd_test_active = false;352 353 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_CTRL,354 DP83TD510E_CTRL_HW_RESET);355 if (ret)356 return ret;357 358 ret = genphy_c45_an_disable_aneg(phydev);359 if (ret)360 return ret;361 362 /* Force master mode */363 ret = phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1_CTRL,364 MDIO_PMA_PMD_BT1_CTRL_CFG_MST);365 if (ret)366 return ret;367 368 /* There is no official recommendation for this register, but it is369 * better to use 1V for TDR since other values seems to be optimized370 * for this amplitude. Except of amplitude, it is better to configure371 * pre TDR silence time to 10ms to avoid false reflections (value 0372 * seems to be too short, otherwise we need to implement own silence373 * time). Also, post TDR silence time should be set to 1000ms to avoid374 * false link state detection, it fits to the polling time of the375 * PHY framework. The idea is to wait until376 * dp83td510_cable_test_get_status() will be called and reconfigure377 * the PHY to the default state within the post silence time window.378 */379 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_TDR_CFG1,380 DP83TD510E_TDR_TX_TYPE |381 DP83TD510E_TDR_CFG1_POST_SILENCE_TIME |382 DP83TD510E_TDR_CFG1_PRE_SILENCE_TIME,383 DP83TD510E_TDR_TX_TYPE_1V |384 DP83TD510E_TDR_CFG1_PRE_SILENCE_TIME_10MS |385 DP83TD510E_TDR_CFG1_POST_SILENCE_TIME_1000MS);386 if (ret)387 return ret;388 389 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_TDR_CFG2,390 FIELD_PREP(DP83TD510E_TDR_END_TAP_INDEX_1,391 DP83TD510E_TDR_END_TAP_INDEX_1_DEF) |392 FIELD_PREP(DP83TD510E_TDR_START_TAP_INDEX_1,393 DP83TD510E_TDR_START_TAP_INDEX_1_DEF));394 if (ret)395 return ret;396 397 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_TDR_FAULT_CFG1,398 FIELD_PREP(DP83TD510E_TDR_FLT_LOC_OFFSET_1,399 DP83TD510E_TDR_FLT_LOC_OFFSET_1_DEF) |400 FIELD_PREP(DP83TD510E_TDR_FLT_INIT_1,401 DP83TD510E_TDR_FLT_INIT_1_DEF));402 if (ret)403 return ret;404 405 /* Undocumented register, from the "Application Note DP83TD510E Cable406 * Diagnostics Toolkit revC".407 */408 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_UNKN_030E,409 DP83TD510E_030E_VAL);410 if (ret)411 return ret;412 413 ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_TDR_CFG3,414 DP83TD510E_TDR_TX_DURATION_US_DEF);415 if (ret)416 return ret;417 418 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_CTRL,419 DP83TD510E_CTRL_SW_RESET);420 if (ret)421 return ret;422 423 return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_TDR_CFG,424 DP83TD510E_TDR_START);425}426 427/**428 * dp83td510_cable_test_get_tdr_status - Get the status of the TDR test for the429 * DP83TD510 PHY.430 * @phydev: Pointer to the phy_device structure.431 * @finished: Pointer to a boolean that indicates whether the test is finished.432 *433 * The function sets the @finished flag to true if the test is complete.434 *435 * Returns: 0 on success or a negative error code on failure.436 */437static int dp83td510_cable_test_get_tdr_status(struct phy_device *phydev,438 bool *finished)439{440 int ret, stat;441 442 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_TDR_CFG);443 if (ret < 0)444 return ret;445 446 if (!(ret & DP83TD510E_TDR_DONE))447 return 0;448 449 if (!(ret & DP83TD510E_TDR_FAIL)) {450 int location;451 452 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2,453 DP83TD510E_TDR_FAULT_STAT);454 if (ret < 0)455 return ret;456 457 if (ret & DP83TD510E_TDR_PEAK_DETECT) {458 if (ret & DP83TD510E_TDR_PEAK_SIGN)459 stat = ETHTOOL_A_CABLE_RESULT_CODE_OPEN;460 else461 stat = ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;462 463 location = FIELD_GET(DP83TD510E_TDR_PEAK_LOCATION,464 ret) * 100;465 ethnl_cable_test_fault_length(phydev,466 ETHTOOL_A_CABLE_PAIR_A,467 location);468 } else {469 stat = ETHTOOL_A_CABLE_RESULT_CODE_OK;470 }471 } else {472 /* Most probably we have active link partner */473 stat = ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;474 }475 476 *finished = true;477 478 ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A, stat);479 480 return phy_init_hw(phydev);481}482 483/**484 * dp83td510_cable_test_get_alcd_status - Get the status of the ALCD test for the485 * DP83TD510 PHY.486 * @phydev: Pointer to the phy_device structure.487 * @finished: Pointer to a boolean that indicates whether the test is finished.488 *489 * The function sets the @finished flag to true if the test is complete.490 * The function reads the cable length and reports it to the user.491 *492 * Returns: 0 on success or a negative error code on failure.493 */494static int dp83td510_cable_test_get_alcd_status(struct phy_device *phydev,495 bool *finished)496{497 unsigned int location;498 int ret, phy_sts;499 500 phy_sts = phy_read(phydev, DP83TD510E_PHY_STS);501 502 if (!(phy_sts & DP83TD510E_LINK_STATUS)) {503 /* If the link is down, we can't do any thing usable now */504 ethnl_cable_test_result_with_src(phydev, ETHTOOL_A_CABLE_PAIR_A,505 ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC,506 ETHTOOL_A_CABLE_INF_SRC_ALCD);507 *finished = true;508 return 0;509 }510 511 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_ALCD_STAT);512 if (ret < 0)513 return ret;514 515 if (!(ret & DP83TD510E_ALCD_COMPLETE))516 return 0;517 518 location = FIELD_GET(DP83TD510E_ALCD_CABLE_LENGTH, ret) * 100;519 520 ethnl_cable_test_fault_length_with_src(phydev, ETHTOOL_A_CABLE_PAIR_A,521 location,522 ETHTOOL_A_CABLE_INF_SRC_ALCD);523 524 ethnl_cable_test_result_with_src(phydev, ETHTOOL_A_CABLE_PAIR_A,525 ETHTOOL_A_CABLE_RESULT_CODE_OK,526 ETHTOOL_A_CABLE_INF_SRC_ALCD);527 *finished = true;528 529 return 0;530}531 532/**533 * dp83td510_cable_test_get_status - Get the status of the cable test for the534 * DP83TD510 PHY.535 * @phydev: Pointer to the phy_device structure.536 * @finished: Pointer to a boolean that indicates whether the test is finished.537 *538 * The function sets the @finished flag to true if the test is complete.539 *540 * Returns: 0 on success or a negative error code on failure.541 */542static int dp83td510_cable_test_get_status(struct phy_device *phydev,543 bool *finished)544{545 struct dp83td510_priv *priv = phydev->priv;546 *finished = false;547 548 if (priv->alcd_test_active)549 return dp83td510_cable_test_get_alcd_status(phydev, finished);550 551 return dp83td510_cable_test_get_tdr_status(phydev, finished);552}553 554static int dp83td510_get_features(struct phy_device *phydev)555{556 /* This PHY can't respond on MDIO bus if no RMII clock is enabled.557 * In case RMII mode is used (most meaningful mode for this PHY) and558 * the PHY do not have own XTAL, and CLK providing MAC is not probed,559 * we won't be able to read all needed ability registers.560 * So provide it manually.561 */562 563 linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported);564 linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);565 linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);566 linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,567 phydev->supported);568 569 return 0;570}571 572static int dp83td510_probe(struct phy_device *phydev)573{574 struct device *dev = &phydev->mdio.dev;575 struct dp83td510_priv *priv;576 577 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);578 if (!priv)579 return -ENOMEM;580 581 phydev->priv = priv;582 583 return 0;584}585 586static struct phy_driver dp83td510_driver[] = {587{588 PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID),589 .name = "TI DP83TD510E",590 591 .flags = PHY_POLL_CABLE_TEST,592 .probe = dp83td510_probe,593 .config_aneg = dp83td510_config_aneg,594 .read_status = dp83td510_read_status,595 .get_features = dp83td510_get_features,596 .config_intr = dp83td510_config_intr,597 .handle_interrupt = dp83td510_handle_interrupt,598 .get_sqi = dp83td510_get_sqi,599 .get_sqi_max = dp83td510_get_sqi_max,600 .cable_test_start = dp83td510_cable_test_start,601 .cable_test_get_status = dp83td510_cable_test_get_status,602 603 .suspend = genphy_suspend,604 .resume = genphy_resume,605} };606module_phy_driver(dp83td510_driver);607 608static struct mdio_device_id __maybe_unused dp83td510_tbl[] = {609 { PHY_ID_MATCH_MODEL(DP83TD510E_PHY_ID) },610 { }611};612MODULE_DEVICE_TABLE(mdio, dp83td510_tbl);613 614MODULE_DESCRIPTION("Texas Instruments DP83TD510E PHY driver");615MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>");616MODULE_LICENSE("GPL v2");617