xref: /openbmc/linux/drivers/net/phy/realtek.c (revision 0db00e5d86dc793aab9722ad3728d99166eb7d96)
1a2443fd1SAndrew Lunn // SPDX-License-Identifier: GPL-2.0+
2bbc4d71dSWilly Liu /* drivers/net/phy/realtek.c
3097c2aa8SJohnson Leung  *
4097c2aa8SJohnson Leung  * Driver for Realtek PHYs
5097c2aa8SJohnson Leung  *
6097c2aa8SJohnson Leung  * Author: Johnson Leung <r58129@freescale.com>
7097c2aa8SJohnson Leung  *
8097c2aa8SJohnson Leung  * Copyright (c) 2004 Freescale Semiconductor, Inc.
9097c2aa8SJohnson Leung  */
108cc5baefSMartin Blumenstingl #include <linux/bitops.h>
110a4355c2SJoakim Zhang #include <linux/of.h>
12097c2aa8SJohnson Leung #include <linux/phy.h>
139d9779e7SPaul Gortmaker #include <linux/module.h>
14fee698d6SHeiner Kallweit #include <linux/delay.h>
157300c9b5SDetlev Casanova #include <linux/clk.h>
16097c2aa8SJohnson Leung 
17097c2aa8SJohnson Leung #define RTL821x_PHYSR				0x11
188cc5baefSMartin Blumenstingl #define RTL821x_PHYSR_DUPLEX			BIT(13)
198cc5baefSMartin Blumenstingl #define RTL821x_PHYSR_SPEED			GENMASK(15, 14)
20a82f266dSMartin Blumenstingl 
21097c2aa8SJohnson Leung #define RTL821x_INER				0x12
2269021e32SMartin Blumenstingl #define RTL8211B_INER_INIT			0x6400
238cc5baefSMartin Blumenstingl #define RTL8211E_INER_LINK_STATUS		BIT(10)
248cc5baefSMartin Blumenstingl #define RTL8211F_INER_LINK_STATUS		BIT(4)
25a82f266dSMartin Blumenstingl 
26a82f266dSMartin Blumenstingl #define RTL821x_INSR				0x13
27a82f266dSMartin Blumenstingl 
28f81dadbcSSerge Semin #define RTL821x_EXT_PAGE_SELECT			0x1e
29a82f266dSMartin Blumenstingl #define RTL821x_PAGE_SELECT			0x1f
30a82f266dSMartin Blumenstingl 
3166e22932SJisheng Zhang #define RTL8211F_PHYCR1				0x18
320a4355c2SJoakim Zhang #define RTL8211F_PHYCR2				0x19
333447cf2eSShengzhou Liu #define RTL8211F_INSR				0x1d
34f609ab0eSMartin Blumenstingl 
358cc5baefSMartin Blumenstingl #define RTL8211F_TX_DELAY			BIT(8)
361b3047b5SMartin Blumenstingl #define RTL8211F_RX_DELAY			BIT(3)
371b3047b5SMartin Blumenstingl 
3866e22932SJisheng Zhang #define RTL8211F_ALDPS_PLL_OFF			BIT(1)
3966e22932SJisheng Zhang #define RTL8211F_ALDPS_ENABLE			BIT(2)
4066e22932SJisheng Zhang #define RTL8211F_ALDPS_XTAL_OFF			BIT(12)
4166e22932SJisheng Zhang 
42bbc4d71dSWilly Liu #define RTL8211E_CTRL_DELAY			BIT(13)
43bbc4d71dSWilly Liu #define RTL8211E_TX_DELAY			BIT(12)
44bbc4d71dSWilly Liu #define RTL8211E_RX_DELAY			BIT(11)
453447cf2eSShengzhou Liu 
460a4355c2SJoakim Zhang #define RTL8211F_CLKOUT_EN			BIT(0)
470a4355c2SJoakim Zhang 
48513588ddSJassi Brar #define RTL8201F_ISR				0x1e
4903829163SIoana Ciornei #define RTL8201F_ISR_ANERR			BIT(15)
5003829163SIoana Ciornei #define RTL8201F_ISR_DUPLEX			BIT(13)
5103829163SIoana Ciornei #define RTL8201F_ISR_LINK			BIT(11)
5203829163SIoana Ciornei #define RTL8201F_ISR_MASK			(RTL8201F_ISR_ANERR | \
5303829163SIoana Ciornei 						 RTL8201F_ISR_DUPLEX | \
5403829163SIoana Ciornei 						 RTL8201F_ISR_LINK)
55513588ddSJassi Brar #define RTL8201F_IER				0x13
56513588ddSJassi Brar 
57d8545825SLinus Walleij #define RTL8366RB_POWER_SAVE			0x15
58d8545825SLinus Walleij #define RTL8366RB_POWER_SAVE_ON			BIT(12)
59d8545825SLinus Walleij 
605181b473SHeiner Kallweit #define RTL_SUPPORTS_5000FULL			BIT(14)
615181b473SHeiner Kallweit #define RTL_SUPPORTS_2500FULL			BIT(13)
625181b473SHeiner Kallweit #define RTL_SUPPORTS_10000FULL			BIT(0)
63087f5b87SHeiner Kallweit #define RTL_ADV_2500FULL			BIT(7)
64087f5b87SHeiner Kallweit #define RTL_LPADV_10000FULL			BIT(11)
65087f5b87SHeiner Kallweit #define RTL_LPADV_5000FULL			BIT(6)
66087f5b87SHeiner Kallweit #define RTL_LPADV_2500FULL			BIT(5)
67087f5b87SHeiner Kallweit 
682d8983f9SYuusuke Ashizuka #define RTL9000A_GINMR				0x14
692d8983f9SYuusuke Ashizuka #define RTL9000A_GINMR_LINK_STATUS		BIT(4)
702d8983f9SYuusuke Ashizuka 
71d445dff2SHeiner Kallweit #define RTLGEN_SPEED_MASK			0x0630
72d445dff2SHeiner Kallweit 
735181b473SHeiner Kallweit #define RTL_GENERIC_PHYID			0x001cc800
74bb726b75SClark Wang #define RTL_8211FVD_PHYID			0x001cc878
755181b473SHeiner Kallweit 
76097c2aa8SJohnson Leung MODULE_DESCRIPTION("Realtek PHY driver");
77097c2aa8SJohnson Leung MODULE_AUTHOR("Johnson Leung");
78097c2aa8SJohnson Leung MODULE_LICENSE("GPL");
79097c2aa8SJohnson Leung 
800a4355c2SJoakim Zhang struct rtl821x_priv {
81d90db36aSJoakim Zhang 	u16 phycr1;
820a4355c2SJoakim Zhang 	u16 phycr2;
83bb726b75SClark Wang 	bool has_phycr2;
847300c9b5SDetlev Casanova 	struct clk *clk;
850a4355c2SJoakim Zhang };
860a4355c2SJoakim Zhang 
rtl821x_read_page(struct phy_device * phydev)87d98c8ccdSHeiner Kallweit static int rtl821x_read_page(struct phy_device *phydev)
88136819a6SMartin Blumenstingl {
89d98c8ccdSHeiner Kallweit 	return __phy_read(phydev, RTL821x_PAGE_SELECT);
90136819a6SMartin Blumenstingl }
91136819a6SMartin Blumenstingl 
rtl821x_write_page(struct phy_device * phydev,int page)92d98c8ccdSHeiner Kallweit static int rtl821x_write_page(struct phy_device *phydev, int page)
93136819a6SMartin Blumenstingl {
94d98c8ccdSHeiner Kallweit 	return __phy_write(phydev, RTL821x_PAGE_SELECT, page);
95136819a6SMartin Blumenstingl }
96136819a6SMartin Blumenstingl 
rtl821x_probe(struct phy_device * phydev)970a4355c2SJoakim Zhang static int rtl821x_probe(struct phy_device *phydev)
980a4355c2SJoakim Zhang {
990a4355c2SJoakim Zhang 	struct device *dev = &phydev->mdio.dev;
1000a4355c2SJoakim Zhang 	struct rtl821x_priv *priv;
101bb726b75SClark Wang 	u32 phy_id = phydev->drv->phy_id;
102f25247d8SColin Ian King 	int ret;
1030a4355c2SJoakim Zhang 
1040a4355c2SJoakim Zhang 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1050a4355c2SJoakim Zhang 	if (!priv)
1060a4355c2SJoakim Zhang 		return -ENOMEM;
1070a4355c2SJoakim Zhang 
1087300c9b5SDetlev Casanova 	priv->clk = devm_clk_get_optional_enabled(dev, NULL);
1097300c9b5SDetlev Casanova 	if (IS_ERR(priv->clk))
1107300c9b5SDetlev Casanova 		return dev_err_probe(dev, PTR_ERR(priv->clk),
1117300c9b5SDetlev Casanova 				     "failed to get phy clock\n");
1127300c9b5SDetlev Casanova 
113f25247d8SColin Ian King 	ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR1);
114f25247d8SColin Ian King 	if (ret < 0)
115f25247d8SColin Ian King 		return ret;
116d90db36aSJoakim Zhang 
117f25247d8SColin Ian King 	priv->phycr1 = ret & (RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF);
118d90db36aSJoakim Zhang 	if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
119d90db36aSJoakim Zhang 		priv->phycr1 |= RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF;
120d90db36aSJoakim Zhang 
121bb726b75SClark Wang 	priv->has_phycr2 = !(phy_id == RTL_8211FVD_PHYID);
122bb726b75SClark Wang 	if (priv->has_phycr2) {
123f25247d8SColin Ian King 		ret = phy_read_paged(phydev, 0xa43, RTL8211F_PHYCR2);
124f25247d8SColin Ian King 		if (ret < 0)
125f25247d8SColin Ian King 			return ret;
1260a4355c2SJoakim Zhang 
127f25247d8SColin Ian King 		priv->phycr2 = ret & RTL8211F_CLKOUT_EN;
1280a4355c2SJoakim Zhang 		if (of_property_read_bool(dev->of_node, "realtek,clkout-disable"))
1290a4355c2SJoakim Zhang 			priv->phycr2 &= ~RTL8211F_CLKOUT_EN;
130bb726b75SClark Wang 	}
1310a4355c2SJoakim Zhang 
1320a4355c2SJoakim Zhang 	phydev->priv = priv;
1330a4355c2SJoakim Zhang 
1340a4355c2SJoakim Zhang 	return 0;
1350a4355c2SJoakim Zhang }
1360a4355c2SJoakim Zhang 
rtl8201_ack_interrupt(struct phy_device * phydev)137513588ddSJassi Brar static int rtl8201_ack_interrupt(struct phy_device *phydev)
138513588ddSJassi Brar {
139513588ddSJassi Brar 	int err;
140513588ddSJassi Brar 
141513588ddSJassi Brar 	err = phy_read(phydev, RTL8201F_ISR);
142513588ddSJassi Brar 
143513588ddSJassi Brar 	return (err < 0) ? err : 0;
144513588ddSJassi Brar }
145513588ddSJassi Brar 
rtl821x_ack_interrupt(struct phy_device * phydev)146097c2aa8SJohnson Leung static int rtl821x_ack_interrupt(struct phy_device *phydev)
147097c2aa8SJohnson Leung {
148097c2aa8SJohnson Leung 	int err;
149097c2aa8SJohnson Leung 
150097c2aa8SJohnson Leung 	err = phy_read(phydev, RTL821x_INSR);
151097c2aa8SJohnson Leung 
152097c2aa8SJohnson Leung 	return (err < 0) ? err : 0;
153097c2aa8SJohnson Leung }
154097c2aa8SJohnson Leung 
rtl8211f_ack_interrupt(struct phy_device * phydev)1553447cf2eSShengzhou Liu static int rtl8211f_ack_interrupt(struct phy_device *phydev)
1563447cf2eSShengzhou Liu {
1573447cf2eSShengzhou Liu 	int err;
1583447cf2eSShengzhou Liu 
159d98c8ccdSHeiner Kallweit 	err = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
1603447cf2eSShengzhou Liu 
1613447cf2eSShengzhou Liu 	return (err < 0) ? err : 0;
1623447cf2eSShengzhou Liu }
1633447cf2eSShengzhou Liu 
rtl8201_config_intr(struct phy_device * phydev)164513588ddSJassi Brar static int rtl8201_config_intr(struct phy_device *phydev)
165513588ddSJassi Brar {
166136819a6SMartin Blumenstingl 	u16 val;
1678b43357fSIoana Ciornei 	int err;
168513588ddSJassi Brar 
1698b43357fSIoana Ciornei 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1708b43357fSIoana Ciornei 		err = rtl8201_ack_interrupt(phydev);
1718b43357fSIoana Ciornei 		if (err)
1728b43357fSIoana Ciornei 			return err;
1738b43357fSIoana Ciornei 
174136819a6SMartin Blumenstingl 		val = BIT(13) | BIT(12) | BIT(11);
1758b43357fSIoana Ciornei 		err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
1768b43357fSIoana Ciornei 	} else {
177136819a6SMartin Blumenstingl 		val = 0;
1788b43357fSIoana Ciornei 		err = phy_write_paged(phydev, 0x7, RTL8201F_IER, val);
1798b43357fSIoana Ciornei 		if (err)
1808b43357fSIoana Ciornei 			return err;
181513588ddSJassi Brar 
1828b43357fSIoana Ciornei 		err = rtl8201_ack_interrupt(phydev);
1838b43357fSIoana Ciornei 	}
1848b43357fSIoana Ciornei 
1858b43357fSIoana Ciornei 	return err;
186513588ddSJassi Brar }
187513588ddSJassi Brar 
rtl8211b_config_intr(struct phy_device * phydev)188ef3d9049SGiuseppe CAVALLARO static int rtl8211b_config_intr(struct phy_device *phydev)
189097c2aa8SJohnson Leung {
190097c2aa8SJohnson Leung 	int err;
191097c2aa8SJohnson Leung 
1928b43357fSIoana Ciornei 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
1938b43357fSIoana Ciornei 		err = rtl821x_ack_interrupt(phydev);
1948b43357fSIoana Ciornei 		if (err)
1958b43357fSIoana Ciornei 			return err;
1968b43357fSIoana Ciornei 
197097c2aa8SJohnson Leung 		err = phy_write(phydev, RTL821x_INER,
19869021e32SMartin Blumenstingl 				RTL8211B_INER_INIT);
1998b43357fSIoana Ciornei 	} else {
200097c2aa8SJohnson Leung 		err = phy_write(phydev, RTL821x_INER, 0);
2018b43357fSIoana Ciornei 		if (err)
2028b43357fSIoana Ciornei 			return err;
2038b43357fSIoana Ciornei 
2048b43357fSIoana Ciornei 		err = rtl821x_ack_interrupt(phydev);
2058b43357fSIoana Ciornei 	}
206097c2aa8SJohnson Leung 
207097c2aa8SJohnson Leung 	return err;
208097c2aa8SJohnson Leung }
209097c2aa8SJohnson Leung 
rtl8211e_config_intr(struct phy_device * phydev)210ef3d9049SGiuseppe CAVALLARO static int rtl8211e_config_intr(struct phy_device *phydev)
211ef3d9049SGiuseppe CAVALLARO {
212ef3d9049SGiuseppe CAVALLARO 	int err;
213ef3d9049SGiuseppe CAVALLARO 
2148b43357fSIoana Ciornei 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
2158b43357fSIoana Ciornei 		err = rtl821x_ack_interrupt(phydev);
2168b43357fSIoana Ciornei 		if (err)
2178b43357fSIoana Ciornei 			return err;
2188b43357fSIoana Ciornei 
219ef3d9049SGiuseppe CAVALLARO 		err = phy_write(phydev, RTL821x_INER,
2208b64fd61SGiuseppe CAVALLARO 				RTL8211E_INER_LINK_STATUS);
2218b43357fSIoana Ciornei 	} else {
222ef3d9049SGiuseppe CAVALLARO 		err = phy_write(phydev, RTL821x_INER, 0);
2238b43357fSIoana Ciornei 		if (err)
2248b43357fSIoana Ciornei 			return err;
2258b43357fSIoana Ciornei 
2268b43357fSIoana Ciornei 		err = rtl821x_ack_interrupt(phydev);
2278b43357fSIoana Ciornei 	}
228ef3d9049SGiuseppe CAVALLARO 
229ef3d9049SGiuseppe CAVALLARO 	return err;
230ef3d9049SGiuseppe CAVALLARO }
231ef3d9049SGiuseppe CAVALLARO 
rtl8211f_config_intr(struct phy_device * phydev)2323447cf2eSShengzhou Liu static int rtl8211f_config_intr(struct phy_device *phydev)
2333447cf2eSShengzhou Liu {
234136819a6SMartin Blumenstingl 	u16 val;
2358b43357fSIoana Ciornei 	int err;
2363447cf2eSShengzhou Liu 
2378b43357fSIoana Ciornei 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
2388b43357fSIoana Ciornei 		err = rtl8211f_ack_interrupt(phydev);
2398b43357fSIoana Ciornei 		if (err)
2408b43357fSIoana Ciornei 			return err;
2418b43357fSIoana Ciornei 
242136819a6SMartin Blumenstingl 		val = RTL8211F_INER_LINK_STATUS;
2438b43357fSIoana Ciornei 		err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
2448b43357fSIoana Ciornei 	} else {
245136819a6SMartin Blumenstingl 		val = 0;
2468b43357fSIoana Ciornei 		err = phy_write_paged(phydev, 0xa42, RTL821x_INER, val);
2478b43357fSIoana Ciornei 		if (err)
2488b43357fSIoana Ciornei 			return err;
2493447cf2eSShengzhou Liu 
2508b43357fSIoana Ciornei 		err = rtl8211f_ack_interrupt(phydev);
2518b43357fSIoana Ciornei 	}
2528b43357fSIoana Ciornei 
2538b43357fSIoana Ciornei 	return err;
2543447cf2eSShengzhou Liu }
2553447cf2eSShengzhou Liu 
rtl8201_handle_interrupt(struct phy_device * phydev)25603829163SIoana Ciornei static irqreturn_t rtl8201_handle_interrupt(struct phy_device *phydev)
25703829163SIoana Ciornei {
25803829163SIoana Ciornei 	int irq_status;
25903829163SIoana Ciornei 
26003829163SIoana Ciornei 	irq_status = phy_read(phydev, RTL8201F_ISR);
26103829163SIoana Ciornei 	if (irq_status < 0) {
26203829163SIoana Ciornei 		phy_error(phydev);
26303829163SIoana Ciornei 		return IRQ_NONE;
26403829163SIoana Ciornei 	}
26503829163SIoana Ciornei 
26603829163SIoana Ciornei 	if (!(irq_status & RTL8201F_ISR_MASK))
26703829163SIoana Ciornei 		return IRQ_NONE;
26803829163SIoana Ciornei 
26903829163SIoana Ciornei 	phy_trigger_machine(phydev);
27003829163SIoana Ciornei 
27103829163SIoana Ciornei 	return IRQ_HANDLED;
27203829163SIoana Ciornei }
27303829163SIoana Ciornei 
rtl821x_handle_interrupt(struct phy_device * phydev)27403829163SIoana Ciornei static irqreturn_t rtl821x_handle_interrupt(struct phy_device *phydev)
27503829163SIoana Ciornei {
27603829163SIoana Ciornei 	int irq_status, irq_enabled;
27703829163SIoana Ciornei 
27803829163SIoana Ciornei 	irq_status = phy_read(phydev, RTL821x_INSR);
27903829163SIoana Ciornei 	if (irq_status < 0) {
28003829163SIoana Ciornei 		phy_error(phydev);
28103829163SIoana Ciornei 		return IRQ_NONE;
28203829163SIoana Ciornei 	}
28303829163SIoana Ciornei 
28403829163SIoana Ciornei 	irq_enabled = phy_read(phydev, RTL821x_INER);
28503829163SIoana Ciornei 	if (irq_enabled < 0) {
28603829163SIoana Ciornei 		phy_error(phydev);
28703829163SIoana Ciornei 		return IRQ_NONE;
28803829163SIoana Ciornei 	}
28903829163SIoana Ciornei 
29003829163SIoana Ciornei 	if (!(irq_status & irq_enabled))
29103829163SIoana Ciornei 		return IRQ_NONE;
29203829163SIoana Ciornei 
29303829163SIoana Ciornei 	phy_trigger_machine(phydev);
29403829163SIoana Ciornei 
29503829163SIoana Ciornei 	return IRQ_HANDLED;
29603829163SIoana Ciornei }
29703829163SIoana Ciornei 
rtl8211f_handle_interrupt(struct phy_device * phydev)29803829163SIoana Ciornei static irqreturn_t rtl8211f_handle_interrupt(struct phy_device *phydev)
29903829163SIoana Ciornei {
30003829163SIoana Ciornei 	int irq_status;
30103829163SIoana Ciornei 
30203829163SIoana Ciornei 	irq_status = phy_read_paged(phydev, 0xa43, RTL8211F_INSR);
30303829163SIoana Ciornei 	if (irq_status < 0) {
30403829163SIoana Ciornei 		phy_error(phydev);
30503829163SIoana Ciornei 		return IRQ_NONE;
30603829163SIoana Ciornei 	}
30703829163SIoana Ciornei 
30803829163SIoana Ciornei 	if (!(irq_status & RTL8211F_INER_LINK_STATUS))
30903829163SIoana Ciornei 		return IRQ_NONE;
31003829163SIoana Ciornei 
31103829163SIoana Ciornei 	phy_trigger_machine(phydev);
31203829163SIoana Ciornei 
31303829163SIoana Ciornei 	return IRQ_HANDLED;
31403829163SIoana Ciornei }
31503829163SIoana Ciornei 
rtl8211_config_aneg(struct phy_device * phydev)316d241d4aaSHeiner Kallweit static int rtl8211_config_aneg(struct phy_device *phydev)
317d241d4aaSHeiner Kallweit {
318d241d4aaSHeiner Kallweit 	int ret;
319d241d4aaSHeiner Kallweit 
320d241d4aaSHeiner Kallweit 	ret = genphy_config_aneg(phydev);
321d241d4aaSHeiner Kallweit 	if (ret < 0)
322d241d4aaSHeiner Kallweit 		return ret;
323d241d4aaSHeiner Kallweit 
324d241d4aaSHeiner Kallweit 	/* Quirk was copied from vendor driver. Unfortunately it includes no
325d241d4aaSHeiner Kallweit 	 * description of the magic numbers.
326d241d4aaSHeiner Kallweit 	 */
327d241d4aaSHeiner Kallweit 	if (phydev->speed == SPEED_100 && phydev->autoneg == AUTONEG_DISABLE) {
328d241d4aaSHeiner Kallweit 		phy_write(phydev, 0x17, 0x2138);
329d241d4aaSHeiner Kallweit 		phy_write(phydev, 0x0e, 0x0260);
330d241d4aaSHeiner Kallweit 	} else {
331d241d4aaSHeiner Kallweit 		phy_write(phydev, 0x17, 0x2108);
332d241d4aaSHeiner Kallweit 		phy_write(phydev, 0x0e, 0x0000);
333d241d4aaSHeiner Kallweit 	}
334d241d4aaSHeiner Kallweit 
335d241d4aaSHeiner Kallweit 	return 0;
336d241d4aaSHeiner Kallweit }
337d241d4aaSHeiner Kallweit 
rtl8211c_config_init(struct phy_device * phydev)338cf87915cSHeiner Kallweit static int rtl8211c_config_init(struct phy_device *phydev)
339cf87915cSHeiner Kallweit {
340cf87915cSHeiner Kallweit 	/* RTL8211C has an issue when operating in Gigabit slave mode */
34148e4adf9SHeiner Kallweit 	return phy_set_bits(phydev, MII_CTRL1000,
342cf87915cSHeiner Kallweit 			    CTL1000_ENABLE_MASTER | CTL1000_AS_MASTER);
343cf87915cSHeiner Kallweit }
344cf87915cSHeiner Kallweit 
rtl8211f_config_init(struct phy_device * phydev)3453447cf2eSShengzhou Liu static int rtl8211f_config_init(struct phy_device *phydev)
3463447cf2eSShengzhou Liu {
3470a4355c2SJoakim Zhang 	struct rtl821x_priv *priv = phydev->priv;
3483aec743dSMartin Blumenstingl 	struct device *dev = &phydev->mdio.dev;
3491b3047b5SMartin Blumenstingl 	u16 val_txdly, val_rxdly;
3503aec743dSMartin Blumenstingl 	int ret;
3513447cf2eSShengzhou Liu 
352d90db36aSJoakim Zhang 	ret = phy_modify_paged_changed(phydev, 0xa43, RTL8211F_PHYCR1,
353d90db36aSJoakim Zhang 				       RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_XTAL_OFF,
354d90db36aSJoakim Zhang 				       priv->phycr1);
355d90db36aSJoakim Zhang 	if (ret < 0) {
356d90db36aSJoakim Zhang 		dev_err(dev, "aldps mode  configuration failed: %pe\n",
357d90db36aSJoakim Zhang 			ERR_PTR(ret));
358d90db36aSJoakim Zhang 		return ret;
359d90db36aSJoakim Zhang 	}
36066e22932SJisheng Zhang 
3611da7756eSSerge Semin 	switch (phydev->interface) {
3621da7756eSSerge Semin 	case PHY_INTERFACE_MODE_RGMII:
3631b3047b5SMartin Blumenstingl 		val_txdly = 0;
3641b3047b5SMartin Blumenstingl 		val_rxdly = 0;
3651b3047b5SMartin Blumenstingl 		break;
3661b3047b5SMartin Blumenstingl 
3671da7756eSSerge Semin 	case PHY_INTERFACE_MODE_RGMII_RXID:
3681b3047b5SMartin Blumenstingl 		val_txdly = 0;
3691b3047b5SMartin Blumenstingl 		val_rxdly = RTL8211F_RX_DELAY;
3701da7756eSSerge Semin 		break;
3711b3047b5SMartin Blumenstingl 
3721da7756eSSerge Semin 	case PHY_INTERFACE_MODE_RGMII_TXID:
3731b3047b5SMartin Blumenstingl 		val_txdly = RTL8211F_TX_DELAY;
3741b3047b5SMartin Blumenstingl 		val_rxdly = 0;
3751da7756eSSerge Semin 		break;
3761b3047b5SMartin Blumenstingl 
3771b3047b5SMartin Blumenstingl 	case PHY_INTERFACE_MODE_RGMII_ID:
3781b3047b5SMartin Blumenstingl 		val_txdly = RTL8211F_TX_DELAY;
3791b3047b5SMartin Blumenstingl 		val_rxdly = RTL8211F_RX_DELAY;
3801b3047b5SMartin Blumenstingl 		break;
3811b3047b5SMartin Blumenstingl 
3821da7756eSSerge Semin 	default: /* the rest of the modes imply leaving delay as is. */
3831da7756eSSerge Semin 		return 0;
3841da7756eSSerge Semin 	}
385e3230494SMartin Blumenstingl 
3863aec743dSMartin Blumenstingl 	ret = phy_modify_paged_changed(phydev, 0xd08, 0x11, RTL8211F_TX_DELAY,
3871b3047b5SMartin Blumenstingl 				       val_txdly);
3883aec743dSMartin Blumenstingl 	if (ret < 0) {
3893aec743dSMartin Blumenstingl 		dev_err(dev, "Failed to update the TX delay register\n");
3903aec743dSMartin Blumenstingl 		return ret;
3913aec743dSMartin Blumenstingl 	} else if (ret) {
3923aec743dSMartin Blumenstingl 		dev_dbg(dev,
3933aec743dSMartin Blumenstingl 			"%s 2ns TX delay (and changing the value from pin-strapping RXD1 or the bootloader)\n",
3941b3047b5SMartin Blumenstingl 			val_txdly ? "Enabling" : "Disabling");
3953aec743dSMartin Blumenstingl 	} else {
3963aec743dSMartin Blumenstingl 		dev_dbg(dev,
3973aec743dSMartin Blumenstingl 			"2ns TX delay was already %s (by pin-strapping RXD1 or bootloader configuration)\n",
3981b3047b5SMartin Blumenstingl 			val_txdly ? "enabled" : "disabled");
3991b3047b5SMartin Blumenstingl 	}
4001b3047b5SMartin Blumenstingl 
4011b3047b5SMartin Blumenstingl 	ret = phy_modify_paged_changed(phydev, 0xd08, 0x15, RTL8211F_RX_DELAY,
4021b3047b5SMartin Blumenstingl 				       val_rxdly);
4031b3047b5SMartin Blumenstingl 	if (ret < 0) {
4041b3047b5SMartin Blumenstingl 		dev_err(dev, "Failed to update the RX delay register\n");
4051b3047b5SMartin Blumenstingl 		return ret;
4061b3047b5SMartin Blumenstingl 	} else if (ret) {
4071b3047b5SMartin Blumenstingl 		dev_dbg(dev,
4081b3047b5SMartin Blumenstingl 			"%s 2ns RX delay (and changing the value from pin-strapping RXD0 or the bootloader)\n",
4091b3047b5SMartin Blumenstingl 			val_rxdly ? "Enabling" : "Disabling");
4101b3047b5SMartin Blumenstingl 	} else {
4111b3047b5SMartin Blumenstingl 		dev_dbg(dev,
4121b3047b5SMartin Blumenstingl 			"2ns RX delay was already %s (by pin-strapping RXD0 or bootloader configuration)\n",
4131b3047b5SMartin Blumenstingl 			val_rxdly ? "enabled" : "disabled");
4143aec743dSMartin Blumenstingl 	}
4153aec743dSMartin Blumenstingl 
416bb726b75SClark Wang 	if (priv->has_phycr2) {
4170a4355c2SJoakim Zhang 		ret = phy_modify_paged(phydev, 0xa43, RTL8211F_PHYCR2,
4180a4355c2SJoakim Zhang 				       RTL8211F_CLKOUT_EN, priv->phycr2);
4190a4355c2SJoakim Zhang 		if (ret < 0) {
4200a4355c2SJoakim Zhang 			dev_err(dev, "clkout configuration failed: %pe\n",
4210a4355c2SJoakim Zhang 				ERR_PTR(ret));
4220a4355c2SJoakim Zhang 			return ret;
4230a4355c2SJoakim Zhang 		}
4240a4355c2SJoakim Zhang 
4250a4355c2SJoakim Zhang 		return genphy_soft_reset(phydev);
4263447cf2eSShengzhou Liu 	}
4273447cf2eSShengzhou Liu 
428c7818378SSiddharth Vadapalli 	return 0;
429c7818378SSiddharth Vadapalli }
430c7818378SSiddharth Vadapalli 
rtl821x_suspend(struct phy_device * phydev)43159e227e2SDetlev Casanova static int rtl821x_suspend(struct phy_device *phydev)
43259e227e2SDetlev Casanova {
43359e227e2SDetlev Casanova 	struct rtl821x_priv *priv = phydev->priv;
43459e227e2SDetlev Casanova 	int ret = 0;
43559e227e2SDetlev Casanova 
43659e227e2SDetlev Casanova 	if (!phydev->wol_enabled) {
43759e227e2SDetlev Casanova 		ret = genphy_suspend(phydev);
43859e227e2SDetlev Casanova 
43959e227e2SDetlev Casanova 		if (ret)
44059e227e2SDetlev Casanova 			return ret;
44159e227e2SDetlev Casanova 
44259e227e2SDetlev Casanova 		clk_disable_unprepare(priv->clk);
44359e227e2SDetlev Casanova 	}
44459e227e2SDetlev Casanova 
44559e227e2SDetlev Casanova 	return ret;
44659e227e2SDetlev Casanova }
44759e227e2SDetlev Casanova 
rtl821x_resume(struct phy_device * phydev)4486813cc8cSJoakim Zhang static int rtl821x_resume(struct phy_device *phydev)
4496813cc8cSJoakim Zhang {
45059e227e2SDetlev Casanova 	struct rtl821x_priv *priv = phydev->priv;
4516813cc8cSJoakim Zhang 	int ret;
4526813cc8cSJoakim Zhang 
45359e227e2SDetlev Casanova 	if (!phydev->wol_enabled)
45459e227e2SDetlev Casanova 		clk_prepare_enable(priv->clk);
45559e227e2SDetlev Casanova 
4566813cc8cSJoakim Zhang 	ret = genphy_resume(phydev);
4576813cc8cSJoakim Zhang 	if (ret < 0)
4586813cc8cSJoakim Zhang 		return ret;
4596813cc8cSJoakim Zhang 
4606813cc8cSJoakim Zhang 	msleep(20);
4616813cc8cSJoakim Zhang 
4626813cc8cSJoakim Zhang 	return 0;
4636813cc8cSJoakim Zhang }
4646813cc8cSJoakim Zhang 
rtl8211e_config_init(struct phy_device * phydev)465f81dadbcSSerge Semin static int rtl8211e_config_init(struct phy_device *phydev)
466f81dadbcSSerge Semin {
467f81dadbcSSerge Semin 	int ret = 0, oldpage;
468f81dadbcSSerge Semin 	u16 val;
469f81dadbcSSerge Semin 
470f81dadbcSSerge Semin 	/* enable TX/RX delay for rgmii-* modes, and disable them for rgmii. */
471f81dadbcSSerge Semin 	switch (phydev->interface) {
472f81dadbcSSerge Semin 	case PHY_INTERFACE_MODE_RGMII:
473bbc4d71dSWilly Liu 		val = RTL8211E_CTRL_DELAY | 0;
474f81dadbcSSerge Semin 		break;
475f81dadbcSSerge Semin 	case PHY_INTERFACE_MODE_RGMII_ID:
476bbc4d71dSWilly Liu 		val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY;
477f81dadbcSSerge Semin 		break;
478f81dadbcSSerge Semin 	case PHY_INTERFACE_MODE_RGMII_RXID:
479bbc4d71dSWilly Liu 		val = RTL8211E_CTRL_DELAY | RTL8211E_RX_DELAY;
480f81dadbcSSerge Semin 		break;
481f81dadbcSSerge Semin 	case PHY_INTERFACE_MODE_RGMII_TXID:
482bbc4d71dSWilly Liu 		val = RTL8211E_CTRL_DELAY | RTL8211E_TX_DELAY;
483f81dadbcSSerge Semin 		break;
484f81dadbcSSerge Semin 	default: /* the rest of the modes imply leaving delays as is. */
485f81dadbcSSerge Semin 		return 0;
486f81dadbcSSerge Semin 	}
487f81dadbcSSerge Semin 
488f81dadbcSSerge Semin 	/* According to a sample driver there is a 0x1c config register on the
489f81dadbcSSerge Semin 	 * 0xa4 extension page (0x7) layout. It can be used to disable/enable
490bbc4d71dSWilly Liu 	 * the RX/TX delays otherwise controlled by RXDLY/TXDLY pins.
491bbc4d71dSWilly Liu 	 * The configuration register definition:
492bbc4d71dSWilly Liu 	 * 14 = reserved
493bbc4d71dSWilly Liu 	 * 13 = Force Tx RX Delay controlled by bit12 bit11,
494bbc4d71dSWilly Liu 	 * 12 = RX Delay, 11 = TX Delay
495bbc4d71dSWilly Liu 	 * 10:0 = Test && debug settings reserved by realtek
496f81dadbcSSerge Semin 	 */
497f81dadbcSSerge Semin 	oldpage = phy_select_page(phydev, 0x7);
498f81dadbcSSerge Semin 	if (oldpage < 0)
499f81dadbcSSerge Semin 		goto err_restore_page;
500f81dadbcSSerge Semin 
501dffe7d2eSKunihiko Hayashi 	ret = __phy_write(phydev, RTL821x_EXT_PAGE_SELECT, 0xa4);
502f81dadbcSSerge Semin 	if (ret)
503f81dadbcSSerge Semin 		goto err_restore_page;
504f81dadbcSSerge Semin 
505bbc4d71dSWilly Liu 	ret = __phy_modify(phydev, 0x1c, RTL8211E_CTRL_DELAY
506bbc4d71dSWilly Liu 			   | RTL8211E_TX_DELAY | RTL8211E_RX_DELAY,
507f81dadbcSSerge Semin 			   val);
508f81dadbcSSerge Semin 
509f81dadbcSSerge Semin err_restore_page:
510f81dadbcSSerge Semin 	return phy_restore_page(phydev, oldpage, ret);
511f81dadbcSSerge Semin }
512f81dadbcSSerge Semin 
rtl8211b_suspend(struct phy_device * phydev)513049ff57aSHeiner Kallweit static int rtl8211b_suspend(struct phy_device *phydev)
514049ff57aSHeiner Kallweit {
515049ff57aSHeiner Kallweit 	phy_write(phydev, MII_MMD_DATA, BIT(9));
516049ff57aSHeiner Kallweit 
517049ff57aSHeiner Kallweit 	return genphy_suspend(phydev);
518049ff57aSHeiner Kallweit }
519049ff57aSHeiner Kallweit 
rtl8211b_resume(struct phy_device * phydev)520049ff57aSHeiner Kallweit static int rtl8211b_resume(struct phy_device *phydev)
521049ff57aSHeiner Kallweit {
522049ff57aSHeiner Kallweit 	phy_write(phydev, MII_MMD_DATA, 0);
523049ff57aSHeiner Kallweit 
524049ff57aSHeiner Kallweit 	return genphy_resume(phydev);
525049ff57aSHeiner Kallweit }
526049ff57aSHeiner Kallweit 
rtl8366rb_config_init(struct phy_device * phydev)527d8545825SLinus Walleij static int rtl8366rb_config_init(struct phy_device *phydev)
528d8545825SLinus Walleij {
529d8545825SLinus Walleij 	int ret;
530d8545825SLinus Walleij 
531d8545825SLinus Walleij 	ret = phy_set_bits(phydev, RTL8366RB_POWER_SAVE,
532d8545825SLinus Walleij 			   RTL8366RB_POWER_SAVE_ON);
533d8545825SLinus Walleij 	if (ret) {
534d8545825SLinus Walleij 		dev_err(&phydev->mdio.dev,
535d8545825SLinus Walleij 			"error enabling power management\n");
536d8545825SLinus Walleij 	}
537d8545825SLinus Walleij 
538d8545825SLinus Walleij 	return ret;
539d8545825SLinus Walleij }
540d8545825SLinus Walleij 
541d445dff2SHeiner Kallweit /* get actual speed to cover the downshift case */
rtlgen_get_speed(struct phy_device * phydev)542d445dff2SHeiner Kallweit static int rtlgen_get_speed(struct phy_device *phydev)
543d445dff2SHeiner Kallweit {
544d445dff2SHeiner Kallweit 	int val;
545d445dff2SHeiner Kallweit 
546d445dff2SHeiner Kallweit 	if (!phydev->link)
547d445dff2SHeiner Kallweit 		return 0;
548d445dff2SHeiner Kallweit 
549d445dff2SHeiner Kallweit 	val = phy_read_paged(phydev, 0xa43, 0x12);
550d445dff2SHeiner Kallweit 	if (val < 0)
551d445dff2SHeiner Kallweit 		return val;
552d445dff2SHeiner Kallweit 
553d445dff2SHeiner Kallweit 	switch (val & RTLGEN_SPEED_MASK) {
554d445dff2SHeiner Kallweit 	case 0x0000:
555d445dff2SHeiner Kallweit 		phydev->speed = SPEED_10;
556d445dff2SHeiner Kallweit 		break;
557d445dff2SHeiner Kallweit 	case 0x0010:
558d445dff2SHeiner Kallweit 		phydev->speed = SPEED_100;
559d445dff2SHeiner Kallweit 		break;
560d445dff2SHeiner Kallweit 	case 0x0020:
561d445dff2SHeiner Kallweit 		phydev->speed = SPEED_1000;
562d445dff2SHeiner Kallweit 		break;
563d445dff2SHeiner Kallweit 	case 0x0200:
564d445dff2SHeiner Kallweit 		phydev->speed = SPEED_10000;
565d445dff2SHeiner Kallweit 		break;
566d445dff2SHeiner Kallweit 	case 0x0210:
567d445dff2SHeiner Kallweit 		phydev->speed = SPEED_2500;
568d445dff2SHeiner Kallweit 		break;
569d445dff2SHeiner Kallweit 	case 0x0220:
570d445dff2SHeiner Kallweit 		phydev->speed = SPEED_5000;
571d445dff2SHeiner Kallweit 		break;
572d445dff2SHeiner Kallweit 	default:
573d445dff2SHeiner Kallweit 		break;
574d445dff2SHeiner Kallweit 	}
575d445dff2SHeiner Kallweit 
576d445dff2SHeiner Kallweit 	return 0;
577d445dff2SHeiner Kallweit }
578d445dff2SHeiner Kallweit 
rtlgen_read_status(struct phy_device * phydev)579d445dff2SHeiner Kallweit static int rtlgen_read_status(struct phy_device *phydev)
580d445dff2SHeiner Kallweit {
581d445dff2SHeiner Kallweit 	int ret;
582d445dff2SHeiner Kallweit 
583d445dff2SHeiner Kallweit 	ret = genphy_read_status(phydev);
584d445dff2SHeiner Kallweit 	if (ret < 0)
585d445dff2SHeiner Kallweit 		return ret;
586d445dff2SHeiner Kallweit 
587d445dff2SHeiner Kallweit 	return rtlgen_get_speed(phydev);
588d445dff2SHeiner Kallweit }
589d445dff2SHeiner Kallweit 
rtlgen_read_mmd(struct phy_device * phydev,int devnum,u16 regnum)5905b3f1395SHeiner Kallweit static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
5915b3f1395SHeiner Kallweit {
5925b3f1395SHeiner Kallweit 	int ret;
5935b3f1395SHeiner Kallweit 
5945b3f1395SHeiner Kallweit 	if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
5955b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa5c);
5965b3f1395SHeiner Kallweit 		ret = __phy_read(phydev, 0x12);
5975b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
5985b3f1395SHeiner Kallweit 	} else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
5995b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa5d);
6005b3f1395SHeiner Kallweit 		ret = __phy_read(phydev, 0x10);
6015b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
6025b3f1395SHeiner Kallweit 	} else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) {
6035b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa5d);
6045b3f1395SHeiner Kallweit 		ret = __phy_read(phydev, 0x11);
6055b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
6065b3f1395SHeiner Kallweit 	} else {
6075b3f1395SHeiner Kallweit 		ret = -EOPNOTSUPP;
6085b3f1395SHeiner Kallweit 	}
6095b3f1395SHeiner Kallweit 
6105b3f1395SHeiner Kallweit 	return ret;
6115b3f1395SHeiner Kallweit }
6125b3f1395SHeiner Kallweit 
rtlgen_write_mmd(struct phy_device * phydev,int devnum,u16 regnum,u16 val)6135b3f1395SHeiner Kallweit static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
6145b3f1395SHeiner Kallweit 			    u16 val)
6155b3f1395SHeiner Kallweit {
6165b3f1395SHeiner Kallweit 	int ret;
6175b3f1395SHeiner Kallweit 
6185b3f1395SHeiner Kallweit 	if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
6195b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa5d);
6205b3f1395SHeiner Kallweit 		ret = __phy_write(phydev, 0x10, val);
6215b3f1395SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
6225b3f1395SHeiner Kallweit 	} else {
6235b3f1395SHeiner Kallweit 		ret = -EOPNOTSUPP;
6245b3f1395SHeiner Kallweit 	}
6255b3f1395SHeiner Kallweit 
6265b3f1395SHeiner Kallweit 	return ret;
6275b3f1395SHeiner Kallweit }
6285b3f1395SHeiner Kallweit 
rtl822x_read_mmd(struct phy_device * phydev,int devnum,u16 regnum)6297a333af6SWilly Liu static int rtl822x_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
630edde25e5SHeiner Kallweit {
631edde25e5SHeiner Kallweit 	int ret = rtlgen_read_mmd(phydev, devnum, regnum);
632edde25e5SHeiner Kallweit 
633edde25e5SHeiner Kallweit 	if (ret != -EOPNOTSUPP)
634edde25e5SHeiner Kallweit 		return ret;
635edde25e5SHeiner Kallweit 
636edde25e5SHeiner Kallweit 	if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE2) {
637edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa6e);
638edde25e5SHeiner Kallweit 		ret = __phy_read(phydev, 0x16);
639edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
640edde25e5SHeiner Kallweit 	} else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
641edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa6d);
642edde25e5SHeiner Kallweit 		ret = __phy_read(phydev, 0x12);
643edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
644edde25e5SHeiner Kallweit 	} else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE2) {
645edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa6d);
646edde25e5SHeiner Kallweit 		ret = __phy_read(phydev, 0x10);
647edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
648edde25e5SHeiner Kallweit 	}
649edde25e5SHeiner Kallweit 
650edde25e5SHeiner Kallweit 	return ret;
651edde25e5SHeiner Kallweit }
652edde25e5SHeiner Kallweit 
rtl822x_write_mmd(struct phy_device * phydev,int devnum,u16 regnum,u16 val)6537a333af6SWilly Liu static int rtl822x_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
654edde25e5SHeiner Kallweit 			     u16 val)
655edde25e5SHeiner Kallweit {
656edde25e5SHeiner Kallweit 	int ret = rtlgen_write_mmd(phydev, devnum, regnum, val);
657edde25e5SHeiner Kallweit 
658edde25e5SHeiner Kallweit 	if (ret != -EOPNOTSUPP)
659edde25e5SHeiner Kallweit 		return ret;
660edde25e5SHeiner Kallweit 
661edde25e5SHeiner Kallweit 	if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV2) {
662edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0xa6d);
663edde25e5SHeiner Kallweit 		ret = __phy_write(phydev, 0x12, val);
664edde25e5SHeiner Kallweit 		rtl821x_write_page(phydev, 0);
665edde25e5SHeiner Kallweit 	}
666edde25e5SHeiner Kallweit 
667edde25e5SHeiner Kallweit 	return ret;
668edde25e5SHeiner Kallweit }
669edde25e5SHeiner Kallweit 
rtl822x_get_features(struct phy_device * phydev)6707a333af6SWilly Liu static int rtl822x_get_features(struct phy_device *phydev)
671087f5b87SHeiner Kallweit {
6725181b473SHeiner Kallweit 	int val;
6735181b473SHeiner Kallweit 
6745181b473SHeiner Kallweit 	val = phy_read_paged(phydev, 0xa61, 0x13);
6755181b473SHeiner Kallweit 	if (val < 0)
6765181b473SHeiner Kallweit 		return val;
6775181b473SHeiner Kallweit 
6785181b473SHeiner Kallweit 	linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
6795181b473SHeiner Kallweit 			 phydev->supported, val & RTL_SUPPORTS_2500FULL);
6805181b473SHeiner Kallweit 	linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
6815181b473SHeiner Kallweit 			 phydev->supported, val & RTL_SUPPORTS_5000FULL);
6825181b473SHeiner Kallweit 	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
6835181b473SHeiner Kallweit 			 phydev->supported, val & RTL_SUPPORTS_10000FULL);
684087f5b87SHeiner Kallweit 
685087f5b87SHeiner Kallweit 	return genphy_read_abilities(phydev);
686087f5b87SHeiner Kallweit }
687087f5b87SHeiner Kallweit 
rtl822x_config_aneg(struct phy_device * phydev)6887a333af6SWilly Liu static int rtl822x_config_aneg(struct phy_device *phydev)
689087f5b87SHeiner Kallweit {
690087f5b87SHeiner Kallweit 	int ret = 0;
691087f5b87SHeiner Kallweit 
692087f5b87SHeiner Kallweit 	if (phydev->autoneg == AUTONEG_ENABLE) {
693087f5b87SHeiner Kallweit 		u16 adv2500 = 0;
694087f5b87SHeiner Kallweit 
695087f5b87SHeiner Kallweit 		if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
696087f5b87SHeiner Kallweit 				      phydev->advertising))
697087f5b87SHeiner Kallweit 			adv2500 = RTL_ADV_2500FULL;
698087f5b87SHeiner Kallweit 
699087f5b87SHeiner Kallweit 		ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
700087f5b87SHeiner Kallweit 					       RTL_ADV_2500FULL, adv2500);
701087f5b87SHeiner Kallweit 		if (ret < 0)
702087f5b87SHeiner Kallweit 			return ret;
703087f5b87SHeiner Kallweit 	}
704087f5b87SHeiner Kallweit 
705087f5b87SHeiner Kallweit 	return __genphy_config_aneg(phydev, ret);
706087f5b87SHeiner Kallweit }
707087f5b87SHeiner Kallweit 
rtl822x_read_status(struct phy_device * phydev)7087a333af6SWilly Liu static int rtl822x_read_status(struct phy_device *phydev)
709087f5b87SHeiner Kallweit {
710d445dff2SHeiner Kallweit 	int ret;
711d445dff2SHeiner Kallweit 
712087f5b87SHeiner Kallweit 	if (phydev->autoneg == AUTONEG_ENABLE) {
713087f5b87SHeiner Kallweit 		int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
714087f5b87SHeiner Kallweit 
715087f5b87SHeiner Kallweit 		if (lpadv < 0)
716087f5b87SHeiner Kallweit 			return lpadv;
717087f5b87SHeiner Kallweit 
718087f5b87SHeiner Kallweit 		linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
719087f5b87SHeiner Kallweit 			phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL);
720087f5b87SHeiner Kallweit 		linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
721087f5b87SHeiner Kallweit 			phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL);
722087f5b87SHeiner Kallweit 		linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
723087f5b87SHeiner Kallweit 			phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
724087f5b87SHeiner Kallweit 	}
725087f5b87SHeiner Kallweit 
726d445dff2SHeiner Kallweit 	ret = genphy_read_status(phydev);
727d445dff2SHeiner Kallweit 	if (ret < 0)
728d445dff2SHeiner Kallweit 		return ret;
729d445dff2SHeiner Kallweit 
730d445dff2SHeiner Kallweit 	return rtlgen_get_speed(phydev);
731087f5b87SHeiner Kallweit }
732087f5b87SHeiner Kallweit 
rtlgen_supports_2_5gbps(struct phy_device * phydev)7335181b473SHeiner Kallweit static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
7345181b473SHeiner Kallweit {
7355181b473SHeiner Kallweit 	int val;
7365181b473SHeiner Kallweit 
7375181b473SHeiner Kallweit 	phy_write(phydev, RTL821x_PAGE_SELECT, 0xa61);
7385181b473SHeiner Kallweit 	val = phy_read(phydev, 0x13);
7395181b473SHeiner Kallweit 	phy_write(phydev, RTL821x_PAGE_SELECT, 0);
7405181b473SHeiner Kallweit 
7415181b473SHeiner Kallweit 	return val >= 0 && val & RTL_SUPPORTS_2500FULL;
7425181b473SHeiner Kallweit }
7435181b473SHeiner Kallweit 
rtlgen_match_phy_device(struct phy_device * phydev)7445181b473SHeiner Kallweit static int rtlgen_match_phy_device(struct phy_device *phydev)
7455181b473SHeiner Kallweit {
7465181b473SHeiner Kallweit 	return phydev->phy_id == RTL_GENERIC_PHYID &&
7475181b473SHeiner Kallweit 	       !rtlgen_supports_2_5gbps(phydev);
7485181b473SHeiner Kallweit }
7495181b473SHeiner Kallweit 
rtl8226_match_phy_device(struct phy_device * phydev)7507a333af6SWilly Liu static int rtl8226_match_phy_device(struct phy_device *phydev)
7515181b473SHeiner Kallweit {
7525181b473SHeiner Kallweit 	return phydev->phy_id == RTL_GENERIC_PHYID &&
7535181b473SHeiner Kallweit 	       rtlgen_supports_2_5gbps(phydev);
7545181b473SHeiner Kallweit }
7555181b473SHeiner Kallweit 
rtlgen_resume(struct phy_device * phydev)756fee698d6SHeiner Kallweit static int rtlgen_resume(struct phy_device *phydev)
757fee698d6SHeiner Kallweit {
758fee698d6SHeiner Kallweit 	int ret = genphy_resume(phydev);
759fee698d6SHeiner Kallweit 
760fee698d6SHeiner Kallweit 	/* Internal PHY's from RTL8168h up may not be instantly ready */
761fee698d6SHeiner Kallweit 	msleep(20);
762fee698d6SHeiner Kallweit 
763fee698d6SHeiner Kallweit 	return ret;
764fee698d6SHeiner Kallweit }
765fee698d6SHeiner Kallweit 
rtl9000a_config_init(struct phy_device * phydev)7662d8983f9SYuusuke Ashizuka static int rtl9000a_config_init(struct phy_device *phydev)
7672d8983f9SYuusuke Ashizuka {
7682d8983f9SYuusuke Ashizuka 	phydev->autoneg = AUTONEG_DISABLE;
7692d8983f9SYuusuke Ashizuka 	phydev->speed = SPEED_100;
7702d8983f9SYuusuke Ashizuka 	phydev->duplex = DUPLEX_FULL;
7712d8983f9SYuusuke Ashizuka 
7722d8983f9SYuusuke Ashizuka 	return 0;
7732d8983f9SYuusuke Ashizuka }
7742d8983f9SYuusuke Ashizuka 
rtl9000a_config_aneg(struct phy_device * phydev)7752d8983f9SYuusuke Ashizuka static int rtl9000a_config_aneg(struct phy_device *phydev)
7762d8983f9SYuusuke Ashizuka {
7772d8983f9SYuusuke Ashizuka 	int ret;
7782d8983f9SYuusuke Ashizuka 	u16 ctl = 0;
7792d8983f9SYuusuke Ashizuka 
7802d8983f9SYuusuke Ashizuka 	switch (phydev->master_slave_set) {
7812d8983f9SYuusuke Ashizuka 	case MASTER_SLAVE_CFG_MASTER_FORCE:
7822d8983f9SYuusuke Ashizuka 		ctl |= CTL1000_AS_MASTER;
7832d8983f9SYuusuke Ashizuka 		break;
7842d8983f9SYuusuke Ashizuka 	case MASTER_SLAVE_CFG_SLAVE_FORCE:
7852d8983f9SYuusuke Ashizuka 		break;
7862d8983f9SYuusuke Ashizuka 	case MASTER_SLAVE_CFG_UNKNOWN:
7872d8983f9SYuusuke Ashizuka 	case MASTER_SLAVE_CFG_UNSUPPORTED:
7882d8983f9SYuusuke Ashizuka 		return 0;
7892d8983f9SYuusuke Ashizuka 	default:
7902d8983f9SYuusuke Ashizuka 		phydev_warn(phydev, "Unsupported Master/Slave mode\n");
7912d8983f9SYuusuke Ashizuka 		return -EOPNOTSUPP;
7922d8983f9SYuusuke Ashizuka 	}
7932d8983f9SYuusuke Ashizuka 
7942d8983f9SYuusuke Ashizuka 	ret = phy_modify_changed(phydev, MII_CTRL1000, CTL1000_AS_MASTER, ctl);
7952d8983f9SYuusuke Ashizuka 	if (ret == 1)
7962d8983f9SYuusuke Ashizuka 		ret = genphy_soft_reset(phydev);
7972d8983f9SYuusuke Ashizuka 
7982d8983f9SYuusuke Ashizuka 	return ret;
7992d8983f9SYuusuke Ashizuka }
8002d8983f9SYuusuke Ashizuka 
rtl9000a_read_status(struct phy_device * phydev)8012d8983f9SYuusuke Ashizuka static int rtl9000a_read_status(struct phy_device *phydev)
8022d8983f9SYuusuke Ashizuka {
8032d8983f9SYuusuke Ashizuka 	int ret;
8042d8983f9SYuusuke Ashizuka 
8052d8983f9SYuusuke Ashizuka 	phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
8062d8983f9SYuusuke Ashizuka 	phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
8072d8983f9SYuusuke Ashizuka 
8082d8983f9SYuusuke Ashizuka 	ret = genphy_update_link(phydev);
8092d8983f9SYuusuke Ashizuka 	if (ret)
8102d8983f9SYuusuke Ashizuka 		return ret;
8112d8983f9SYuusuke Ashizuka 
8122d8983f9SYuusuke Ashizuka 	ret = phy_read(phydev, MII_CTRL1000);
8132d8983f9SYuusuke Ashizuka 	if (ret < 0)
8142d8983f9SYuusuke Ashizuka 		return ret;
8152d8983f9SYuusuke Ashizuka 	if (ret & CTL1000_AS_MASTER)
8162d8983f9SYuusuke Ashizuka 		phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
8172d8983f9SYuusuke Ashizuka 	else
8182d8983f9SYuusuke Ashizuka 		phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
8192d8983f9SYuusuke Ashizuka 
8202d8983f9SYuusuke Ashizuka 	ret = phy_read(phydev, MII_STAT1000);
8212d8983f9SYuusuke Ashizuka 	if (ret < 0)
8222d8983f9SYuusuke Ashizuka 		return ret;
8232d8983f9SYuusuke Ashizuka 	if (ret & LPA_1000MSRES)
8242d8983f9SYuusuke Ashizuka 		phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
8252d8983f9SYuusuke Ashizuka 	else
8262d8983f9SYuusuke Ashizuka 		phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
8272d8983f9SYuusuke Ashizuka 
8282d8983f9SYuusuke Ashizuka 	return 0;
8292d8983f9SYuusuke Ashizuka }
8302d8983f9SYuusuke Ashizuka 
rtl9000a_ack_interrupt(struct phy_device * phydev)8312d8983f9SYuusuke Ashizuka static int rtl9000a_ack_interrupt(struct phy_device *phydev)
8322d8983f9SYuusuke Ashizuka {
8332d8983f9SYuusuke Ashizuka 	int err;
8342d8983f9SYuusuke Ashizuka 
8352d8983f9SYuusuke Ashizuka 	err = phy_read(phydev, RTL8211F_INSR);
8362d8983f9SYuusuke Ashizuka 
8372d8983f9SYuusuke Ashizuka 	return (err < 0) ? err : 0;
8382d8983f9SYuusuke Ashizuka }
8392d8983f9SYuusuke Ashizuka 
rtl9000a_config_intr(struct phy_device * phydev)8402d8983f9SYuusuke Ashizuka static int rtl9000a_config_intr(struct phy_device *phydev)
8412d8983f9SYuusuke Ashizuka {
8422d8983f9SYuusuke Ashizuka 	u16 val;
8432d8983f9SYuusuke Ashizuka 	int err;
8442d8983f9SYuusuke Ashizuka 
8452d8983f9SYuusuke Ashizuka 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
8462d8983f9SYuusuke Ashizuka 		err = rtl9000a_ack_interrupt(phydev);
8472d8983f9SYuusuke Ashizuka 		if (err)
8482d8983f9SYuusuke Ashizuka 			return err;
8492d8983f9SYuusuke Ashizuka 
8502d8983f9SYuusuke Ashizuka 		val = (u16)~RTL9000A_GINMR_LINK_STATUS;
8512d8983f9SYuusuke Ashizuka 		err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
8522d8983f9SYuusuke Ashizuka 	} else {
8532d8983f9SYuusuke Ashizuka 		val = ~0;
8542d8983f9SYuusuke Ashizuka 		err = phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
8552d8983f9SYuusuke Ashizuka 		if (err)
8562d8983f9SYuusuke Ashizuka 			return err;
8572d8983f9SYuusuke Ashizuka 
8582d8983f9SYuusuke Ashizuka 		err = rtl9000a_ack_interrupt(phydev);
8592d8983f9SYuusuke Ashizuka 	}
8602d8983f9SYuusuke Ashizuka 
8612d8983f9SYuusuke Ashizuka 	return phy_write_paged(phydev, 0xa42, RTL9000A_GINMR, val);
8622d8983f9SYuusuke Ashizuka }
8632d8983f9SYuusuke Ashizuka 
rtl9000a_handle_interrupt(struct phy_device * phydev)8642d8983f9SYuusuke Ashizuka static irqreturn_t rtl9000a_handle_interrupt(struct phy_device *phydev)
8652d8983f9SYuusuke Ashizuka {
8662d8983f9SYuusuke Ashizuka 	int irq_status;
8672d8983f9SYuusuke Ashizuka 
8682d8983f9SYuusuke Ashizuka 	irq_status = phy_read(phydev, RTL8211F_INSR);
8692d8983f9SYuusuke Ashizuka 	if (irq_status < 0) {
8702d8983f9SYuusuke Ashizuka 		phy_error(phydev);
8712d8983f9SYuusuke Ashizuka 		return IRQ_NONE;
8722d8983f9SYuusuke Ashizuka 	}
8732d8983f9SYuusuke Ashizuka 
8742d8983f9SYuusuke Ashizuka 	if (!(irq_status & RTL8211F_INER_LINK_STATUS))
8752d8983f9SYuusuke Ashizuka 		return IRQ_NONE;
8762d8983f9SYuusuke Ashizuka 
8772d8983f9SYuusuke Ashizuka 	phy_trigger_machine(phydev);
8782d8983f9SYuusuke Ashizuka 
8792d8983f9SYuusuke Ashizuka 	return IRQ_HANDLED;
8802d8983f9SYuusuke Ashizuka }
8812d8983f9SYuusuke Ashizuka 
88271b9c4a8SJongsung Kim static struct phy_driver realtek_drvs[] = {
88371b9c4a8SJongsung Kim 	{
884ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x00008201),
88512959667SJonas Jensen 		.name           = "RTL8201CP Ethernet",
886f3037c5aSHeiner Kallweit 		.read_page	= rtl821x_read_page,
887f3037c5aSHeiner Kallweit 		.write_page	= rtl821x_write_page,
88871b9c4a8SJongsung Kim 	}, {
889ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc816),
8900432e833SHolger Hoffstätte 		.name		= "RTL8201F Fast Ethernet",
891513588ddSJassi Brar 		.config_intr	= &rtl8201_config_intr,
89203829163SIoana Ciornei 		.handle_interrupt = rtl8201_handle_interrupt,
893513588ddSJassi Brar 		.suspend	= genphy_suspend,
894513588ddSJassi Brar 		.resume		= genphy_resume,
895d98c8ccdSHeiner Kallweit 		.read_page	= rtl821x_read_page,
896d98c8ccdSHeiner Kallweit 		.write_page	= rtl821x_write_page,
897513588ddSJassi Brar 	}, {
898f3284e01SHeiner Kallweit 		PHY_ID_MATCH_MODEL(0x001cc880),
899f3284e01SHeiner Kallweit 		.name		= "RTL8208 Fast Ethernet",
900f3284e01SHeiner Kallweit 		.read_mmd	= genphy_read_mmd_unsupported,
901f3284e01SHeiner Kallweit 		.write_mmd	= genphy_write_mmd_unsupported,
902f3284e01SHeiner Kallweit 		.suspend	= genphy_suspend,
903f3284e01SHeiner Kallweit 		.resume		= genphy_resume,
904f3284e01SHeiner Kallweit 		.read_page	= rtl821x_read_page,
905f3284e01SHeiner Kallweit 		.write_page	= rtl821x_write_page,
906f3284e01SHeiner Kallweit 	}, {
907ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc910),
908d241d4aaSHeiner Kallweit 		.name		= "RTL8211 Gigabit Ethernet",
909d241d4aaSHeiner Kallweit 		.config_aneg	= rtl8211_config_aneg,
910d241d4aaSHeiner Kallweit 		.read_mmd	= &genphy_read_mmd_unsupported,
911d241d4aaSHeiner Kallweit 		.write_mmd	= &genphy_write_mmd_unsupported,
912daf3ddbeSHeiner Kallweit 		.read_page	= rtl821x_read_page,
913daf3ddbeSHeiner Kallweit 		.write_page	= rtl821x_write_page,
914d241d4aaSHeiner Kallweit 	}, {
915ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc912),
916ef3d9049SGiuseppe CAVALLARO 		.name		= "RTL8211B Gigabit Ethernet",
917ef3d9049SGiuseppe CAVALLARO 		.config_intr	= &rtl8211b_config_intr,
91803829163SIoana Ciornei 		.handle_interrupt = rtl821x_handle_interrupt,
9190231b1a0SKevin Hao 		.read_mmd	= &genphy_read_mmd_unsupported,
9200231b1a0SKevin Hao 		.write_mmd	= &genphy_write_mmd_unsupported,
921049ff57aSHeiner Kallweit 		.suspend	= rtl8211b_suspend,
922049ff57aSHeiner Kallweit 		.resume		= rtl8211b_resume,
923daf3ddbeSHeiner Kallweit 		.read_page	= rtl821x_read_page,
924daf3ddbeSHeiner Kallweit 		.write_page	= rtl821x_write_page,
92571b9c4a8SJongsung Kim 	}, {
926ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc913),
927cf87915cSHeiner Kallweit 		.name		= "RTL8211C Gigabit Ethernet",
928cf87915cSHeiner Kallweit 		.config_init	= rtl8211c_config_init,
929cf87915cSHeiner Kallweit 		.read_mmd	= &genphy_read_mmd_unsupported,
930cf87915cSHeiner Kallweit 		.write_mmd	= &genphy_write_mmd_unsupported,
931daf3ddbeSHeiner Kallweit 		.read_page	= rtl821x_read_page,
932daf3ddbeSHeiner Kallweit 		.write_page	= rtl821x_write_page,
933cf87915cSHeiner Kallweit 	}, {
934ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc914),
9350024f892SShaohui Xie 		.name		= "RTL8211DN Gigabit Ethernet",
9360024f892SShaohui Xie 		.config_intr	= rtl8211e_config_intr,
93703829163SIoana Ciornei 		.handle_interrupt = rtl821x_handle_interrupt,
9380024f892SShaohui Xie 		.suspend	= genphy_suspend,
9390024f892SShaohui Xie 		.resume		= genphy_resume,
940daf3ddbeSHeiner Kallweit 		.read_page	= rtl821x_read_page,
941daf3ddbeSHeiner Kallweit 		.write_page	= rtl821x_write_page,
9420024f892SShaohui Xie 	}, {
943ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc915),
944ef3d9049SGiuseppe CAVALLARO 		.name		= "RTL8211E Gigabit Ethernet",
945f81dadbcSSerge Semin 		.config_init	= &rtl8211e_config_init,
946ef3d9049SGiuseppe CAVALLARO 		.config_intr	= &rtl8211e_config_intr,
94703829163SIoana Ciornei 		.handle_interrupt = rtl821x_handle_interrupt,
948ef3d9049SGiuseppe CAVALLARO 		.suspend	= genphy_suspend,
949ef3d9049SGiuseppe CAVALLARO 		.resume		= genphy_resume,
950daf3ddbeSHeiner Kallweit 		.read_page	= rtl821x_read_page,
951daf3ddbeSHeiner Kallweit 		.write_page	= rtl821x_write_page,
9523447cf2eSShengzhou Liu 	}, {
953ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc916),
9543447cf2eSShengzhou Liu 		.name		= "RTL8211F Gigabit Ethernet",
9550a4355c2SJoakim Zhang 		.probe		= rtl821x_probe,
9563447cf2eSShengzhou Liu 		.config_init	= &rtl8211f_config_init,
9574826d2c4SAntonio Borneo 		.read_status	= rtlgen_read_status,
9583447cf2eSShengzhou Liu 		.config_intr	= &rtl8211f_config_intr,
95903829163SIoana Ciornei 		.handle_interrupt = rtl8211f_handle_interrupt,
96059e227e2SDetlev Casanova 		.suspend	= rtl821x_suspend,
9616813cc8cSJoakim Zhang 		.resume		= rtl821x_resume,
962d98c8ccdSHeiner Kallweit 		.read_page	= rtl821x_read_page,
963d98c8ccdSHeiner Kallweit 		.write_page	= rtl821x_write_page,
96459e227e2SDetlev Casanova 		.flags		= PHY_ALWAYS_CALL_SUSPEND,
965d8545825SLinus Walleij 	}, {
966bb726b75SClark Wang 		PHY_ID_MATCH_EXACT(RTL_8211FVD_PHYID),
967bb726b75SClark Wang 		.name		= "RTL8211F-VD Gigabit Ethernet",
968bb726b75SClark Wang 		.probe		= rtl821x_probe,
969bb726b75SClark Wang 		.config_init	= &rtl8211f_config_init,
970bb726b75SClark Wang 		.read_status	= rtlgen_read_status,
971bb726b75SClark Wang 		.config_intr	= &rtl8211f_config_intr,
972bb726b75SClark Wang 		.handle_interrupt = rtl8211f_handle_interrupt,
97359e227e2SDetlev Casanova 		.suspend	= rtl821x_suspend,
974bb726b75SClark Wang 		.resume		= rtl821x_resume,
975bb726b75SClark Wang 		.read_page	= rtl821x_read_page,
976bb726b75SClark Wang 		.write_page	= rtl821x_write_page,
97759e227e2SDetlev Casanova 		.flags		= PHY_ALWAYS_CALL_SUSPEND,
978bb726b75SClark Wang 	}, {
9795181b473SHeiner Kallweit 		.name		= "Generic FE-GE Realtek PHY",
9805181b473SHeiner Kallweit 		.match_phy_device = rtlgen_match_phy_device,
981d445dff2SHeiner Kallweit 		.read_status	= rtlgen_read_status,
982f66ebd14SHeiner Kallweit 		.suspend	= genphy_suspend,
983fee698d6SHeiner Kallweit 		.resume		= rtlgen_resume,
984f66ebd14SHeiner Kallweit 		.read_page	= rtl821x_read_page,
985f66ebd14SHeiner Kallweit 		.write_page	= rtl821x_write_page,
9865b3f1395SHeiner Kallweit 		.read_mmd	= rtlgen_read_mmd,
9875b3f1395SHeiner Kallweit 		.write_mmd	= rtlgen_write_mmd,
988f66ebd14SHeiner Kallweit 	}, {
9897a333af6SWilly Liu 		.name		= "RTL8226 2.5Gbps PHY",
9907a333af6SWilly Liu 		.match_phy_device = rtl8226_match_phy_device,
9917a333af6SWilly Liu 		.get_features	= rtl822x_get_features,
9927a333af6SWilly Liu 		.config_aneg	= rtl822x_config_aneg,
9937a333af6SWilly Liu 		.read_status	= rtl822x_read_status,
994087f5b87SHeiner Kallweit 		.suspend	= genphy_suspend,
995fee698d6SHeiner Kallweit 		.resume		= rtlgen_resume,
996087f5b87SHeiner Kallweit 		.read_page	= rtl821x_read_page,
997087f5b87SHeiner Kallweit 		.write_page	= rtl821x_write_page,
9987a333af6SWilly Liu 		.read_mmd	= rtl822x_read_mmd,
9997a333af6SWilly Liu 		.write_mmd	= rtl822x_write_mmd,
1000087f5b87SHeiner Kallweit 	}, {
1001b3ba9ae8SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc840),
10027a333af6SWilly Liu 		.name		= "RTL8226B_RTL8221B 2.5Gbps PHY",
10037a333af6SWilly Liu 		.get_features	= rtl822x_get_features,
10047a333af6SWilly Liu 		.config_aneg	= rtl822x_config_aneg,
10057a333af6SWilly Liu 		.read_status	= rtl822x_read_status,
1006b3ba9ae8SHeiner Kallweit 		.suspend	= genphy_suspend,
1007b3ba9ae8SHeiner Kallweit 		.resume		= rtlgen_resume,
1008b3ba9ae8SHeiner Kallweit 		.read_page	= rtl821x_read_page,
1009b3ba9ae8SHeiner Kallweit 		.write_page	= rtl821x_write_page,
10107a333af6SWilly Liu 		.read_mmd	= rtl822x_read_mmd,
10117a333af6SWilly Liu 		.write_mmd	= rtl822x_write_mmd,
1012b3ba9ae8SHeiner Kallweit 	}, {
101374d155beSWilly Liu 		PHY_ID_MATCH_EXACT(0x001cc838),
101474d155beSWilly Liu 		.name           = "RTL8226-CG 2.5Gbps PHY",
101574d155beSWilly Liu 		.get_features   = rtl822x_get_features,
101674d155beSWilly Liu 		.config_aneg    = rtl822x_config_aneg,
101774d155beSWilly Liu 		.read_status    = rtl822x_read_status,
101874d155beSWilly Liu 		.suspend        = genphy_suspend,
101974d155beSWilly Liu 		.resume         = rtlgen_resume,
102074d155beSWilly Liu 		.read_page      = rtl821x_read_page,
102174d155beSWilly Liu 		.write_page     = rtl821x_write_page,
102274d155beSWilly Liu 	}, {
102374d155beSWilly Liu 		PHY_ID_MATCH_EXACT(0x001cc848),
102474d155beSWilly Liu 		.name           = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
102574d155beSWilly Liu 		.get_features   = rtl822x_get_features,
102674d155beSWilly Liu 		.config_aneg    = rtl822x_config_aneg,
102774d155beSWilly Liu 		.read_status    = rtl822x_read_status,
102874d155beSWilly Liu 		.suspend        = genphy_suspend,
102974d155beSWilly Liu 		.resume         = rtlgen_resume,
103074d155beSWilly Liu 		.read_page      = rtl821x_read_page,
103174d155beSWilly Liu 		.write_page     = rtl821x_write_page,
103274d155beSWilly Liu 	}, {
103374d155beSWilly Liu 		PHY_ID_MATCH_EXACT(0x001cc849),
103474d155beSWilly Liu 		.name           = "RTL8221B-VB-CG 2.5Gbps PHY",
103574d155beSWilly Liu 		.get_features   = rtl822x_get_features,
103674d155beSWilly Liu 		.config_aneg    = rtl822x_config_aneg,
103774d155beSWilly Liu 		.read_status    = rtl822x_read_status,
103874d155beSWilly Liu 		.suspend        = genphy_suspend,
103974d155beSWilly Liu 		.resume         = rtlgen_resume,
104074d155beSWilly Liu 		.read_page      = rtl821x_read_page,
104174d155beSWilly Liu 		.write_page     = rtl821x_write_page,
104274d155beSWilly Liu 	}, {
104374d155beSWilly Liu 		PHY_ID_MATCH_EXACT(0x001cc84a),
104474d155beSWilly Liu 		.name           = "RTL8221B-VM-CG 2.5Gbps PHY",
104574d155beSWilly Liu 		.get_features   = rtl822x_get_features,
104674d155beSWilly Liu 		.config_aneg    = rtl822x_config_aneg,
104774d155beSWilly Liu 		.read_status    = rtl822x_read_status,
104874d155beSWilly Liu 		.suspend        = genphy_suspend,
104974d155beSWilly Liu 		.resume         = rtlgen_resume,
105074d155beSWilly Liu 		.read_page      = rtl821x_read_page,
105174d155beSWilly Liu 		.write_page     = rtl821x_write_page,
105274d155beSWilly Liu 	}, {
1053ca494936SHeiner Kallweit 		PHY_ID_MATCH_EXACT(0x001cc961),
1054d8545825SLinus Walleij 		.name		= "RTL8366RB Gigabit Ethernet",
1055d8545825SLinus Walleij 		.config_init	= &rtl8366rb_config_init,
10564c8e0459SLinus Walleij 		/* These interrupts are handled by the irq controller
10574c8e0459SLinus Walleij 		 * embedded inside the RTL8366RB, they get unmasked when the
10584c8e0459SLinus Walleij 		 * irq is requested and ACKed by reading the status register,
10594c8e0459SLinus Walleij 		 * which is done by the irqchip code.
10604c8e0459SLinus Walleij 		 */
10614c8e0459SLinus Walleij 		.config_intr	= genphy_no_config_intr,
106203829163SIoana Ciornei 		.handle_interrupt = genphy_handle_interrupt_no_ack,
1063d8545825SLinus Walleij 		.suspend	= genphy_suspend,
1064d8545825SLinus Walleij 		.resume		= genphy_resume,
10652d8983f9SYuusuke Ashizuka 	}, {
10662d8983f9SYuusuke Ashizuka 		PHY_ID_MATCH_EXACT(0x001ccb00),
10672d8983f9SYuusuke Ashizuka 		.name		= "RTL9000AA_RTL9000AN Ethernet",
10682d8983f9SYuusuke Ashizuka 		.features       = PHY_BASIC_T1_FEATURES,
10692d8983f9SYuusuke Ashizuka 		.config_init	= rtl9000a_config_init,
10702d8983f9SYuusuke Ashizuka 		.config_aneg	= rtl9000a_config_aneg,
10712d8983f9SYuusuke Ashizuka 		.read_status	= rtl9000a_read_status,
10722d8983f9SYuusuke Ashizuka 		.config_intr	= rtl9000a_config_intr,
10732d8983f9SYuusuke Ashizuka 		.handle_interrupt = rtl9000a_handle_interrupt,
10742d8983f9SYuusuke Ashizuka 		.suspend	= genphy_suspend,
10752d8983f9SYuusuke Ashizuka 		.resume		= genphy_resume,
10762d8983f9SYuusuke Ashizuka 		.read_page	= rtl821x_read_page,
10772d8983f9SYuusuke Ashizuka 		.write_page	= rtl821x_write_page,
10782ca2969aSAlvin Šipraga 	}, {
10792ca2969aSAlvin Šipraga 		PHY_ID_MATCH_EXACT(0x001cc942),
10802ca2969aSAlvin Šipraga 		.name		= "RTL8365MB-VC Gigabit Ethernet",
10812ca2969aSAlvin Šipraga 		/* Interrupt handling analogous to RTL8366RB */
10822ca2969aSAlvin Šipraga 		.config_intr	= genphy_no_config_intr,
10832ca2969aSAlvin Šipraga 		.handle_interrupt = genphy_handle_interrupt_no_ack,
10842ca2969aSAlvin Šipraga 		.suspend	= genphy_suspend,
10852ca2969aSAlvin Šipraga 		.resume		= genphy_resume,
1086*b45cbfa2SMark Mentovai 	}, {
1087*b45cbfa2SMark Mentovai 		PHY_ID_MATCH_EXACT(0x001cc960),
1088*b45cbfa2SMark Mentovai 		.name		= "RTL8366S Gigabit Ethernet",
1089*b45cbfa2SMark Mentovai 		.suspend	= genphy_suspend,
1090*b45cbfa2SMark Mentovai 		.resume		= genphy_resume,
1091*b45cbfa2SMark Mentovai 		.read_mmd	= genphy_read_mmd_unsupported,
1092*b45cbfa2SMark Mentovai 		.write_mmd	= genphy_write_mmd_unsupported,
109371b9c4a8SJongsung Kim 	},
1094097c2aa8SJohnson Leung };
1095097c2aa8SJohnson Leung 
109650fd7150SJohan Hovold module_phy_driver(realtek_drvs);
10974e4f10f6SDavid Woodhouse 
10983b73e842SHeiner Kallweit static const struct mdio_device_id __maybe_unused realtek_tbl[] = {
1099ca494936SHeiner Kallweit 	{ PHY_ID_MATCH_VENDOR(0x001cc800) },
11004e4f10f6SDavid Woodhouse 	{ }
11014e4f10f6SDavid Woodhouse };
11024e4f10f6SDavid Woodhouse 
11034e4f10f6SDavid Woodhouse MODULE_DEVICE_TABLE(mdio, realtek_tbl);
1104