xref: /OK3568_Linux_fs/kernel/drivers/net/phy/motorcomm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Driver for Motorcomm PHYs
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author: Peter Geis <pgwipeout@gmail.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/netdevice.h>
11*4882a593Smuzhiyun #include <linux/of_device.h>
12*4882a593Smuzhiyun #include <linux/phy.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define PHY_ID_YT8511		0x0000010a
15*4882a593Smuzhiyun #define PHY_ID_YT8512		0x00000118
16*4882a593Smuzhiyun #define PHY_ID_YT8512B		0x00000128
17*4882a593Smuzhiyun #define PHY_ID_YT8531S		0x4f51e91a
18*4882a593Smuzhiyun #define PHY_ID_YT8531		0x4f51e91b
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define YT8511_PAGE_SELECT	0x1e
21*4882a593Smuzhiyun #define YT8511_PAGE		0x1f
22*4882a593Smuzhiyun #define YT8511_EXT_CLK_GATE	0x0c
23*4882a593Smuzhiyun #define YT8511_EXT_DELAY_DRIVE	0x0d
24*4882a593Smuzhiyun #define YT8511_EXT_SLEEP_CTRL	0x27
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun /* 2b00 25m from pll
27*4882a593Smuzhiyun  * 2b01 25m from xtl *default*
28*4882a593Smuzhiyun  * 2b10 62.m from pll
29*4882a593Smuzhiyun  * 2b11 125m from pll
30*4882a593Smuzhiyun  */
31*4882a593Smuzhiyun #define YT8511_CLK_125M		(BIT(2) | BIT(1))
32*4882a593Smuzhiyun #define YT8511_PLLON_SLP	BIT(14)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* RX Delay enabled = 1.8ns 1000T, 8ns 10/100T */
35*4882a593Smuzhiyun #define YT8511_DELAY_RX		BIT(0)
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* TX Gig-E Delay is bits 7:4, default 0x5
38*4882a593Smuzhiyun  * TX Fast-E Delay is bits 15:12, default 0xf
39*4882a593Smuzhiyun  * Delay = 150ps * N - 250ps
40*4882a593Smuzhiyun  * On = 2000ps, off = 50ps
41*4882a593Smuzhiyun  */
42*4882a593Smuzhiyun #define YT8511_DELAY_GE_TX_EN	(0xf << 4)
43*4882a593Smuzhiyun #define YT8511_DELAY_GE_TX_DIS	(0x2 << 4)
44*4882a593Smuzhiyun #define YT8511_DELAY_FE_TX_EN	(0xf << 12)
45*4882a593Smuzhiyun #define YT8511_DELAY_FE_TX_DIS	(0x2 << 12)
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define YT8512_EXTREG_AFE_PLL		0x50
48*4882a593Smuzhiyun #define YT8512_EXTREG_EXTEND_COMBO	0x4000
49*4882a593Smuzhiyun #define YT8512_EXTREG_LED0		0x40c0
50*4882a593Smuzhiyun #define YT8512_EXTREG_LED1		0x40c3
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define YT8512_EXTREG_SLEEP_CONTROL1	0x2027
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define YT_SOFTWARE_RESET		0x8000
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define YT8512_CONFIG_PLL_REFCLK_SEL_EN	0x0040
57*4882a593Smuzhiyun #define YT8512_CONTROL1_RMII_EN		0x0001
58*4882a593Smuzhiyun #define YT8512_LED0_ACT_BLK_IND		0x1000
59*4882a593Smuzhiyun #define YT8512_LED0_DIS_LED_AN_TRY	0x0001
60*4882a593Smuzhiyun #define YT8512_LED0_BT_BLK_EN		0x0002
61*4882a593Smuzhiyun #define YT8512_LED0_HT_BLK_EN		0x0004
62*4882a593Smuzhiyun #define YT8512_LED0_COL_BLK_EN		0x0008
63*4882a593Smuzhiyun #define YT8512_LED0_BT_ON_EN		0x0010
64*4882a593Smuzhiyun #define YT8512_LED1_BT_ON_EN		0x0010
65*4882a593Smuzhiyun #define YT8512_LED1_TXACT_BLK_EN	0x0100
66*4882a593Smuzhiyun #define YT8512_LED1_RXACT_BLK_EN	0x0200
67*4882a593Smuzhiyun #define YT8512_SPEED_MODE		0xc000
68*4882a593Smuzhiyun #define YT8512_DUPLEX			0x2000
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define YT8512_SPEED_MODE_BIT		14
71*4882a593Smuzhiyun #define YT8512_DUPLEX_BIT		13
72*4882a593Smuzhiyun #define YT8512_EN_SLEEP_SW_BIT		15
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /* if system depends on ethernet packet to restore from sleep,
75*4882a593Smuzhiyun  * please define this macro to 1 otherwise, define it to 0.
76*4882a593Smuzhiyun  */
77*4882a593Smuzhiyun #define SYS_WAKEUP_BASED_ON_ETH_PKT	1
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun /* to enable system WOL feature of phy, please define this macro to 1
80*4882a593Smuzhiyun  * otherwise, define it to 0.
81*4882a593Smuzhiyun  */
82*4882a593Smuzhiyun #define YTPHY_WOL_FEATURE_ENABLE	0
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #if (YTPHY_WOL_FEATURE_ENABLE)
85*4882a593Smuzhiyun #undef SYS_WAKEUP_BASED_ON_ETH_PKT
86*4882a593Smuzhiyun #define SYS_WAKEUP_BASED_ON_ETH_PKT	1
87*4882a593Smuzhiyun #endif
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun /* for YT8531 package A xtal init config */
90*4882a593Smuzhiyun #define YTPHY8531A_XTAL_INIT		0
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun #define REG_PHY_SPEC_STATUS		0x11
93*4882a593Smuzhiyun #define REG_DEBUG_ADDR_OFFSET		0x1e
94*4882a593Smuzhiyun #define REG_DEBUG_DATA			0x1f
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define YT8521_EXTREG_SLEEP_CONTROL1	0x27
97*4882a593Smuzhiyun #define YT8521_EN_SLEEP_SW_BIT		15
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun #define YT8521_SPEED_MODE		0xc000
100*4882a593Smuzhiyun #define YT8521_DUPLEX			0x2000
101*4882a593Smuzhiyun #define YT8521_SPEED_MODE_BIT		14
102*4882a593Smuzhiyun #define YT8521_DUPLEX_BIT		13
103*4882a593Smuzhiyun #define YT8521_LINK_STATUS_BIT		10
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /* YT8521 polling mode */
106*4882a593Smuzhiyun #define YT8521_PHY_MODE_FIBER		1 /* fiber mode only */
107*4882a593Smuzhiyun #define YT8521_PHY_MODE_UTP		2 /* utp mode only */
108*4882a593Smuzhiyun #define YT8521_PHY_MODE_POLL		3 /* fiber and utp, poll mode */
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun static int yt8521_hw_strap_polling(struct phy_device *phydev);
111*4882a593Smuzhiyun #define YT8521_PHY_MODE_CURR		yt8521_hw_strap_polling(phydev)
112*4882a593Smuzhiyun 
yt8511_read_page(struct phy_device * phydev)113*4882a593Smuzhiyun static int yt8511_read_page(struct phy_device *phydev)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	return __phy_read(phydev, YT8511_PAGE_SELECT);
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun 
yt8511_write_page(struct phy_device * phydev,int page)118*4882a593Smuzhiyun static int yt8511_write_page(struct phy_device *phydev, int page)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	return __phy_write(phydev, YT8511_PAGE_SELECT, page);
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun 
yt8511_config_init(struct phy_device * phydev)123*4882a593Smuzhiyun static int yt8511_config_init(struct phy_device *phydev)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	int oldpage, ret = 0;
126*4882a593Smuzhiyun 	unsigned int ge, fe;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	oldpage = phy_select_page(phydev, YT8511_EXT_CLK_GATE);
129*4882a593Smuzhiyun 	if (oldpage < 0)
130*4882a593Smuzhiyun 		goto err_restore_page;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	/* set rgmii delay mode */
133*4882a593Smuzhiyun 	switch (phydev->interface) {
134*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII:
135*4882a593Smuzhiyun 		ge = YT8511_DELAY_GE_TX_DIS;
136*4882a593Smuzhiyun 		fe = YT8511_DELAY_FE_TX_DIS;
137*4882a593Smuzhiyun 		break;
138*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII_RXID:
139*4882a593Smuzhiyun 		ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_DIS;
140*4882a593Smuzhiyun 		fe = YT8511_DELAY_FE_TX_DIS;
141*4882a593Smuzhiyun 		break;
142*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII_TXID:
143*4882a593Smuzhiyun 		ge = YT8511_DELAY_GE_TX_EN;
144*4882a593Smuzhiyun 		fe = YT8511_DELAY_FE_TX_EN;
145*4882a593Smuzhiyun 		break;
146*4882a593Smuzhiyun 	case PHY_INTERFACE_MODE_RGMII_ID:
147*4882a593Smuzhiyun 		ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN;
148*4882a593Smuzhiyun 		fe = YT8511_DELAY_FE_TX_EN;
149*4882a593Smuzhiyun 		break;
150*4882a593Smuzhiyun 	default: /* do not support other modes */
151*4882a593Smuzhiyun 		ret = -EOPNOTSUPP;
152*4882a593Smuzhiyun 		goto err_restore_page;
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	ret = __phy_modify(phydev, YT8511_PAGE, (YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN), ge);
156*4882a593Smuzhiyun 	if (ret < 0)
157*4882a593Smuzhiyun 		goto err_restore_page;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	/* set clock mode to 125mhz */
160*4882a593Smuzhiyun 	ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_CLK_125M);
161*4882a593Smuzhiyun 	if (ret < 0)
162*4882a593Smuzhiyun 		goto err_restore_page;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* fast ethernet delay is in a separate page */
165*4882a593Smuzhiyun 	ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_DELAY_DRIVE);
166*4882a593Smuzhiyun 	if (ret < 0)
167*4882a593Smuzhiyun 		goto err_restore_page;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	ret = __phy_modify(phydev, YT8511_PAGE, YT8511_DELAY_FE_TX_EN, fe);
170*4882a593Smuzhiyun 	if (ret < 0)
171*4882a593Smuzhiyun 		goto err_restore_page;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	/* leave pll enabled in sleep */
174*4882a593Smuzhiyun 	ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_SLEEP_CTRL);
175*4882a593Smuzhiyun 	if (ret < 0)
176*4882a593Smuzhiyun 		goto err_restore_page;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_PLLON_SLP);
179*4882a593Smuzhiyun 	if (ret < 0)
180*4882a593Smuzhiyun 		goto err_restore_page;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun err_restore_page:
183*4882a593Smuzhiyun 	return phy_restore_page(phydev, oldpage, ret);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
ytphy_read_ext(struct phy_device * phydev,u32 regnum)186*4882a593Smuzhiyun static u32 ytphy_read_ext(struct phy_device *phydev, u32 regnum)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	int ret;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	phy_lock_mdio_bus(phydev);
191*4882a593Smuzhiyun 	ret = __phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
192*4882a593Smuzhiyun 	if (ret < 0)
193*4882a593Smuzhiyun 		goto err_handle;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	ret = __phy_read(phydev, REG_DEBUG_DATA);
196*4882a593Smuzhiyun 	if (ret < 0)
197*4882a593Smuzhiyun 		goto err_handle;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun err_handle:
200*4882a593Smuzhiyun 	phy_unlock_mdio_bus(phydev);
201*4882a593Smuzhiyun 	return ret;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
ytphy_write_ext(struct phy_device * phydev,u32 regnum,u16 val)204*4882a593Smuzhiyun static int ytphy_write_ext(struct phy_device *phydev, u32 regnum, u16 val)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	int ret;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	phy_lock_mdio_bus(phydev);
209*4882a593Smuzhiyun 	ret = __phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
210*4882a593Smuzhiyun 	if (ret < 0)
211*4882a593Smuzhiyun 		goto err_handle;
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	ret = __phy_write(phydev, REG_DEBUG_DATA, val);
214*4882a593Smuzhiyun 	if (ret < 0)
215*4882a593Smuzhiyun 		goto err_handle;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun err_handle:
218*4882a593Smuzhiyun 	phy_unlock_mdio_bus(phydev);
219*4882a593Smuzhiyun 	return ret;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
ytphy_soft_reset(struct phy_device * phydev)222*4882a593Smuzhiyun static int ytphy_soft_reset(struct phy_device *phydev)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun 	int ret = 0, val = 0;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	val = phy_read(phydev, MII_BMCR);
227*4882a593Smuzhiyun 	if (val < 0)
228*4882a593Smuzhiyun 		return val;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	ret = phy_write(phydev, MII_BMCR, val | BMCR_RESET);
231*4882a593Smuzhiyun 	if (ret < 0)
232*4882a593Smuzhiyun 		return ret;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	return ret;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
yt8512_clk_init(struct phy_device * phydev)237*4882a593Smuzhiyun static int yt8512_clk_init(struct phy_device *phydev)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	struct device_node *node = phydev->mdio.dev.of_node;
240*4882a593Smuzhiyun 	const char *strings = NULL;
241*4882a593Smuzhiyun 	int ret;
242*4882a593Smuzhiyun 	int val;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (node && node->parent && node->parent->parent) {
245*4882a593Smuzhiyun 		ret = of_property_read_string(node->parent->parent,
246*4882a593Smuzhiyun 					      "clock_in_out", &strings);
247*4882a593Smuzhiyun 		if (!ret) {
248*4882a593Smuzhiyun 			if (!strcmp(strings, "input"))
249*4882a593Smuzhiyun 				return 0;
250*4882a593Smuzhiyun 		}
251*4882a593Smuzhiyun 	}
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, YT8512_EXTREG_AFE_PLL);
254*4882a593Smuzhiyun 	if (val < 0)
255*4882a593Smuzhiyun 		return val;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	val |= YT8512_CONFIG_PLL_REFCLK_SEL_EN;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, YT8512_EXTREG_AFE_PLL, val);
260*4882a593Smuzhiyun 	if (ret < 0)
261*4882a593Smuzhiyun 		return ret;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, YT8512_EXTREG_EXTEND_COMBO);
264*4882a593Smuzhiyun 	if (val < 0)
265*4882a593Smuzhiyun 		return val;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	val |= YT8512_CONTROL1_RMII_EN;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, YT8512_EXTREG_EXTEND_COMBO, val);
270*4882a593Smuzhiyun 	if (ret < 0)
271*4882a593Smuzhiyun 		return ret;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	val = phy_read(phydev, MII_BMCR);
274*4882a593Smuzhiyun 	if (val < 0)
275*4882a593Smuzhiyun 		return val;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	val |= YT_SOFTWARE_RESET;
278*4882a593Smuzhiyun 	ret = phy_write(phydev, MII_BMCR, val);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	return ret;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
yt8512_led_init(struct phy_device * phydev)283*4882a593Smuzhiyun static int yt8512_led_init(struct phy_device *phydev)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	int ret;
286*4882a593Smuzhiyun 	int val;
287*4882a593Smuzhiyun 	int mask;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, YT8512_EXTREG_LED0);
290*4882a593Smuzhiyun 	if (val < 0)
291*4882a593Smuzhiyun 		return val;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	val |= YT8512_LED0_ACT_BLK_IND;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	mask = YT8512_LED0_DIS_LED_AN_TRY | YT8512_LED0_BT_BLK_EN |
296*4882a593Smuzhiyun 		YT8512_LED0_HT_BLK_EN | YT8512_LED0_COL_BLK_EN |
297*4882a593Smuzhiyun 		YT8512_LED0_BT_ON_EN;
298*4882a593Smuzhiyun 	val &= ~mask;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, YT8512_EXTREG_LED0, val);
301*4882a593Smuzhiyun 	if (ret < 0)
302*4882a593Smuzhiyun 		return ret;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, YT8512_EXTREG_LED1);
305*4882a593Smuzhiyun 	if (val < 0)
306*4882a593Smuzhiyun 		return val;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	val |= YT8512_LED1_BT_ON_EN;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	mask = YT8512_LED1_TXACT_BLK_EN | YT8512_LED1_RXACT_BLK_EN;
311*4882a593Smuzhiyun 	val &= ~mask;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, YT8512_LED1_BT_ON_EN, val);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return ret;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
yt8512_config_init(struct phy_device * phydev)318*4882a593Smuzhiyun static int yt8512_config_init(struct phy_device *phydev)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	int ret;
321*4882a593Smuzhiyun 	int val;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	ret = yt8512_clk_init(phydev);
324*4882a593Smuzhiyun 	if (ret < 0)
325*4882a593Smuzhiyun 		return ret;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	ret = yt8512_led_init(phydev);
328*4882a593Smuzhiyun 	if (ret < 0)
329*4882a593Smuzhiyun 		return ret;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/* disable auto sleep */
332*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1);
333*4882a593Smuzhiyun 	if (val < 0)
334*4882a593Smuzhiyun 		return val;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	val &= (~BIT(YT8512_EN_SLEEP_SW_BIT));
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1, val);
339*4882a593Smuzhiyun 	if (ret < 0)
340*4882a593Smuzhiyun 		return ret;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	return ret;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
yt8512_read_status(struct phy_device * phydev)345*4882a593Smuzhiyun static int yt8512_read_status(struct phy_device *phydev)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	int ret;
348*4882a593Smuzhiyun 	int val;
349*4882a593Smuzhiyun 	int speed, speed_mode, duplex;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	ret = genphy_update_link(phydev);
352*4882a593Smuzhiyun 	if (ret)
353*4882a593Smuzhiyun 		return ret;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	val = phy_read(phydev, REG_PHY_SPEC_STATUS);
356*4882a593Smuzhiyun 	if (val < 0)
357*4882a593Smuzhiyun 		return val;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	duplex = (val & YT8512_DUPLEX) >> YT8512_DUPLEX_BIT;
360*4882a593Smuzhiyun 	speed_mode = (val & YT8512_SPEED_MODE) >> YT8512_SPEED_MODE_BIT;
361*4882a593Smuzhiyun 	switch (speed_mode) {
362*4882a593Smuzhiyun 	case 0:
363*4882a593Smuzhiyun 		speed = SPEED_10;
364*4882a593Smuzhiyun 		break;
365*4882a593Smuzhiyun 	case 1:
366*4882a593Smuzhiyun 		speed = SPEED_100;
367*4882a593Smuzhiyun 		break;
368*4882a593Smuzhiyun 	case 2:
369*4882a593Smuzhiyun 	case 3:
370*4882a593Smuzhiyun 	default:
371*4882a593Smuzhiyun 		speed = SPEED_UNKNOWN;
372*4882a593Smuzhiyun 		break;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	phydev->speed = speed;
376*4882a593Smuzhiyun 	phydev->duplex = duplex;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	return 0;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
yt8521_soft_reset(struct phy_device * phydev)381*4882a593Smuzhiyun static int yt8521_soft_reset(struct phy_device *phydev)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	int ret = 0, val;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR == YT8521_PHY_MODE_UTP) {
386*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa000, 0);
387*4882a593Smuzhiyun 		ret = ytphy_soft_reset(phydev);
388*4882a593Smuzhiyun 		if (ret < 0)
389*4882a593Smuzhiyun 			return ret;
390*4882a593Smuzhiyun 	}
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR == YT8521_PHY_MODE_FIBER) {
393*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa000, 2);
394*4882a593Smuzhiyun 		ret = ytphy_soft_reset(phydev);
395*4882a593Smuzhiyun 		if (ret < 0)
396*4882a593Smuzhiyun 			return ret;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa000, 0);
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR == YT8521_PHY_MODE_POLL) {
402*4882a593Smuzhiyun 		val = ytphy_read_ext(phydev, 0xa001);
403*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa001, (val & ~0x8000));
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa000, 0);
406*4882a593Smuzhiyun 		ret = ytphy_soft_reset(phydev);
407*4882a593Smuzhiyun 		if (ret < 0)
408*4882a593Smuzhiyun 			return ret;
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	return 0;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun 
yt8521_hw_strap_polling(struct phy_device * phydev)414*4882a593Smuzhiyun static int yt8521_hw_strap_polling(struct phy_device *phydev)
415*4882a593Smuzhiyun {
416*4882a593Smuzhiyun 	int val = 0;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, 0xa001) & 0x7;
419*4882a593Smuzhiyun 	switch (val) {
420*4882a593Smuzhiyun 	case 1:
421*4882a593Smuzhiyun 	case 4:
422*4882a593Smuzhiyun 	case 5:
423*4882a593Smuzhiyun 		return YT8521_PHY_MODE_FIBER;
424*4882a593Smuzhiyun 	case 2:
425*4882a593Smuzhiyun 	case 6:
426*4882a593Smuzhiyun 	case 7:
427*4882a593Smuzhiyun 		return YT8521_PHY_MODE_POLL;
428*4882a593Smuzhiyun 	case 3:
429*4882a593Smuzhiyun 	case 0:
430*4882a593Smuzhiyun 	default:
431*4882a593Smuzhiyun 		return YT8521_PHY_MODE_UTP;
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
yt8521_config_init(struct phy_device * phydev)435*4882a593Smuzhiyun static int yt8521_config_init(struct phy_device *phydev)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	int ret, hw_strap_mode;
438*4882a593Smuzhiyun 	int val;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun #if (YTPHY_WOL_FEATURE_ENABLE)
441*4882a593Smuzhiyun 	struct ethtool_wolinfo wol;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	/* set phy wol enable */
444*4882a593Smuzhiyun 	memset(&wol, 0x0, sizeof(struct ethtool_wolinfo));
445*4882a593Smuzhiyun 	wol.wolopts |= WAKE_MAGIC;
446*4882a593Smuzhiyun 	ytphy_wol_feature_set(phydev, &wol);
447*4882a593Smuzhiyun #endif
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	phydev->irq = PHY_POLL;
450*4882a593Smuzhiyun 	/* NOTE: this function should not be called more than one for each chip. */
451*4882a593Smuzhiyun 	hw_strap_mode = ytphy_read_ext(phydev, 0xa001) & 0x7;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	ytphy_write_ext(phydev, 0xa000, 0);
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	/* disable auto sleep */
456*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1);
457*4882a593Smuzhiyun 	if (val < 0)
458*4882a593Smuzhiyun 		return val;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	val &= (~BIT(YT8521_EN_SLEEP_SW_BIT));
461*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, val);
462*4882a593Smuzhiyun 	if (ret < 0)
463*4882a593Smuzhiyun 		return ret;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	/* enable RXC clock when no wire plug */
466*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, 0xc);
467*4882a593Smuzhiyun 	if (val < 0)
468*4882a593Smuzhiyun 		return val;
469*4882a593Smuzhiyun 	val &= ~(1 << 12);
470*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xc, val);
471*4882a593Smuzhiyun 	if (ret < 0)
472*4882a593Smuzhiyun 		return ret;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	netdev_info(phydev->attached_dev, "%s done, phy addr: %d, strap mode = %d, polling mode = %d\n",
475*4882a593Smuzhiyun 		    __func__, phydev->mdio.addr, hw_strap_mode, yt8521_hw_strap_polling(phydev));
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	return ret;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun /* for fiber mode, there is no 10M speed mode and
481*4882a593Smuzhiyun  * this function is for this purpose.
482*4882a593Smuzhiyun  */
yt8521_adjust_status(struct phy_device * phydev,int val,int is_utp)483*4882a593Smuzhiyun static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	int speed = SPEED_UNKNOWN;
486*4882a593Smuzhiyun 	int speed_mode, duplex;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	if (is_utp)
489*4882a593Smuzhiyun 		duplex = (val & YT8521_DUPLEX) >> YT8521_DUPLEX_BIT;
490*4882a593Smuzhiyun 	else
491*4882a593Smuzhiyun 		duplex = 1;
492*4882a593Smuzhiyun 	speed_mode = (val & YT8521_SPEED_MODE) >> YT8521_SPEED_MODE_BIT;
493*4882a593Smuzhiyun 	switch (speed_mode) {
494*4882a593Smuzhiyun 	case 0:
495*4882a593Smuzhiyun 		if (is_utp)
496*4882a593Smuzhiyun 			speed = SPEED_10;
497*4882a593Smuzhiyun 		break;
498*4882a593Smuzhiyun 	case 1:
499*4882a593Smuzhiyun 		speed = SPEED_100;
500*4882a593Smuzhiyun 		break;
501*4882a593Smuzhiyun 	case 2:
502*4882a593Smuzhiyun 		speed = SPEED_1000;
503*4882a593Smuzhiyun 		break;
504*4882a593Smuzhiyun 	case 3:
505*4882a593Smuzhiyun 		break;
506*4882a593Smuzhiyun 	default:
507*4882a593Smuzhiyun 		speed = SPEED_UNKNOWN;
508*4882a593Smuzhiyun 		break;
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	phydev->speed = speed;
512*4882a593Smuzhiyun 	phydev->duplex = duplex;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	return 0;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun /* for fiber mode, when speed is 100M, there is no definition for
518*4882a593Smuzhiyun  * autonegotiation, and this function handles this case and return
519*4882a593Smuzhiyun  * 1 per linux kernel's polling.
520*4882a593Smuzhiyun  */
yt8521_aneg_done(struct phy_device * phydev)521*4882a593Smuzhiyun static int yt8521_aneg_done(struct phy_device *phydev)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun 	int link_fiber = 0, link_utp = 0;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	/* reading Fiber */
526*4882a593Smuzhiyun 	ytphy_write_ext(phydev, 0xa000, 2);
527*4882a593Smuzhiyun 	link_fiber = !!(phy_read(phydev, REG_PHY_SPEC_STATUS) & (BIT(YT8521_LINK_STATUS_BIT)));
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	/* reading UTP */
530*4882a593Smuzhiyun 	ytphy_write_ext(phydev, 0xa000, 0);
531*4882a593Smuzhiyun 	if (!link_fiber)
532*4882a593Smuzhiyun 		link_utp = !!(phy_read(phydev, REG_PHY_SPEC_STATUS) & (BIT(YT8521_LINK_STATUS_BIT)));
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	netdev_info(phydev->attached_dev, "%s, phy addr: %d, link_fiber: %d, link_utp: %d\n",
535*4882a593Smuzhiyun 		    __func__, phydev->mdio.addr, link_fiber, link_utp);
536*4882a593Smuzhiyun 	return !!(link_fiber | link_utp);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
yt8521_read_status(struct phy_device * phydev)539*4882a593Smuzhiyun static int yt8521_read_status(struct phy_device *phydev)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun 	int link_utp = 0, link_fiber = 0;
542*4882a593Smuzhiyun 	int yt8521_fiber_latch_val;
543*4882a593Smuzhiyun 	int yt8521_fiber_curr_val;
544*4882a593Smuzhiyun 	int link, ret;
545*4882a593Smuzhiyun 	int val;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {
548*4882a593Smuzhiyun 		/* reading UTP */
549*4882a593Smuzhiyun 		ret = ytphy_write_ext(phydev, 0xa000, 0);
550*4882a593Smuzhiyun 		if (ret < 0)
551*4882a593Smuzhiyun 			return ret;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 		val = phy_read(phydev, REG_PHY_SPEC_STATUS);
554*4882a593Smuzhiyun 		if (val < 0)
555*4882a593Smuzhiyun 			return val;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 		link = val & (BIT(YT8521_LINK_STATUS_BIT));
558*4882a593Smuzhiyun 		if (link) {
559*4882a593Smuzhiyun 			link_utp = 1;
560*4882a593Smuzhiyun 			yt8521_adjust_status(phydev, val, 1);
561*4882a593Smuzhiyun 		} else {
562*4882a593Smuzhiyun 			link_utp = 0;
563*4882a593Smuzhiyun 		}
564*4882a593Smuzhiyun 	}
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) {
567*4882a593Smuzhiyun 		/* reading Fiber */
568*4882a593Smuzhiyun 		ret = ytphy_write_ext(phydev, 0xa000, 2);
569*4882a593Smuzhiyun 		if (ret < 0)
570*4882a593Smuzhiyun 			return ret;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 		val = phy_read(phydev, REG_PHY_SPEC_STATUS);
573*4882a593Smuzhiyun 		if (val < 0)
574*4882a593Smuzhiyun 			return val;
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 		/* note: below debug information is used to check multiple PHy ports. */
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 		/* for fiber, from 1000m to 100m, there is not link down from 0x11,
579*4882a593Smuzhiyun 		 * and check reg 1 to identify such case this is important for Linux
580*4882a593Smuzhiyun 		 * kernel for that, missing linkdown event will cause problem.
581*4882a593Smuzhiyun 		 */
582*4882a593Smuzhiyun 		yt8521_fiber_latch_val = phy_read(phydev, MII_BMSR);
583*4882a593Smuzhiyun 		yt8521_fiber_curr_val = phy_read(phydev, MII_BMSR);
584*4882a593Smuzhiyun 		link = val & (BIT(YT8521_LINK_STATUS_BIT));
585*4882a593Smuzhiyun 		if (link && yt8521_fiber_latch_val != yt8521_fiber_curr_val) {
586*4882a593Smuzhiyun 			link = 0;
587*4882a593Smuzhiyun 			netdev_info(phydev->attached_dev, "%s, phy addr: %d, fiber link down detect, latch = %04x, curr = %04x\n",
588*4882a593Smuzhiyun 				    __func__, phydev->mdio.addr, yt8521_fiber_latch_val,
589*4882a593Smuzhiyun 				    yt8521_fiber_curr_val);
590*4882a593Smuzhiyun 		}
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 		if (link) {
593*4882a593Smuzhiyun 			link_fiber = 1;
594*4882a593Smuzhiyun 			yt8521_adjust_status(phydev, val, 0);
595*4882a593Smuzhiyun 		} else {
596*4882a593Smuzhiyun 			link_fiber = 0;
597*4882a593Smuzhiyun 		}
598*4882a593Smuzhiyun 	}
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	if (link_utp || link_fiber) {
601*4882a593Smuzhiyun 		if (phydev->link == 0)
602*4882a593Smuzhiyun 			netdev_info(phydev->attached_dev, "%s, phy addr: %d, link up, media: %s, mii reg 0x11 = 0x%x\n",
603*4882a593Smuzhiyun 				    __func__, phydev->mdio.addr,
604*4882a593Smuzhiyun 				    (link_utp && link_fiber) ? "UNKNOWN MEDIA" : (link_utp ? "UTP" : "Fiber"),
605*4882a593Smuzhiyun 				    (unsigned int)val);
606*4882a593Smuzhiyun 		phydev->link = 1;
607*4882a593Smuzhiyun 	} else {
608*4882a593Smuzhiyun 		if (phydev->link == 1)
609*4882a593Smuzhiyun 			netdev_info(phydev->attached_dev, "%s, phy addr: %d, link down\n",
610*4882a593Smuzhiyun 				    __func__, phydev->mdio.addr);
611*4882a593Smuzhiyun 		phydev->link = 0;
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	/* utp or combo */
615*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {
616*4882a593Smuzhiyun 		if (link_fiber)
617*4882a593Smuzhiyun 			ytphy_write_ext(phydev, 0xa000, 2);
618*4882a593Smuzhiyun 		if (link_utp)
619*4882a593Smuzhiyun 			ytphy_write_ext(phydev, 0xa000, 0);
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	return 0;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun 
yt8521_suspend(struct phy_device * phydev)625*4882a593Smuzhiyun static int yt8521_suspend(struct phy_device *phydev)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun #if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
628*4882a593Smuzhiyun 	int value;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	ytphy_write_ext(phydev, 0xa000, 0);
631*4882a593Smuzhiyun 	value = phy_read(phydev, MII_BMCR);
632*4882a593Smuzhiyun 	phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	ytphy_write_ext(phydev, 0xa000, 2);
635*4882a593Smuzhiyun 	value = phy_read(phydev, MII_BMCR);
636*4882a593Smuzhiyun 	phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	ytphy_write_ext(phydev, 0xa000, 0);
639*4882a593Smuzhiyun #endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	return 0;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun 
yt8521_resume(struct phy_device * phydev)644*4882a593Smuzhiyun static int yt8521_resume(struct phy_device *phydev)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	int value, ret;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	/* disable auto sleep */
649*4882a593Smuzhiyun 	value = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1);
650*4882a593Smuzhiyun 	if (value < 0)
651*4882a593Smuzhiyun 		return value;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	value &= (~BIT(YT8521_EN_SLEEP_SW_BIT));
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, value);
656*4882a593Smuzhiyun 	if (ret < 0)
657*4882a593Smuzhiyun 		return ret;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun #if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
660*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {
661*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa000, 0);
662*4882a593Smuzhiyun 		value = phy_read(phydev, MII_BMCR);
663*4882a593Smuzhiyun 		phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) {
667*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa000, 2);
668*4882a593Smuzhiyun 		value = phy_read(phydev, MII_BMCR);
669*4882a593Smuzhiyun 		phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 		ytphy_write_ext(phydev, 0xa000, 0);
672*4882a593Smuzhiyun 	}
673*4882a593Smuzhiyun #endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	return 0;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun 
yt8531_rxclk_duty_init(struct phy_device * phydev)678*4882a593Smuzhiyun static int yt8531_rxclk_duty_init(struct phy_device *phydev)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	unsigned int value = 0x9696;
681*4882a593Smuzhiyun 	int ret = 0;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa040, 0xffff);
684*4882a593Smuzhiyun 	if (ret < 0)
685*4882a593Smuzhiyun 		return ret;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa041, 0xff);
688*4882a593Smuzhiyun 	if (ret < 0)
689*4882a593Smuzhiyun 		return ret;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa039, 0xbf00);
692*4882a593Smuzhiyun 	if (ret < 0)
693*4882a593Smuzhiyun 		return ret;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	/* nodelay duty = 0x9696 (default)
696*4882a593Smuzhiyun 	 * fixed delay duty = 0x4040
697*4882a593Smuzhiyun 	 * step delay 0xf duty = 0x4041
698*4882a593Smuzhiyun 	 */
699*4882a593Smuzhiyun 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
700*4882a593Smuzhiyun 	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
701*4882a593Smuzhiyun 		value = 0x4040;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa03a, value);
704*4882a593Smuzhiyun 	if (ret < 0)
705*4882a593Smuzhiyun 		return ret;
706*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa03b, value);
707*4882a593Smuzhiyun 	if (ret < 0)
708*4882a593Smuzhiyun 		return ret;
709*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa03c, value);
710*4882a593Smuzhiyun 	if (ret < 0)
711*4882a593Smuzhiyun 		return ret;
712*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa03d, value);
713*4882a593Smuzhiyun 	if (ret < 0)
714*4882a593Smuzhiyun 		return ret;
715*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa03e, value);
716*4882a593Smuzhiyun 	if (ret < 0)
717*4882a593Smuzhiyun 		return ret;
718*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa03f, value);
719*4882a593Smuzhiyun 	if (ret < 0)
720*4882a593Smuzhiyun 		return ret;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	return ret;
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun 
yt8531S_config_init(struct phy_device * phydev)725*4882a593Smuzhiyun static int yt8531S_config_init(struct phy_device *phydev)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun #if (YTPHY8531A_XTAL_INIT)
728*4882a593Smuzhiyun 	int ret = 0;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	ret = yt8531a_xtal_init(phydev);
731*4882a593Smuzhiyun 	if (ret < 0)
732*4882a593Smuzhiyun 		return ret;
733*4882a593Smuzhiyun #endif
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun 	return yt8521_config_init(phydev);
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun 
yt8531_config_init(struct phy_device * phydev)738*4882a593Smuzhiyun static int yt8531_config_init(struct phy_device *phydev)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun 	int ret = 0, val;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun #if (YTPHY8531A_XTAL_INIT)
743*4882a593Smuzhiyun 	ret = yt8531a_xtal_init(phydev);
744*4882a593Smuzhiyun 	if (ret < 0)
745*4882a593Smuzhiyun 		return ret;
746*4882a593Smuzhiyun #endif
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	/* PHY_CLK_OUT 125M enabled (default) */
749*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa012, 0xd0);
750*4882a593Smuzhiyun 	if (ret < 0)
751*4882a593Smuzhiyun 		return ret;
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	ret = yt8531_rxclk_duty_init(phydev);
754*4882a593Smuzhiyun 	if (ret < 0)
755*4882a593Smuzhiyun 		return ret;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	/* RXC, PHY_CLK_OUT and RXData Drive strength:
758*4882a593Smuzhiyun 	 * Drive strength of RXC = 6, PHY_CLK_OUT = 3, RXD0 = 4 (default 1.8v)
759*4882a593Smuzhiyun 	 * If the io voltage is 3.3v, PHY_CLK_OUT = 2, set 0xa010 = 0xdacf
760*4882a593Smuzhiyun 	 */
761*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0xa010, 0xdbcf);
762*4882a593Smuzhiyun 	if (ret < 0)
763*4882a593Smuzhiyun 		return ret;
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	/* Change 100M default BGS voltage from 0x294c to 0x274c */
766*4882a593Smuzhiyun 	val = ytphy_read_ext(phydev, 0x57);
767*4882a593Smuzhiyun 	val = (val & ~(0xf << 8)) | (7 << 8);
768*4882a593Smuzhiyun 	ret = ytphy_write_ext(phydev, 0x57, val);
769*4882a593Smuzhiyun 	if (ret < 0)
770*4882a593Smuzhiyun 		return ret;
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	return ret;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun static struct phy_driver motorcomm_phy_drvs[] = {
776*4882a593Smuzhiyun 	{
777*4882a593Smuzhiyun 		PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
778*4882a593Smuzhiyun 		.name		= "YT8511 Gigabit Ethernet",
779*4882a593Smuzhiyun 		.config_init	= yt8511_config_init,
780*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
781*4882a593Smuzhiyun 		.resume		= genphy_resume,
782*4882a593Smuzhiyun 		.read_page	= yt8511_read_page,
783*4882a593Smuzhiyun 		.write_page	= yt8511_write_page,
784*4882a593Smuzhiyun 	}, {
785*4882a593Smuzhiyun 		PHY_ID_MATCH_EXACT(PHY_ID_YT8512),
786*4882a593Smuzhiyun 		.name		= "YT8512 Ethernet",
787*4882a593Smuzhiyun 		.config_init	= yt8512_config_init,
788*4882a593Smuzhiyun 		.read_status	= yt8512_read_status,
789*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
790*4882a593Smuzhiyun 		.resume		= genphy_resume,
791*4882a593Smuzhiyun 	}, {
792*4882a593Smuzhiyun 		PHY_ID_MATCH_EXACT(PHY_ID_YT8512B),
793*4882a593Smuzhiyun 		.name		= "YT8512B Ethernet",
794*4882a593Smuzhiyun 		.config_init	= yt8512_config_init,
795*4882a593Smuzhiyun 		.read_status	= yt8512_read_status,
796*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
797*4882a593Smuzhiyun 		.resume		= genphy_resume,
798*4882a593Smuzhiyun 	}, {
799*4882a593Smuzhiyun 		/* same as 8521 */
800*4882a593Smuzhiyun 		PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
801*4882a593Smuzhiyun 		.name          = "YT8531S Gigabit Ethernet",
802*4882a593Smuzhiyun 		.features      = PHY_GBIT_FEATURES,
803*4882a593Smuzhiyun 		.soft_reset    = yt8521_soft_reset,
804*4882a593Smuzhiyun 		.aneg_done     = yt8521_aneg_done,
805*4882a593Smuzhiyun 		.config_init   = yt8531S_config_init,
806*4882a593Smuzhiyun 		.read_status   = yt8521_read_status,
807*4882a593Smuzhiyun 		.suspend       = yt8521_suspend,
808*4882a593Smuzhiyun 		.resume        = yt8521_resume,
809*4882a593Smuzhiyun #if (YTPHY_WOL_FEATURE_ENABLE)
810*4882a593Smuzhiyun 		.get_wol       = &ytphy_wol_feature_get,
811*4882a593Smuzhiyun 		.set_wol       = &ytphy_wol_feature_set,
812*4882a593Smuzhiyun #endif
813*4882a593Smuzhiyun 	}, {
814*4882a593Smuzhiyun 		/* same as 8511 */
815*4882a593Smuzhiyun 		PHY_ID_MATCH_EXACT(PHY_ID_YT8531),
816*4882a593Smuzhiyun 		.name          = "YT8531 Gigabit Ethernet",
817*4882a593Smuzhiyun 		.features      = PHY_GBIT_FEATURES,
818*4882a593Smuzhiyun 		.config_init   = yt8531_config_init,
819*4882a593Smuzhiyun 		.suspend       = genphy_suspend,
820*4882a593Smuzhiyun 		.resume        = genphy_resume,
821*4882a593Smuzhiyun #if (YTPHY_WOL_FEATURE_ENABLE)
822*4882a593Smuzhiyun 		.get_wol       = &ytphy_wol_feature_get,
823*4882a593Smuzhiyun 		.set_wol       = &ytphy_wol_feature_set,
824*4882a593Smuzhiyun #endif
825*4882a593Smuzhiyun 	},
826*4882a593Smuzhiyun };
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun module_phy_driver(motorcomm_phy_drvs);
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun MODULE_DESCRIPTION("Motorcomm PHY driver");
831*4882a593Smuzhiyun MODULE_AUTHOR("Peter Geis");
832*4882a593Smuzhiyun MODULE_LICENSE("GPL");
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
835*4882a593Smuzhiyun 	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
836*4882a593Smuzhiyun 	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8512) },
837*4882a593Smuzhiyun 	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8512B) },
838*4882a593Smuzhiyun 	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
839*4882a593Smuzhiyun 	{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },
840*4882a593Smuzhiyun 	{ /* sentinal */ }
841*4882a593Smuzhiyun };
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun MODULE_DEVICE_TABLE(mdio, motorcomm_tbl);
844