brintos

brintos / linux-shallow public Read only

0
0
Text · 19.0 KiB · 92aa3a2 Raw
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