xref: /openbmc/linux/drivers/net/phy/smsc.c (revision 7365494550f6e96b8e444201bf5fdaec40e7e007)
1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+
2c9e055acSHerbert Valerio Riedel /*
3c9e055acSHerbert Valerio Riedel  * drivers/net/phy/smsc.c
4c9e055acSHerbert Valerio Riedel  *
5c9e055acSHerbert Valerio Riedel  * Driver for SMSC PHYs
6c9e055acSHerbert Valerio Riedel  *
7c9e055acSHerbert Valerio Riedel  * Author: Herbert Valerio Riedel
8c9e055acSHerbert Valerio Riedel  *
9c9e055acSHerbert Valerio Riedel  * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>
10c9e055acSHerbert Valerio Riedel  *
1190b24cfbSSteve Glendinning  * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net
124d9b1a02SSteve Glendinning  *
13c9e055acSHerbert Valerio Riedel  */
14c9e055acSHerbert Valerio Riedel 
15c9e055acSHerbert Valerio Riedel #include <linux/kernel.h>
16c9e055acSHerbert Valerio Riedel #include <linux/module.h>
17c9e055acSHerbert Valerio Riedel #include <linux/mii.h>
18c9e055acSHerbert Valerio Riedel #include <linux/ethtool.h>
19c6e970a0SAndrew Lunn #include <linux/of.h>
20c9e055acSHerbert Valerio Riedel #include <linux/phy.h>
21c9e055acSHerbert Valerio Riedel #include <linux/netdevice.h>
2243c6759eSJavier Martinez Canillas #include <linux/smscphy.h>
23c9e055acSHerbert Valerio Riedel 
2405b35e7eSAndre Edich /* Vendor-specific PHY Definitions */
2505b35e7eSAndre Edich /* EDPD NLP / crossover time configuration */
2605b35e7eSAndre Edich #define PHY_EDPD_CONFIG			16
2705b35e7eSAndre Edich #define PHY_EDPD_CONFIG_EXT_CROSSOVER_	0x0001
2805b35e7eSAndre Edich 
2905b35e7eSAndre Edich /* Control/Status Indication Register */
3005b35e7eSAndre Edich #define SPECIAL_CTRL_STS		27
3105b35e7eSAndre Edich #define SPECIAL_CTRL_STS_OVRRD_AMDIX_	0x8000
3205b35e7eSAndre Edich #define SPECIAL_CTRL_STS_AMDIX_ENABLE_	0x4000
3305b35e7eSAndre Edich #define SPECIAL_CTRL_STS_AMDIX_STATE_	0x2000
3405b35e7eSAndre Edich 
35030a8902SAndrew Lunn struct smsc_hw_stat {
36030a8902SAndrew Lunn 	const char *string;
37030a8902SAndrew Lunn 	u8 reg;
38030a8902SAndrew Lunn 	u8 bits;
39030a8902SAndrew Lunn };
40030a8902SAndrew Lunn 
41030a8902SAndrew Lunn static struct smsc_hw_stat smsc_hw_stats[] = {
42030a8902SAndrew Lunn 	{ "phy_symbol_errors", 26, 16},
43030a8902SAndrew Lunn };
44030a8902SAndrew Lunn 
450a9c453eSTeresa Remmet struct smsc_phy_priv {
460a9c453eSTeresa Remmet 	bool energy_enable;
470a9c453eSTeresa Remmet };
480a9c453eSTeresa Remmet 
4948c41b99SSteve Glendinning static int smsc_phy_config_intr(struct phy_device *phydev)
50c9e055acSHerbert Valerio Riedel {
51*73654945SMarco Felsch 	struct smsc_phy_priv *priv = phydev->priv;
52*73654945SMarco Felsch 	u16 intmask = 0;
53*73654945SMarco Felsch 	int rc;
54*73654945SMarco Felsch 
55*73654945SMarco Felsch 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
56*73654945SMarco Felsch 		intmask = MII_LAN83C185_ISF_INT4 | MII_LAN83C185_ISF_INT6;
57*73654945SMarco Felsch 		if (priv->energy_enable)
58*73654945SMarco Felsch 			intmask |= MII_LAN83C185_ISF_INT7;
59*73654945SMarco Felsch 	}
60*73654945SMarco Felsch 
61*73654945SMarco Felsch 	rc = phy_write(phydev, MII_LAN83C185_IM, intmask);
62c9e055acSHerbert Valerio Riedel 
63c9e055acSHerbert Valerio Riedel 	return rc < 0 ? rc : 0;
64c9e055acSHerbert Valerio Riedel }
65c9e055acSHerbert Valerio Riedel 
6648c41b99SSteve Glendinning static int smsc_phy_ack_interrupt(struct phy_device *phydev)
67c9e055acSHerbert Valerio Riedel {
68c9e055acSHerbert Valerio Riedel 	int rc = phy_read (phydev, MII_LAN83C185_ISF);
69c9e055acSHerbert Valerio Riedel 
70c9e055acSHerbert Valerio Riedel 	return rc < 0 ? rc : 0;
71c9e055acSHerbert Valerio Riedel }
72c9e055acSHerbert Valerio Riedel 
7348c41b99SSteve Glendinning static int smsc_phy_config_init(struct phy_device *phydev)
74c9e055acSHerbert Valerio Riedel {
750a9c453eSTeresa Remmet 	struct smsc_phy_priv *priv = phydev->priv;
760a9c453eSTeresa Remmet 
7721009686SGwenhael Goavec-Merou 	int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
7821009686SGwenhael Goavec-Merou 
7921009686SGwenhael Goavec-Merou 	if (rc < 0)
8021009686SGwenhael Goavec-Merou 		return rc;
8121009686SGwenhael Goavec-Merou 
820a9c453eSTeresa Remmet 	if (priv->energy_enable) {
8321009686SGwenhael Goavec-Merou 		/* Enable energy detect mode for this SMSC Transceivers */
8421009686SGwenhael Goavec-Merou 		rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
8521009686SGwenhael Goavec-Merou 			       rc | MII_LAN83C185_EDPWRDOWN);
8621009686SGwenhael Goavec-Merou 		if (rc < 0)
8721009686SGwenhael Goavec-Merou 			return rc;
88d88ecb37SHeiko Schocher 	}
8921009686SGwenhael Goavec-Merou 
9021009686SGwenhael Goavec-Merou 	return smsc_phy_ack_interrupt(phydev);
9121009686SGwenhael Goavec-Merou }
9221009686SGwenhael Goavec-Merou 
9321009686SGwenhael Goavec-Merou static int smsc_phy_reset(struct phy_device *phydev)
9421009686SGwenhael Goavec-Merou {
956ded7cd6Strem 	int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
966ded7cd6Strem 	if (rc < 0)
976ded7cd6Strem 		return rc;
986ded7cd6Strem 
996ded7cd6Strem 	/* If the SMSC PHY is in power down mode, then set it
1006ded7cd6Strem 	 * in all capable mode before using it.
1016ded7cd6Strem 	 */
1026ded7cd6Strem 	if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {
103fc0f7e33SManfred Schlaegl 		/* set "all capable" mode */
1046ded7cd6Strem 		rc |= MII_LAN83C185_MODE_ALL;
1056ded7cd6Strem 		phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
1066ded7cd6Strem 	}
107fc0f7e33SManfred Schlaegl 
108fc0f7e33SManfred Schlaegl 	/* reset the phy */
109fc0f7e33SManfred Schlaegl 	return genphy_soft_reset(phydev);
110c9e055acSHerbert Valerio Riedel }
111c9e055acSHerbert Valerio Riedel 
1124223dbffSPatrick Trantham static int lan911x_config_init(struct phy_device *phydev)
113b629820dSMarek Vasut {
1144223dbffSPatrick Trantham 	return smsc_phy_ack_interrupt(phydev);
1154223dbffSPatrick Trantham }
1164223dbffSPatrick Trantham 
11705b35e7eSAndre Edich static int lan87xx_config_aneg(struct phy_device *phydev)
11805b35e7eSAndre Edich {
11905b35e7eSAndre Edich 	int rc;
12005b35e7eSAndre Edich 	int val;
12105b35e7eSAndre Edich 
12205b35e7eSAndre Edich 	switch (phydev->mdix_ctrl) {
12305b35e7eSAndre Edich 	case ETH_TP_MDI:
12405b35e7eSAndre Edich 		val = SPECIAL_CTRL_STS_OVRRD_AMDIX_;
12505b35e7eSAndre Edich 		break;
12605b35e7eSAndre Edich 	case ETH_TP_MDI_X:
12705b35e7eSAndre Edich 		val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
12805b35e7eSAndre Edich 			SPECIAL_CTRL_STS_AMDIX_STATE_;
12905b35e7eSAndre Edich 		break;
13005b35e7eSAndre Edich 	case ETH_TP_MDI_AUTO:
13105b35e7eSAndre Edich 		val = SPECIAL_CTRL_STS_AMDIX_ENABLE_;
13205b35e7eSAndre Edich 		break;
13305b35e7eSAndre Edich 	default:
13405b35e7eSAndre Edich 		return genphy_config_aneg(phydev);
13505b35e7eSAndre Edich 	}
13605b35e7eSAndre Edich 
13705b35e7eSAndre Edich 	rc = phy_read(phydev, SPECIAL_CTRL_STS);
13805b35e7eSAndre Edich 	if (rc < 0)
13905b35e7eSAndre Edich 		return rc;
14005b35e7eSAndre Edich 
14105b35e7eSAndre Edich 	rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ |
14205b35e7eSAndre Edich 		SPECIAL_CTRL_STS_AMDIX_ENABLE_ |
14305b35e7eSAndre Edich 		SPECIAL_CTRL_STS_AMDIX_STATE_);
14405b35e7eSAndre Edich 	rc |= val;
14505b35e7eSAndre Edich 	phy_write(phydev, SPECIAL_CTRL_STS, rc);
14605b35e7eSAndre Edich 
14705b35e7eSAndre Edich 	phydev->mdix = phydev->mdix_ctrl;
14805b35e7eSAndre Edich 	return genphy_config_aneg(phydev);
14905b35e7eSAndre Edich }
15005b35e7eSAndre Edich 
15105b35e7eSAndre Edich static int lan87xx_config_aneg_ext(struct phy_device *phydev)
15205b35e7eSAndre Edich {
15305b35e7eSAndre Edich 	int rc;
15405b35e7eSAndre Edich 
15505b35e7eSAndre Edich 	/* Extend Manual AutoMDIX timer */
15605b35e7eSAndre Edich 	rc = phy_read(phydev, PHY_EDPD_CONFIG);
15705b35e7eSAndre Edich 	if (rc < 0)
15805b35e7eSAndre Edich 		return rc;
15905b35e7eSAndre Edich 
16005b35e7eSAndre Edich 	rc |= PHY_EDPD_CONFIG_EXT_CROSSOVER_;
16105b35e7eSAndre Edich 	phy_write(phydev, PHY_EDPD_CONFIG, rc);
16205b35e7eSAndre Edich 	return lan87xx_config_aneg(phydev);
16305b35e7eSAndre Edich }
16405b35e7eSAndre Edich 
165b629820dSMarek Vasut /*
166776829deSIgor Plyatov  * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable
167776829deSIgor Plyatov  * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to
168776829deSIgor Plyatov  * unstable detection of plugging in Ethernet cable.
169776829deSIgor Plyatov  * This workaround disables Energy Detect Power-Down mode and waiting for
170776829deSIgor Plyatov  * response on link pulses to detect presence of plugged Ethernet cable.
171776829deSIgor Plyatov  * The Energy Detect Power-Down mode is enabled again in the end of procedure to
172776829deSIgor Plyatov  * save approximately 220 mW of power if cable is unplugged.
173b629820dSMarek Vasut  */
1744223dbffSPatrick Trantham static int lan87xx_read_status(struct phy_device *phydev)
1754223dbffSPatrick Trantham {
1760a9c453eSTeresa Remmet 	struct smsc_phy_priv *priv = phydev->priv;
1770a9c453eSTeresa Remmet 
1784223dbffSPatrick Trantham 	int err = genphy_read_status(phydev);
1790a9c453eSTeresa Remmet 
1800a9c453eSTeresa Remmet 	if (!phydev->link && priv->energy_enable) {
1814223dbffSPatrick Trantham 		/* Disable EDPD to wake up PHY */
182b629820dSMarek Vasut 		int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
183b629820dSMarek Vasut 		if (rc < 0)
184b629820dSMarek Vasut 			return rc;
185b629820dSMarek Vasut 
1864223dbffSPatrick Trantham 		rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
1874223dbffSPatrick Trantham 			       rc & ~MII_LAN83C185_EDPWRDOWN);
188b629820dSMarek Vasut 		if (rc < 0)
189b629820dSMarek Vasut 			return rc;
190b629820dSMarek Vasut 
1916d61f483SDejin Zheng 		/* Wait max 640 ms to detect energy and the timeout is not
1926d61f483SDejin Zheng 		 * an actual error.
1936d61f483SDejin Zheng 		 */
1946d61f483SDejin Zheng 		read_poll_timeout(phy_read, rc,
1956d61f483SDejin Zheng 				  rc & MII_LAN83C185_ENERGYON || rc < 0,
1966d61f483SDejin Zheng 				  10000, 640000, true, phydev,
1976d61f483SDejin Zheng 				  MII_LAN83C185_CTRL_STATUS);
198776829deSIgor Plyatov 		if (rc < 0)
199776829deSIgor Plyatov 			return rc;
2004223dbffSPatrick Trantham 
2014223dbffSPatrick Trantham 		/* Re-enable EDPD */
2024223dbffSPatrick Trantham 		rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);
2034223dbffSPatrick Trantham 		if (rc < 0)
2044223dbffSPatrick Trantham 			return rc;
2054223dbffSPatrick Trantham 
2064223dbffSPatrick Trantham 		rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,
2074223dbffSPatrick Trantham 			       rc | MII_LAN83C185_EDPWRDOWN);
2084223dbffSPatrick Trantham 		if (rc < 0)
2094223dbffSPatrick Trantham 			return rc;
210b629820dSMarek Vasut 	}
211b629820dSMarek Vasut 
2124223dbffSPatrick Trantham 	return err;
213698244acSGiuseppe Cavallaro }
214c9e055acSHerbert Valerio Riedel 
215030a8902SAndrew Lunn static int smsc_get_sset_count(struct phy_device *phydev)
216030a8902SAndrew Lunn {
217030a8902SAndrew Lunn 	return ARRAY_SIZE(smsc_hw_stats);
218030a8902SAndrew Lunn }
219030a8902SAndrew Lunn 
220030a8902SAndrew Lunn static void smsc_get_strings(struct phy_device *phydev, u8 *data)
221030a8902SAndrew Lunn {
222030a8902SAndrew Lunn 	int i;
223030a8902SAndrew Lunn 
224030a8902SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) {
2252da55390SArnd Bergmann 		strncpy(data + i * ETH_GSTRING_LEN,
226030a8902SAndrew Lunn 		       smsc_hw_stats[i].string, ETH_GSTRING_LEN);
227030a8902SAndrew Lunn 	}
228030a8902SAndrew Lunn }
229030a8902SAndrew Lunn 
230030a8902SAndrew Lunn static u64 smsc_get_stat(struct phy_device *phydev, int i)
231030a8902SAndrew Lunn {
232030a8902SAndrew Lunn 	struct smsc_hw_stat stat = smsc_hw_stats[i];
233030a8902SAndrew Lunn 	int val;
234030a8902SAndrew Lunn 	u64 ret;
235030a8902SAndrew Lunn 
236030a8902SAndrew Lunn 	val = phy_read(phydev, stat.reg);
237030a8902SAndrew Lunn 	if (val < 0)
2386c3442f5SJisheng Zhang 		ret = U64_MAX;
239030a8902SAndrew Lunn 	else
240030a8902SAndrew Lunn 		ret = val;
241030a8902SAndrew Lunn 
242030a8902SAndrew Lunn 	return ret;
243030a8902SAndrew Lunn }
244030a8902SAndrew Lunn 
245030a8902SAndrew Lunn static void smsc_get_stats(struct phy_device *phydev,
246030a8902SAndrew Lunn 			   struct ethtool_stats *stats, u64 *data)
247030a8902SAndrew Lunn {
248030a8902SAndrew Lunn 	int i;
249030a8902SAndrew Lunn 
250030a8902SAndrew Lunn 	for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)
251030a8902SAndrew Lunn 		data[i] = smsc_get_stat(phydev, i);
252030a8902SAndrew Lunn }
253030a8902SAndrew Lunn 
2540a9c453eSTeresa Remmet static int smsc_phy_probe(struct phy_device *phydev)
2550a9c453eSTeresa Remmet {
2560a9c453eSTeresa Remmet 	struct device *dev = &phydev->mdio.dev;
2570a9c453eSTeresa Remmet 	struct device_node *of_node = dev->of_node;
2580a9c453eSTeresa Remmet 	struct smsc_phy_priv *priv;
2590a9c453eSTeresa Remmet 
2600a9c453eSTeresa Remmet 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
2610a9c453eSTeresa Remmet 	if (!priv)
2620a9c453eSTeresa Remmet 		return -ENOMEM;
2630a9c453eSTeresa Remmet 
2640a9c453eSTeresa Remmet 	priv->energy_enable = true;
2650a9c453eSTeresa Remmet 
2660a9c453eSTeresa Remmet 	if (of_property_read_bool(of_node, "smsc,disable-energy-detect"))
2670a9c453eSTeresa Remmet 		priv->energy_enable = false;
2680a9c453eSTeresa Remmet 
2690a9c453eSTeresa Remmet 	phydev->priv = priv;
2700a9c453eSTeresa Remmet 
2710a9c453eSTeresa Remmet 	return 0;
2720a9c453eSTeresa Remmet }
2730a9c453eSTeresa Remmet 
274d5bf9071SChristian Hohnstaedt static struct phy_driver smsc_phy_driver[] = {
275d5bf9071SChristian Hohnstaedt {
276c9e055acSHerbert Valerio Riedel 	.phy_id		= 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */
277c9e055acSHerbert Valerio Riedel 	.phy_id_mask	= 0xfffffff0,
278c9e055acSHerbert Valerio Riedel 	.name		= "SMSC LAN83C185",
279c9e055acSHerbert Valerio Riedel 
280dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
281c9e055acSHerbert Valerio Riedel 
2820a9c453eSTeresa Remmet 	.probe		= smsc_phy_probe,
2830a9c453eSTeresa Remmet 
284c9e055acSHerbert Valerio Riedel 	/* basic functions */
28548c41b99SSteve Glendinning 	.config_init	= smsc_phy_config_init,
28621009686SGwenhael Goavec-Merou 	.soft_reset	= smsc_phy_reset,
287c9e055acSHerbert Valerio Riedel 
288c9e055acSHerbert Valerio Riedel 	/* IRQ related */
28948c41b99SSteve Glendinning 	.ack_interrupt	= smsc_phy_ack_interrupt,
29048c41b99SSteve Glendinning 	.config_intr	= smsc_phy_config_intr,
291c9e055acSHerbert Valerio Riedel 
292c64d2a9aSSteve Glendinning 	.suspend	= genphy_suspend,
293c64d2a9aSSteve Glendinning 	.resume		= genphy_resume,
294d5bf9071SChristian Hohnstaedt }, {
2954d9b1a02SSteve Glendinning 	.phy_id		= 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
2964d9b1a02SSteve Glendinning 	.phy_id_mask	= 0xfffffff0,
2974d9b1a02SSteve Glendinning 	.name		= "SMSC LAN8187",
2984d9b1a02SSteve Glendinning 
299dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
3004d9b1a02SSteve Glendinning 
3010a9c453eSTeresa Remmet 	.probe		= smsc_phy_probe,
3020a9c453eSTeresa Remmet 
3034d9b1a02SSteve Glendinning 	/* basic functions */
3044d9b1a02SSteve Glendinning 	.config_init	= smsc_phy_config_init,
30521009686SGwenhael Goavec-Merou 	.soft_reset	= smsc_phy_reset,
3064d9b1a02SSteve Glendinning 
3074d9b1a02SSteve Glendinning 	/* IRQ related */
3084d9b1a02SSteve Glendinning 	.ack_interrupt	= smsc_phy_ack_interrupt,
3094d9b1a02SSteve Glendinning 	.config_intr	= smsc_phy_config_intr,
3104d9b1a02SSteve Glendinning 
311030a8902SAndrew Lunn 	/* Statistics */
312030a8902SAndrew Lunn 	.get_sset_count = smsc_get_sset_count,
313030a8902SAndrew Lunn 	.get_strings	= smsc_get_strings,
314030a8902SAndrew Lunn 	.get_stats	= smsc_get_stats,
315030a8902SAndrew Lunn 
316c64d2a9aSSteve Glendinning 	.suspend	= genphy_suspend,
317c64d2a9aSSteve Glendinning 	.resume		= genphy_resume,
318d5bf9071SChristian Hohnstaedt }, {
31905b35e7eSAndre Edich 	/* This covers internal PHY (phy_id: 0x0007C0C3) for
32005b35e7eSAndre Edich 	 * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505)
32105b35e7eSAndre Edich 	 */
3224d9b1a02SSteve Glendinning 	.phy_id		= 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
3234d9b1a02SSteve Glendinning 	.phy_id_mask	= 0xfffffff0,
3244d9b1a02SSteve Glendinning 	.name		= "SMSC LAN8700",
3254d9b1a02SSteve Glendinning 
326dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
3274d9b1a02SSteve Glendinning 
3280a9c453eSTeresa Remmet 	.probe		= smsc_phy_probe,
3290a9c453eSTeresa Remmet 
3304d9b1a02SSteve Glendinning 	/* basic functions */
331776829deSIgor Plyatov 	.read_status	= lan87xx_read_status,
3324d9b1a02SSteve Glendinning 	.config_init	= smsc_phy_config_init,
33321009686SGwenhael Goavec-Merou 	.soft_reset	= smsc_phy_reset,
33405b35e7eSAndre Edich 	.config_aneg	= lan87xx_config_aneg,
3354d9b1a02SSteve Glendinning 
3364d9b1a02SSteve Glendinning 	/* IRQ related */
3374d9b1a02SSteve Glendinning 	.ack_interrupt	= smsc_phy_ack_interrupt,
3384d9b1a02SSteve Glendinning 	.config_intr	= smsc_phy_config_intr,
3394d9b1a02SSteve Glendinning 
340030a8902SAndrew Lunn 	/* Statistics */
341030a8902SAndrew Lunn 	.get_sset_count = smsc_get_sset_count,
342030a8902SAndrew Lunn 	.get_strings	= smsc_get_strings,
343030a8902SAndrew Lunn 	.get_stats	= smsc_get_stats,
344030a8902SAndrew Lunn 
345c64d2a9aSSteve Glendinning 	.suspend	= genphy_suspend,
346c64d2a9aSSteve Glendinning 	.resume		= genphy_resume,
347d5bf9071SChristian Hohnstaedt }, {
348fd9abb3dSSteve Glendinning 	.phy_id		= 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
349fd9abb3dSSteve Glendinning 	.phy_id_mask	= 0xfffffff0,
350fd9abb3dSSteve Glendinning 	.name		= "SMSC LAN911x Internal PHY",
351fd9abb3dSSteve Glendinning 
352dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
353fd9abb3dSSteve Glendinning 
3540a9c453eSTeresa Remmet 	.probe		= smsc_phy_probe,
3550a9c453eSTeresa Remmet 
356fd9abb3dSSteve Glendinning 	/* basic functions */
357698244acSGiuseppe Cavallaro 	.config_init	= lan911x_config_init,
358fd9abb3dSSteve Glendinning 
359fd9abb3dSSteve Glendinning 	/* IRQ related */
360fd9abb3dSSteve Glendinning 	.ack_interrupt	= smsc_phy_ack_interrupt,
361fd9abb3dSSteve Glendinning 	.config_intr	= smsc_phy_config_intr,
362fd9abb3dSSteve Glendinning 
363c64d2a9aSSteve Glendinning 	.suspend	= genphy_suspend,
364c64d2a9aSSteve Glendinning 	.resume		= genphy_resume,
365d5bf9071SChristian Hohnstaedt }, {
36605b35e7eSAndre Edich 	/* This covers internal PHY (phy_id: 0x0007C0F0) for
36705b35e7eSAndre Edich 	 * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01)
36805b35e7eSAndre Edich 	 */
369e072b639SSteve Glendinning 	.phy_id		= 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */
370e072b639SSteve Glendinning 	.phy_id_mask	= 0xfffffff0,
371e072b639SSteve Glendinning 	.name		= "SMSC LAN8710/LAN8720",
372e072b639SSteve Glendinning 
373dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
374a4307c0eSHeiner Kallweit 	.flags		= PHY_RST_AFTER_CLK_EN,
375e072b639SSteve Glendinning 
3760a9c453eSTeresa Remmet 	.probe		= smsc_phy_probe,
3770a9c453eSTeresa Remmet 
378e072b639SSteve Glendinning 	/* basic functions */
3794223dbffSPatrick Trantham 	.read_status	= lan87xx_read_status,
3804257d583SPatrick Trantham 	.config_init	= smsc_phy_config_init,
38121009686SGwenhael Goavec-Merou 	.soft_reset	= smsc_phy_reset,
38205b35e7eSAndre Edich 	.config_aneg	= lan87xx_config_aneg_ext,
383e072b639SSteve Glendinning 
384e072b639SSteve Glendinning 	/* IRQ related */
385e072b639SSteve Glendinning 	.ack_interrupt	= smsc_phy_ack_interrupt,
386e072b639SSteve Glendinning 	.config_intr	= smsc_phy_config_intr,
387e072b639SSteve Glendinning 
388030a8902SAndrew Lunn 	/* Statistics */
389030a8902SAndrew Lunn 	.get_sset_count = smsc_get_sset_count,
390030a8902SAndrew Lunn 	.get_strings	= smsc_get_strings,
391030a8902SAndrew Lunn 	.get_stats	= smsc_get_stats,
392030a8902SAndrew Lunn 
393e072b639SSteve Glendinning 	.suspend	= genphy_suspend,
394e072b639SSteve Glendinning 	.resume		= genphy_resume,
39526706d43SJoshua Henderson }, {
39626706d43SJoshua Henderson 	.phy_id		= 0x0007c110,
39726706d43SJoshua Henderson 	.phy_id_mask	= 0xfffffff0,
39826706d43SJoshua Henderson 	.name		= "SMSC LAN8740",
39926706d43SJoshua Henderson 
400dcdecdcfSHeiner Kallweit 	/* PHY_BASIC_FEATURES */
40176db2d46SMartin Fuzzey 	.flags		= PHY_RST_AFTER_CLK_EN,
40226706d43SJoshua Henderson 
4030a9c453eSTeresa Remmet 	.probe		= smsc_phy_probe,
4040a9c453eSTeresa Remmet 
40526706d43SJoshua Henderson 	/* basic functions */
40626706d43SJoshua Henderson 	.read_status	= lan87xx_read_status,
40726706d43SJoshua Henderson 	.config_init	= smsc_phy_config_init,
40826706d43SJoshua Henderson 	.soft_reset	= smsc_phy_reset,
40926706d43SJoshua Henderson 
41026706d43SJoshua Henderson 	/* IRQ related */
41126706d43SJoshua Henderson 	.ack_interrupt	= smsc_phy_ack_interrupt,
41226706d43SJoshua Henderson 	.config_intr	= smsc_phy_config_intr,
41326706d43SJoshua Henderson 
414030a8902SAndrew Lunn 	/* Statistics */
415030a8902SAndrew Lunn 	.get_sset_count = smsc_get_sset_count,
416030a8902SAndrew Lunn 	.get_strings	= smsc_get_strings,
417030a8902SAndrew Lunn 	.get_stats	= smsc_get_stats,
418030a8902SAndrew Lunn 
41926706d43SJoshua Henderson 	.suspend	= genphy_suspend,
42026706d43SJoshua Henderson 	.resume		= genphy_resume,
421d5bf9071SChristian Hohnstaedt } };
422e072b639SSteve Glendinning 
42350fd7150SJohan Hovold module_phy_driver(smsc_phy_driver);
424c9e055acSHerbert Valerio Riedel 
425c9e055acSHerbert Valerio Riedel MODULE_DESCRIPTION("SMSC PHY driver");
426c9e055acSHerbert Valerio Riedel MODULE_AUTHOR("Herbert Valerio Riedel");
427c9e055acSHerbert Valerio Riedel MODULE_LICENSE("GPL");
428c9e055acSHerbert Valerio Riedel 
429cf93c945SUwe Kleine-König static struct mdio_device_id __maybe_unused smsc_tbl[] = {
4304e4f10f6SDavid Woodhouse 	{ 0x0007c0a0, 0xfffffff0 },
4314e4f10f6SDavid Woodhouse 	{ 0x0007c0b0, 0xfffffff0 },
4324e4f10f6SDavid Woodhouse 	{ 0x0007c0c0, 0xfffffff0 },
4334e4f10f6SDavid Woodhouse 	{ 0x0007c0d0, 0xfffffff0 },
4344e4f10f6SDavid Woodhouse 	{ 0x0007c0f0, 0xfffffff0 },
43526706d43SJoshua Henderson 	{ 0x0007c110, 0xfffffff0 },
4364e4f10f6SDavid Woodhouse 	{ }
4374e4f10f6SDavid Woodhouse };
4384e4f10f6SDavid Woodhouse 
4394e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, smsc_tbl);
440