brintos

brintos / linux-shallow public Read only

0
0
Text · 19.9 KiB · 150aea7 Raw
852 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/smsc.c4 *5 * Driver for SMSC PHYs6 *7 * Author: Herbert Valerio Riedel8 *9 * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>10 *11 * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net12 *13 */14 15#include <linux/clk.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/mii.h>19#include <linux/ethtool.h>20#include <linux/of.h>21#include <linux/phy.h>22#include <linux/netdevice.h>23#include <linux/crc16.h>24#include <linux/etherdevice.h>25#include <linux/smscphy.h>26 27/* Vendor-specific PHY Definitions */28/* EDPD NLP / crossover time configuration */29#define PHY_EDPD_CONFIG			1630#define PHY_EDPD_CONFIG_EXT_CROSSOVER_	0x000131 32/* Control/Status Indication Register */33#define SPECIAL_CTRL_STS		2734#define SPECIAL_CTRL_STS_OVRRD_AMDIX_	0x800035#define SPECIAL_CTRL_STS_AMDIX_ENABLE_	0x400036#define SPECIAL_CTRL_STS_AMDIX_STATE_	0x200037 38#define EDPD_MAX_WAIT_DFLT_MS		64039/* interval between phylib state machine runs in ms */40#define PHY_STATE_MACH_MS		100041 42struct smsc_hw_stat {43	const char *string;44	u8 reg;45	u8 bits;46};47 48static struct smsc_hw_stat smsc_hw_stats[] = {49	{ "phy_symbol_errors", 26, 16},50};51 52struct smsc_phy_priv {53	unsigned int edpd_enable:1;54	unsigned int edpd_mode_set_by_user:1;55	unsigned int edpd_max_wait_ms;56	bool wol_arp;57};58 59static int smsc_phy_ack_interrupt(struct phy_device *phydev)60{61	int rc = phy_read(phydev, MII_LAN83C185_ISF);62 63	return rc < 0 ? rc : 0;64}65 66int smsc_phy_config_intr(struct phy_device *phydev)67{68	int rc;69 70	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {71		rc = smsc_phy_ack_interrupt(phydev);72		if (rc)73			return rc;74 75		rc = phy_write(phydev, MII_LAN83C185_IM,76			       MII_LAN83C185_ISF_INT_PHYLIB_EVENTS);77	} else {78		rc = phy_write(phydev, MII_LAN83C185_IM, 0);79		if (rc)80			return rc;81 82		rc = smsc_phy_ack_interrupt(phydev);83	}84 85	return rc < 0 ? rc : 0;86}87EXPORT_SYMBOL_GPL(smsc_phy_config_intr);88 89static int smsc_phy_config_edpd(struct phy_device *phydev)90{91	struct smsc_phy_priv *priv = phydev->priv;92 93	if (priv->edpd_enable)94		return phy_set_bits(phydev, MII_LAN83C185_CTRL_STATUS,95				    MII_LAN83C185_EDPWRDOWN);96	else97		return phy_clear_bits(phydev, MII_LAN83C185_CTRL_STATUS,98				      MII_LAN83C185_EDPWRDOWN);99}100 101irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev)102{103	int irq_status;104 105	irq_status = phy_read(phydev, MII_LAN83C185_ISF);106	if (irq_status < 0) {107		if (irq_status != -ENODEV)108			phy_error(phydev);109 110		return IRQ_NONE;111	}112 113	if (!(irq_status & MII_LAN83C185_ISF_INT_PHYLIB_EVENTS))114		return IRQ_NONE;115 116	phy_trigger_machine(phydev);117 118	return IRQ_HANDLED;119}120EXPORT_SYMBOL_GPL(smsc_phy_handle_interrupt);121 122int smsc_phy_config_init(struct phy_device *phydev)123{124	struct smsc_phy_priv *priv = phydev->priv;125 126	if (!priv)127		return 0;128 129	/* don't use EDPD in irq mode except overridden by user */130	if (!priv->edpd_mode_set_by_user && phydev->irq != PHY_POLL)131		priv->edpd_enable = false;132 133	return smsc_phy_config_edpd(phydev);134}135EXPORT_SYMBOL_GPL(smsc_phy_config_init);136 137static int smsc_phy_reset(struct phy_device *phydev)138{139	int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);140	if (rc < 0)141		return rc;142 143	/* If the SMSC PHY is in power down mode, then set it144	 * in all capable mode before using it.145	 */146	if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {147		/* set "all capable" mode */148		rc |= MII_LAN83C185_MODE_ALL;149		phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);150	}151 152	/* reset the phy */153	return genphy_soft_reset(phydev);154}155 156static int lan87xx_config_aneg(struct phy_device *phydev)157{158	int rc;159	int val;160 161	switch (phydev->mdix_ctrl) {162	case ETH_TP_MDI:163		val = SPECIAL_CTRL_STS_OVRRD_AMDIX_;164		break;165	case ETH_TP_MDI_X:166		val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ |167			SPECIAL_CTRL_STS_AMDIX_STATE_;168		break;169	case ETH_TP_MDI_AUTO:170		val = SPECIAL_CTRL_STS_AMDIX_ENABLE_;171		break;172	default:173		return genphy_config_aneg(phydev);174	}175 176	rc = phy_read(phydev, SPECIAL_CTRL_STS);177	if (rc < 0)178		return rc;179 180	rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ |181		SPECIAL_CTRL_STS_AMDIX_ENABLE_ |182		SPECIAL_CTRL_STS_AMDIX_STATE_);183	rc |= val;184	phy_write(phydev, SPECIAL_CTRL_STS, rc);185 186	phydev->mdix = phydev->mdix_ctrl;187	return genphy_config_aneg(phydev);188}189 190static int lan95xx_config_aneg_ext(struct phy_device *phydev)191{192	if (phydev->phy_id == 0x0007c0f0) { /* LAN9500A or LAN9505A */193		/* Extend Manual AutoMDIX timer */194		int rc = phy_set_bits(phydev, PHY_EDPD_CONFIG,195				      PHY_EDPD_CONFIG_EXT_CROSSOVER_);196 197		if (rc < 0)198			return rc;199	}200 201	return lan87xx_config_aneg(phydev);202}203 204/*205 * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable206 * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to207 * unstable detection of plugging in Ethernet cable.208 * This workaround disables Energy Detect Power-Down mode and waiting for209 * response on link pulses to detect presence of plugged Ethernet cable.210 * The Energy Detect Power-Down mode is enabled again in the end of procedure to211 * save approximately 220 mW of power if cable is unplugged.212 * The workaround is only applicable to poll mode. Energy Detect Power-Down may213 * not be used in interrupt mode lest link change detection becomes unreliable.214 */215int lan87xx_read_status(struct phy_device *phydev)216{217	struct smsc_phy_priv *priv = phydev->priv;218	int err;219 220	err = genphy_read_status(phydev);221	if (err)222		return err;223 224	if (!phydev->link && priv && priv->edpd_enable &&225	    priv->edpd_max_wait_ms) {226		unsigned int max_wait = priv->edpd_max_wait_ms * 1000;227		int rc;228 229		/* Disable EDPD to wake up PHY */230		rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);231		if (rc < 0)232			return rc;233 234		rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,235			       rc & ~MII_LAN83C185_EDPWRDOWN);236		if (rc < 0)237			return rc;238 239		/* Wait max 640 ms to detect energy and the timeout is not240		 * an actual error.241		 */242		read_poll_timeout(phy_read, rc,243				  rc & MII_LAN83C185_ENERGYON || rc < 0,244				  10000, max_wait, true, phydev,245				  MII_LAN83C185_CTRL_STATUS);246		if (rc < 0)247			return rc;248 249		/* Re-enable EDPD */250		rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);251		if (rc < 0)252			return rc;253 254		rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,255			       rc | MII_LAN83C185_EDPWRDOWN);256		if (rc < 0)257			return rc;258	}259 260	return err;261}262EXPORT_SYMBOL_GPL(lan87xx_read_status);263 264static int lan874x_phy_config_init(struct phy_device *phydev)265{266	u16 val;267	int rc;268 269	/* Setup LED2/nINT/nPME pin to function as nPME.  May need user option270	 * to use LED1/nINT/nPME.271	 */272	val = MII_LAN874X_PHY_PME2_SET;273 274	/* The bits MII_LAN874X_PHY_WOL_PFDA_FR, MII_LAN874X_PHY_WOL_WUFR,275	 * MII_LAN874X_PHY_WOL_MPR, and MII_LAN874X_PHY_WOL_BCAST_FR need to276	 * be cleared to de-assert PME signal after a WoL event happens, but277	 * using PME auto clear gets around that.278	 */279	val |= MII_LAN874X_PHY_PME_SELF_CLEAR;280	rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR,281			   val);282	if (rc < 0)283		return rc;284 285	/* set nPME self clear delay time */286	rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_MCFGR,287			   MII_LAN874X_PHY_PME_SELF_CLEAR_DELAY);288	if (rc < 0)289		return rc;290 291	return smsc_phy_config_init(phydev);292}293 294static void lan874x_get_wol(struct phy_device *phydev,295			    struct ethtool_wolinfo *wol)296{297	struct smsc_phy_priv *priv = phydev->priv;298	int rc;299 300	wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC |301			  WAKE_ARP | WAKE_MCAST);302	wol->wolopts = 0;303 304	rc = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR);305	if (rc < 0)306		return;307 308	if (rc & MII_LAN874X_PHY_WOL_PFDAEN)309		wol->wolopts |= WAKE_UCAST;310 311	if (rc & MII_LAN874X_PHY_WOL_BCSTEN)312		wol->wolopts |= WAKE_BCAST;313 314	if (rc & MII_LAN874X_PHY_WOL_MPEN)315		wol->wolopts |= WAKE_MAGIC;316 317	if (rc & MII_LAN874X_PHY_WOL_WUEN) {318		if (priv->wol_arp)319			wol->wolopts |= WAKE_ARP;320		else321			wol->wolopts |= WAKE_MCAST;322	}323}324 325static u16 smsc_crc16(const u8 *buffer, size_t len)326{327	return bitrev16(crc16(0xFFFF, buffer, len));328}329 330static int lan874x_chk_wol_pattern(const u8 pattern[], const u16 *mask,331				   u8 len, u8 *data, u8 *datalen)332{333	size_t i, j, k;334	int ret = 0;335	u16 bits;336 337	/* Pattern filtering can match up to 128 bytes of frame data.  There338	 * are 8 registers to program the 16-bit masks, where each bit means339	 * the byte will be compared.  The frame data will then go through a340	 * CRC16 calculation for hardware comparison.  This helper function341	 * makes sure only relevant frame data are included in this342	 * calculation.  It provides a warning when the masks and expected343	 * data size do not match.344	 */345	i = 0;346	k = 0;347	while (len > 0) {348		bits = *mask;349		for (j = 0; j < 16; j++, i++, len--) {350			/* No more pattern. */351			if (!len) {352				/* The rest of bitmap is not empty. */353				if (bits)354					ret = i + 1;355				break;356			}357			if (bits & 1)358				data[k++] = pattern[i];359			bits >>= 1;360		}361		mask++;362	}363	*datalen = k;364	return ret;365}366 367static int lan874x_set_wol_pattern(struct phy_device *phydev, u16 val,368				   const u8 data[], u8 datalen,369				   const u16 *mask, u8 masklen)370{371	u16 crc, reg;372	int rc;373 374	/* Starting pattern offset is set before calling this function. */375	val |= MII_LAN874X_PHY_WOL_FILTER_EN;376	rc = phy_write_mmd(phydev, MDIO_MMD_PCS,377			   MII_LAN874X_PHY_MMD_WOL_WUF_CFGA, val);378	if (rc < 0)379		return rc;380 381	crc = smsc_crc16(data, datalen);382	rc = phy_write_mmd(phydev, MDIO_MMD_PCS,383			   MII_LAN874X_PHY_MMD_WOL_WUF_CFGB, crc);384	if (rc < 0)385		return rc;386 387	masklen = (masklen + 15) & ~0xf;388	reg = MII_LAN874X_PHY_MMD_WOL_WUF_MASK7;389	while (masklen >= 16) {390		rc = phy_write_mmd(phydev, MDIO_MMD_PCS, reg, *mask);391		if (rc < 0)392			return rc;393		reg--;394		mask++;395		masklen -= 16;396	}397 398	/* Clear out the rest of mask registers. */399	while (reg != MII_LAN874X_PHY_MMD_WOL_WUF_MASK0) {400		phy_write_mmd(phydev, MDIO_MMD_PCS, reg, 0);401		reg--;402	}403	return rc;404}405 406static int lan874x_set_wol(struct phy_device *phydev,407			   struct ethtool_wolinfo *wol)408{409	struct net_device *ndev = phydev->attached_dev;410	struct smsc_phy_priv *priv = phydev->priv;411	u16 val, val_wucsr;412	u8 data[128];413	u8 datalen;414	int rc;415 416	/* lan874x has only one WoL filter pattern */417	if ((wol->wolopts & (WAKE_ARP | WAKE_MCAST)) ==418	    (WAKE_ARP | WAKE_MCAST)) {419		phydev_info(phydev,420			    "lan874x WoL supports one of ARP|MCAST at a time\n");421		return -EOPNOTSUPP;422	}423 424	rc = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR);425	if (rc < 0)426		return rc;427 428	val_wucsr = rc;429 430	if (wol->wolopts & WAKE_UCAST)431		val_wucsr |= MII_LAN874X_PHY_WOL_PFDAEN;432	else433		val_wucsr &= ~MII_LAN874X_PHY_WOL_PFDAEN;434 435	if (wol->wolopts & WAKE_BCAST)436		val_wucsr |= MII_LAN874X_PHY_WOL_BCSTEN;437	else438		val_wucsr &= ~MII_LAN874X_PHY_WOL_BCSTEN;439 440	if (wol->wolopts & WAKE_MAGIC)441		val_wucsr |= MII_LAN874X_PHY_WOL_MPEN;442	else443		val_wucsr &= ~MII_LAN874X_PHY_WOL_MPEN;444 445	/* Need to use pattern matching */446	if (wol->wolopts & (WAKE_ARP | WAKE_MCAST))447		val_wucsr |= MII_LAN874X_PHY_WOL_WUEN;448	else449		val_wucsr &= ~MII_LAN874X_PHY_WOL_WUEN;450 451	if (wol->wolopts & WAKE_ARP) {452		const u8 pattern[2] = { 0x08, 0x06 };453		const u16 mask[1] = { 0x0003 };454 455		rc = lan874x_chk_wol_pattern(pattern, mask, 2, data,456					     &datalen);457		if (rc)458			phydev_dbg(phydev, "pattern not valid at %d\n", rc);459 460		/* Need to match broadcast destination address and provided461		 * data pattern at offset 12.462		 */463		val = 12 | MII_LAN874X_PHY_WOL_FILTER_BCSTEN;464		rc = lan874x_set_wol_pattern(phydev, val, data, datalen, mask,465					     2);466		if (rc < 0)467			return rc;468		priv->wol_arp = true;469	}470 471	if (wol->wolopts & WAKE_MCAST) {472		/* Need to match multicast destination address. */473		val = MII_LAN874X_PHY_WOL_FILTER_MCASTTEN;474		rc = lan874x_set_wol_pattern(phydev, val, data, 0, NULL, 0);475		if (rc < 0)476			return rc;477		priv->wol_arp = false;478	}479 480	if (wol->wolopts & (WAKE_MAGIC | WAKE_UCAST)) {481		const u8 *mac = (const u8 *)ndev->dev_addr;482		int i, reg;483 484		reg = MII_LAN874X_PHY_MMD_WOL_RX_ADDRC;485		for (i = 0; i < 6; i += 2, reg--) {486			rc = phy_write_mmd(phydev, MDIO_MMD_PCS, reg,487					   ((mac[i + 1] << 8) | mac[i]));488			if (rc < 0)489				return rc;490		}491	}492 493	rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR,494			   val_wucsr);495	if (rc < 0)496		return rc;497 498	return 0;499}500 501static int smsc_get_sset_count(struct phy_device *phydev)502{503	return ARRAY_SIZE(smsc_hw_stats);504}505 506static void smsc_get_strings(struct phy_device *phydev, u8 *data)507{508	int i;509 510	for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)511		ethtool_puts(&data, smsc_hw_stats[i].string);512}513 514static u64 smsc_get_stat(struct phy_device *phydev, int i)515{516	struct smsc_hw_stat stat = smsc_hw_stats[i];517	int val;518	u64 ret;519 520	val = phy_read(phydev, stat.reg);521	if (val < 0)522		ret = U64_MAX;523	else524		ret = val;525 526	return ret;527}528 529static void smsc_get_stats(struct phy_device *phydev,530			   struct ethtool_stats *stats, u64 *data)531{532	int i;533 534	for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)535		data[i] = smsc_get_stat(phydev, i);536}537 538static int smsc_phy_get_edpd(struct phy_device *phydev, u16 *edpd)539{540	struct smsc_phy_priv *priv = phydev->priv;541 542	if (!priv)543		return -EOPNOTSUPP;544 545	if (!priv->edpd_enable)546		*edpd = ETHTOOL_PHY_EDPD_DISABLE;547	else if (!priv->edpd_max_wait_ms)548		*edpd = ETHTOOL_PHY_EDPD_NO_TX;549	else550		*edpd = PHY_STATE_MACH_MS + priv->edpd_max_wait_ms;551 552	return 0;553}554 555static int smsc_phy_set_edpd(struct phy_device *phydev, u16 edpd)556{557	struct smsc_phy_priv *priv = phydev->priv;558 559	if (!priv)560		return -EOPNOTSUPP;561 562	switch (edpd) {563	case ETHTOOL_PHY_EDPD_DISABLE:564		priv->edpd_enable = false;565		break;566	case ETHTOOL_PHY_EDPD_NO_TX:567		priv->edpd_enable = true;568		priv->edpd_max_wait_ms = 0;569		break;570	case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:571		edpd = PHY_STATE_MACH_MS + EDPD_MAX_WAIT_DFLT_MS;572		fallthrough;573	default:574		if (phydev->irq != PHY_POLL)575			return -EOPNOTSUPP;576		if (edpd < PHY_STATE_MACH_MS || edpd > PHY_STATE_MACH_MS + 1000)577			return -EINVAL;578		priv->edpd_enable = true;579		priv->edpd_max_wait_ms = edpd - PHY_STATE_MACH_MS;580	}581 582	priv->edpd_mode_set_by_user = true;583 584	return smsc_phy_config_edpd(phydev);585}586 587int smsc_phy_get_tunable(struct phy_device *phydev,588			 struct ethtool_tunable *tuna, void *data)589{590	switch (tuna->id) {591	case ETHTOOL_PHY_EDPD:592		return smsc_phy_get_edpd(phydev, data);593	default:594		return -EOPNOTSUPP;595	}596}597EXPORT_SYMBOL_GPL(smsc_phy_get_tunable);598 599int smsc_phy_set_tunable(struct phy_device *phydev,600			 struct ethtool_tunable *tuna, const void *data)601{602	switch (tuna->id) {603	case ETHTOOL_PHY_EDPD:604		return smsc_phy_set_edpd(phydev, *(u16 *)data);605	default:606		return -EOPNOTSUPP;607	}608}609EXPORT_SYMBOL_GPL(smsc_phy_set_tunable);610 611int smsc_phy_probe(struct phy_device *phydev)612{613	struct device *dev = &phydev->mdio.dev;614	struct smsc_phy_priv *priv;615	struct clk *refclk;616 617	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);618	if (!priv)619		return -ENOMEM;620 621	priv->edpd_enable = true;622	priv->edpd_max_wait_ms = EDPD_MAX_WAIT_DFLT_MS;623 624	if (device_property_present(dev, "smsc,disable-energy-detect"))625		priv->edpd_enable = false;626 627	phydev->priv = priv;628 629	/* Make clk optional to keep DTB backward compatibility. */630	refclk = devm_clk_get_optional_enabled(dev, NULL);631	if (IS_ERR(refclk))632		return dev_err_probe(dev, PTR_ERR(refclk),633				     "Failed to request clock\n");634 635	return clk_set_rate(refclk, 50 * 1000 * 1000);636}637EXPORT_SYMBOL_GPL(smsc_phy_probe);638 639static struct phy_driver smsc_phy_driver[] = {640{641	.phy_id		= 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */642	.phy_id_mask	= 0xfffffff0,643	.name		= "SMSC LAN83C185",644 645	/* PHY_BASIC_FEATURES */646 647	.probe		= smsc_phy_probe,648 649	/* basic functions */650	.config_init	= smsc_phy_config_init,651	.soft_reset	= smsc_phy_reset,652 653	/* IRQ related */654	.config_intr	= smsc_phy_config_intr,655	.handle_interrupt = smsc_phy_handle_interrupt,656 657	.suspend	= genphy_suspend,658	.resume		= genphy_resume,659}, {660	.phy_id		= 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */661	.phy_id_mask	= 0xfffffff0,662	.name		= "SMSC LAN8187",663 664	/* PHY_BASIC_FEATURES */665 666	.probe		= smsc_phy_probe,667 668	/* basic functions */669	.config_init	= smsc_phy_config_init,670	.soft_reset	= smsc_phy_reset,671 672	/* IRQ related */673	.config_intr	= smsc_phy_config_intr,674	.handle_interrupt = smsc_phy_handle_interrupt,675 676	/* Statistics */677	.get_sset_count = smsc_get_sset_count,678	.get_strings	= smsc_get_strings,679	.get_stats	= smsc_get_stats,680 681	.suspend	= genphy_suspend,682	.resume		= genphy_resume,683}, {684	/* This covers internal PHY (phy_id: 0x0007C0C3) for685	 * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505)686	 */687	.phy_id		= 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */688	.phy_id_mask	= 0xfffffff0,689	.name		= "SMSC LAN8700",690 691	/* PHY_BASIC_FEATURES */692 693	.probe		= smsc_phy_probe,694 695	/* basic functions */696	.read_status	= lan87xx_read_status,697	.config_init	= smsc_phy_config_init,698	.soft_reset	= smsc_phy_reset,699	.config_aneg	= lan87xx_config_aneg,700 701	/* IRQ related */702	.config_intr	= smsc_phy_config_intr,703	.handle_interrupt = smsc_phy_handle_interrupt,704 705	/* Statistics */706	.get_sset_count = smsc_get_sset_count,707	.get_strings	= smsc_get_strings,708	.get_stats	= smsc_get_stats,709 710	.get_tunable	= smsc_phy_get_tunable,711	.set_tunable	= smsc_phy_set_tunable,712 713	.suspend	= genphy_suspend,714	.resume		= genphy_resume,715}, {716	.phy_id		= 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */717	.phy_id_mask	= 0xfffffff0,718	.name		= "SMSC LAN911x Internal PHY",719 720	/* PHY_BASIC_FEATURES */721 722	.probe		= smsc_phy_probe,723 724	/* IRQ related */725	.config_intr	= smsc_phy_config_intr,726	.handle_interrupt = smsc_phy_handle_interrupt,727 728	.suspend	= genphy_suspend,729	.resume		= genphy_resume,730}, {731	/* This covers internal PHY (phy_id: 0x0007C0F0) for732	 * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01)733	 */734	.phy_id		= 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */735	.phy_id_mask	= 0xfffffff0,736	.name		= "SMSC LAN8710/LAN8720",737 738	/* PHY_BASIC_FEATURES */739 740	.probe		= smsc_phy_probe,741 742	/* basic functions */743	.read_status	= lan87xx_read_status,744	.config_init	= smsc_phy_config_init,745	.soft_reset	= smsc_phy_reset,746	.config_aneg	= lan95xx_config_aneg_ext,747 748	/* IRQ related */749	.config_intr	= smsc_phy_config_intr,750	.handle_interrupt = smsc_phy_handle_interrupt,751 752	/* Statistics */753	.get_sset_count = smsc_get_sset_count,754	.get_strings	= smsc_get_strings,755	.get_stats	= smsc_get_stats,756 757	.get_tunable	= smsc_phy_get_tunable,758	.set_tunable	= smsc_phy_set_tunable,759 760	.suspend	= genphy_suspend,761	.resume		= genphy_resume,762}, {763	.phy_id		= 0x0007c110,764	.phy_id_mask	= 0xfffffff0,765	.name		= "SMSC LAN8740",766 767	/* PHY_BASIC_FEATURES */768	.flags		= PHY_RST_AFTER_CLK_EN,769 770	.probe		= smsc_phy_probe,771 772	/* basic functions */773	.read_status	= lan87xx_read_status,774	.config_init	= lan874x_phy_config_init,775	.soft_reset	= smsc_phy_reset,776 777	/* IRQ related */778	.config_intr	= smsc_phy_config_intr,779	.handle_interrupt = smsc_phy_handle_interrupt,780 781	/* Statistics */782	.get_sset_count = smsc_get_sset_count,783	.get_strings	= smsc_get_strings,784	.get_stats	= smsc_get_stats,785 786	.get_tunable	= smsc_phy_get_tunable,787	.set_tunable	= smsc_phy_set_tunable,788 789	/* WoL */790	.set_wol	= lan874x_set_wol,791	.get_wol	= lan874x_get_wol,792 793	.suspend	= genphy_suspend,794	.resume		= genphy_resume,795}, {796	.phy_id		= 0x0007c130,	/* 0x0007c130 and 0x0007c131 */797	/* This mask (0xfffffff2) is to differentiate from798	 * LAN88xx (phy_id 0x0007c132)799	 * and allows future phy_id revisions.800	 */801	.phy_id_mask	= 0xfffffff2,802	.name		= "Microchip LAN8742",803 804	/* PHY_BASIC_FEATURES */805	.flags		= PHY_RST_AFTER_CLK_EN,806 807	.probe		= smsc_phy_probe,808 809	/* basic functions */810	.read_status	= lan87xx_read_status,811	.config_init	= lan874x_phy_config_init,812	.soft_reset	= smsc_phy_reset,813 814	/* IRQ related */815	.config_intr	= smsc_phy_config_intr,816	.handle_interrupt = smsc_phy_handle_interrupt,817 818	/* Statistics */819	.get_sset_count = smsc_get_sset_count,820	.get_strings	= smsc_get_strings,821	.get_stats	= smsc_get_stats,822 823	.get_tunable	= smsc_phy_get_tunable,824	.set_tunable	= smsc_phy_set_tunable,825 826	/* WoL */827	.set_wol	= lan874x_set_wol,828	.get_wol	= lan874x_get_wol,829 830	.suspend	= genphy_suspend,831	.resume		= genphy_resume,832} };833 834module_phy_driver(smsc_phy_driver);835 836MODULE_DESCRIPTION("SMSC PHY driver");837MODULE_AUTHOR("Herbert Valerio Riedel");838MODULE_LICENSE("GPL");839 840static struct mdio_device_id __maybe_unused smsc_tbl[] = {841	{ 0x0007c0a0, 0xfffffff0 },842	{ 0x0007c0b0, 0xfffffff0 },843	{ 0x0007c0c0, 0xfffffff0 },844	{ 0x0007c0d0, 0xfffffff0 },845	{ 0x0007c0f0, 0xfffffff0 },846	{ 0x0007c110, 0xfffffff0 },847	{ 0x0007c130, 0xfffffff2 },848	{ }849};850 851MODULE_DEVICE_TABLE(mdio, smsc_tbl);852