xref: /OK3568_Linux_fs/kernel/drivers/net/phy/nxp-tja11xx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* NXP TJA1100 BroadRReach PHY driver
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2018 Marek Vasut <marex@denx.de>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include <linux/delay.h>
7*4882a593Smuzhiyun #include <linux/ethtool.h>
8*4882a593Smuzhiyun #include <linux/ethtool_netlink.h>
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/mdio.h>
11*4882a593Smuzhiyun #include <linux/mii.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/phy.h>
14*4882a593Smuzhiyun #include <linux/hwmon.h>
15*4882a593Smuzhiyun #include <linux/bitfield.h>
16*4882a593Smuzhiyun #include <linux/of_mdio.h>
17*4882a593Smuzhiyun #include <linux/of_irq.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define PHY_ID_MASK			0xfffffff0
20*4882a593Smuzhiyun #define PHY_ID_TJA1100			0x0180dc40
21*4882a593Smuzhiyun #define PHY_ID_TJA1101			0x0180dd00
22*4882a593Smuzhiyun #define PHY_ID_TJA1102			0x0180dc80
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define MII_ECTRL			17
25*4882a593Smuzhiyun #define MII_ECTRL_LINK_CONTROL		BIT(15)
26*4882a593Smuzhiyun #define MII_ECTRL_POWER_MODE_MASK	GENMASK(14, 11)
27*4882a593Smuzhiyun #define MII_ECTRL_POWER_MODE_NO_CHANGE	(0x0 << 11)
28*4882a593Smuzhiyun #define MII_ECTRL_POWER_MODE_NORMAL	(0x3 << 11)
29*4882a593Smuzhiyun #define MII_ECTRL_POWER_MODE_STANDBY	(0xc << 11)
30*4882a593Smuzhiyun #define MII_ECTRL_CABLE_TEST		BIT(5)
31*4882a593Smuzhiyun #define MII_ECTRL_CONFIG_EN		BIT(2)
32*4882a593Smuzhiyun #define MII_ECTRL_WAKE_REQUEST		BIT(0)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define MII_CFG1			18
35*4882a593Smuzhiyun #define MII_CFG1_MASTER_SLAVE		BIT(15)
36*4882a593Smuzhiyun #define MII_CFG1_AUTO_OP		BIT(14)
37*4882a593Smuzhiyun #define MII_CFG1_SLEEP_CONFIRM		BIT(6)
38*4882a593Smuzhiyun #define MII_CFG1_LED_MODE_MASK		GENMASK(5, 4)
39*4882a593Smuzhiyun #define MII_CFG1_LED_MODE_LINKUP	0
40*4882a593Smuzhiyun #define MII_CFG1_LED_ENABLE		BIT(3)
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define MII_CFG2			19
43*4882a593Smuzhiyun #define MII_CFG2_SLEEP_REQUEST_TO	GENMASK(1, 0)
44*4882a593Smuzhiyun #define MII_CFG2_SLEEP_REQUEST_TO_16MS	0x3
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define MII_INTSRC			21
47*4882a593Smuzhiyun #define MII_INTSRC_TEMP_ERR		BIT(1)
48*4882a593Smuzhiyun #define MII_INTSRC_UV_ERR		BIT(3)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define MII_INTEN			22
51*4882a593Smuzhiyun #define MII_INTEN_LINK_FAIL		BIT(10)
52*4882a593Smuzhiyun #define MII_INTEN_LINK_UP		BIT(9)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define MII_COMMSTAT			23
55*4882a593Smuzhiyun #define MII_COMMSTAT_LINK_UP		BIT(15)
56*4882a593Smuzhiyun #define MII_COMMSTAT_SQI_STATE		GENMASK(7, 5)
57*4882a593Smuzhiyun #define MII_COMMSTAT_SQI_MAX		7
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define MII_GENSTAT			24
60*4882a593Smuzhiyun #define MII_GENSTAT_PLL_LOCKED		BIT(14)
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define MII_EXTSTAT			25
63*4882a593Smuzhiyun #define MII_EXTSTAT_SHORT_DETECT	BIT(8)
64*4882a593Smuzhiyun #define MII_EXTSTAT_OPEN_DETECT		BIT(7)
65*4882a593Smuzhiyun #define MII_EXTSTAT_POLARITY_DETECT	BIT(6)
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #define MII_COMMCFG			27
68*4882a593Smuzhiyun #define MII_COMMCFG_AUTO_OP		BIT(15)
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun struct tja11xx_priv {
71*4882a593Smuzhiyun 	char		*hwmon_name;
72*4882a593Smuzhiyun 	struct device	*hwmon_dev;
73*4882a593Smuzhiyun 	struct phy_device *phydev;
74*4882a593Smuzhiyun 	struct work_struct phy_register_work;
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun struct tja11xx_phy_stats {
78*4882a593Smuzhiyun 	const char	*string;
79*4882a593Smuzhiyun 	u8		reg;
80*4882a593Smuzhiyun 	u8		off;
81*4882a593Smuzhiyun 	u16		mask;
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun static struct tja11xx_phy_stats tja11xx_hw_stats[] = {
85*4882a593Smuzhiyun 	{ "phy_symbol_error_count", 20, 0, GENMASK(15, 0) },
86*4882a593Smuzhiyun 	{ "phy_polarity_detect", 25, 6, BIT(6) },
87*4882a593Smuzhiyun 	{ "phy_open_detect", 25, 7, BIT(7) },
88*4882a593Smuzhiyun 	{ "phy_short_detect", 25, 8, BIT(8) },
89*4882a593Smuzhiyun 	{ "phy_rem_rcvr_count", 26, 0, GENMASK(7, 0) },
90*4882a593Smuzhiyun 	{ "phy_loc_rcvr_count", 26, 8, GENMASK(15, 8) },
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
tja11xx_check(struct phy_device * phydev,u8 reg,u16 mask,u16 set)93*4882a593Smuzhiyun static int tja11xx_check(struct phy_device *phydev, u8 reg, u16 mask, u16 set)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	int val;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	return phy_read_poll_timeout(phydev, reg, val, (val & mask) == set,
98*4882a593Smuzhiyun 				     150, 30000, false);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
phy_modify_check(struct phy_device * phydev,u8 reg,u16 mask,u16 set)101*4882a593Smuzhiyun static int phy_modify_check(struct phy_device *phydev, u8 reg,
102*4882a593Smuzhiyun 			    u16 mask, u16 set)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	int ret;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	ret = phy_modify(phydev, reg, mask, set);
107*4882a593Smuzhiyun 	if (ret)
108*4882a593Smuzhiyun 		return ret;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	return tja11xx_check(phydev, reg, mask, set);
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
tja11xx_enable_reg_write(struct phy_device * phydev)113*4882a593Smuzhiyun static int tja11xx_enable_reg_write(struct phy_device *phydev)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_CONFIG_EN);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
tja11xx_enable_link_control(struct phy_device * phydev)118*4882a593Smuzhiyun static int tja11xx_enable_link_control(struct phy_device *phydev)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun 	return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
tja11xx_disable_link_control(struct phy_device * phydev)123*4882a593Smuzhiyun static int tja11xx_disable_link_control(struct phy_device *phydev)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	return phy_clear_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL);
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
tja11xx_wakeup(struct phy_device * phydev)128*4882a593Smuzhiyun static int tja11xx_wakeup(struct phy_device *phydev)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	int ret;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_ECTRL);
133*4882a593Smuzhiyun 	if (ret < 0)
134*4882a593Smuzhiyun 		return ret;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	switch (ret & MII_ECTRL_POWER_MODE_MASK) {
137*4882a593Smuzhiyun 	case MII_ECTRL_POWER_MODE_NO_CHANGE:
138*4882a593Smuzhiyun 		break;
139*4882a593Smuzhiyun 	case MII_ECTRL_POWER_MODE_NORMAL:
140*4882a593Smuzhiyun 		ret = phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_WAKE_REQUEST);
141*4882a593Smuzhiyun 		if (ret)
142*4882a593Smuzhiyun 			return ret;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 		ret = phy_clear_bits(phydev, MII_ECTRL, MII_ECTRL_WAKE_REQUEST);
145*4882a593Smuzhiyun 		if (ret)
146*4882a593Smuzhiyun 			return ret;
147*4882a593Smuzhiyun 		break;
148*4882a593Smuzhiyun 	case MII_ECTRL_POWER_MODE_STANDBY:
149*4882a593Smuzhiyun 		ret = phy_modify_check(phydev, MII_ECTRL,
150*4882a593Smuzhiyun 				       MII_ECTRL_POWER_MODE_MASK,
151*4882a593Smuzhiyun 				       MII_ECTRL_POWER_MODE_STANDBY);
152*4882a593Smuzhiyun 		if (ret)
153*4882a593Smuzhiyun 			return ret;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 		ret = phy_modify(phydev, MII_ECTRL, MII_ECTRL_POWER_MODE_MASK,
156*4882a593Smuzhiyun 				 MII_ECTRL_POWER_MODE_NORMAL);
157*4882a593Smuzhiyun 		if (ret)
158*4882a593Smuzhiyun 			return ret;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 		ret = phy_modify_check(phydev, MII_GENSTAT,
161*4882a593Smuzhiyun 				       MII_GENSTAT_PLL_LOCKED,
162*4882a593Smuzhiyun 				       MII_GENSTAT_PLL_LOCKED);
163*4882a593Smuzhiyun 		if (ret)
164*4882a593Smuzhiyun 			return ret;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 		return tja11xx_enable_link_control(phydev);
167*4882a593Smuzhiyun 	default:
168*4882a593Smuzhiyun 		break;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
tja11xx_soft_reset(struct phy_device * phydev)174*4882a593Smuzhiyun static int tja11xx_soft_reset(struct phy_device *phydev)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	int ret;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	ret = tja11xx_enable_reg_write(phydev);
179*4882a593Smuzhiyun 	if (ret)
180*4882a593Smuzhiyun 		return ret;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	return genphy_soft_reset(phydev);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun 
tja11xx_config_aneg_cable_test(struct phy_device * phydev)185*4882a593Smuzhiyun static int tja11xx_config_aneg_cable_test(struct phy_device *phydev)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun 	bool finished = false;
188*4882a593Smuzhiyun 	int ret;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (phydev->link)
191*4882a593Smuzhiyun 		return 0;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	if (!phydev->drv->cable_test_start ||
194*4882a593Smuzhiyun 	    !phydev->drv->cable_test_get_status)
195*4882a593Smuzhiyun 		return 0;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	ret = ethnl_cable_test_alloc(phydev, ETHTOOL_MSG_CABLE_TEST_NTF);
198*4882a593Smuzhiyun 	if (ret)
199*4882a593Smuzhiyun 		return ret;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	ret = phydev->drv->cable_test_start(phydev);
202*4882a593Smuzhiyun 	if (ret)
203*4882a593Smuzhiyun 		return ret;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	/* According to the documentation this test takes 100 usec */
206*4882a593Smuzhiyun 	usleep_range(100, 200);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	ret = phydev->drv->cable_test_get_status(phydev, &finished);
209*4882a593Smuzhiyun 	if (ret)
210*4882a593Smuzhiyun 		return ret;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	if (finished)
213*4882a593Smuzhiyun 		ethnl_cable_test_finished(phydev);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
tja11xx_config_aneg(struct phy_device * phydev)218*4882a593Smuzhiyun static int tja11xx_config_aneg(struct phy_device *phydev)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	int ret, changed = 0;
221*4882a593Smuzhiyun 	u16 ctl = 0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	switch (phydev->master_slave_set) {
224*4882a593Smuzhiyun 	case MASTER_SLAVE_CFG_MASTER_FORCE:
225*4882a593Smuzhiyun 		ctl |= MII_CFG1_MASTER_SLAVE;
226*4882a593Smuzhiyun 		break;
227*4882a593Smuzhiyun 	case MASTER_SLAVE_CFG_SLAVE_FORCE:
228*4882a593Smuzhiyun 		break;
229*4882a593Smuzhiyun 	case MASTER_SLAVE_CFG_UNKNOWN:
230*4882a593Smuzhiyun 	case MASTER_SLAVE_CFG_UNSUPPORTED:
231*4882a593Smuzhiyun 		goto do_test;
232*4882a593Smuzhiyun 	default:
233*4882a593Smuzhiyun 		phydev_warn(phydev, "Unsupported Master/Slave mode\n");
234*4882a593Smuzhiyun 		return -ENOTSUPP;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	changed = phy_modify_changed(phydev, MII_CFG1, MII_CFG1_MASTER_SLAVE, ctl);
238*4882a593Smuzhiyun 	if (changed < 0)
239*4882a593Smuzhiyun 		return changed;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun do_test:
242*4882a593Smuzhiyun 	ret = tja11xx_config_aneg_cable_test(phydev);
243*4882a593Smuzhiyun 	if (ret)
244*4882a593Smuzhiyun 		return ret;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	return __genphy_config_aneg(phydev, changed);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
tja11xx_config_init(struct phy_device * phydev)249*4882a593Smuzhiyun static int tja11xx_config_init(struct phy_device *phydev)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun 	int ret;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	ret = tja11xx_enable_reg_write(phydev);
254*4882a593Smuzhiyun 	if (ret)
255*4882a593Smuzhiyun 		return ret;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	phydev->autoneg = AUTONEG_DISABLE;
258*4882a593Smuzhiyun 	phydev->speed = SPEED_100;
259*4882a593Smuzhiyun 	phydev->duplex = DUPLEX_FULL;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	switch (phydev->phy_id & PHY_ID_MASK) {
262*4882a593Smuzhiyun 	case PHY_ID_TJA1100:
263*4882a593Smuzhiyun 		ret = phy_modify(phydev, MII_CFG1,
264*4882a593Smuzhiyun 				 MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK |
265*4882a593Smuzhiyun 				 MII_CFG1_LED_ENABLE,
266*4882a593Smuzhiyun 				 MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_LINKUP |
267*4882a593Smuzhiyun 				 MII_CFG1_LED_ENABLE);
268*4882a593Smuzhiyun 		if (ret)
269*4882a593Smuzhiyun 			return ret;
270*4882a593Smuzhiyun 		break;
271*4882a593Smuzhiyun 	case PHY_ID_TJA1101:
272*4882a593Smuzhiyun 	case PHY_ID_TJA1102:
273*4882a593Smuzhiyun 		ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
274*4882a593Smuzhiyun 		if (ret)
275*4882a593Smuzhiyun 			return ret;
276*4882a593Smuzhiyun 		break;
277*4882a593Smuzhiyun 	default:
278*4882a593Smuzhiyun 		return -EINVAL;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	ret = phy_clear_bits(phydev, MII_CFG1, MII_CFG1_SLEEP_CONFIRM);
282*4882a593Smuzhiyun 	if (ret)
283*4882a593Smuzhiyun 		return ret;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	ret = phy_modify(phydev, MII_CFG2, MII_CFG2_SLEEP_REQUEST_TO,
286*4882a593Smuzhiyun 			 MII_CFG2_SLEEP_REQUEST_TO_16MS);
287*4882a593Smuzhiyun 	if (ret)
288*4882a593Smuzhiyun 		return ret;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	ret = tja11xx_wakeup(phydev);
291*4882a593Smuzhiyun 	if (ret < 0)
292*4882a593Smuzhiyun 		return ret;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	/* ACK interrupts by reading the status register */
295*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_INTSRC);
296*4882a593Smuzhiyun 	if (ret < 0)
297*4882a593Smuzhiyun 		return ret;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	return 0;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun 
tja11xx_read_status(struct phy_device * phydev)302*4882a593Smuzhiyun static int tja11xx_read_status(struct phy_device *phydev)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	int ret;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
307*4882a593Smuzhiyun 	phydev->master_slave_state = MASTER_SLAVE_STATE_UNSUPPORTED;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	ret = genphy_update_link(phydev);
310*4882a593Smuzhiyun 	if (ret)
311*4882a593Smuzhiyun 		return ret;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_CFG1);
314*4882a593Smuzhiyun 	if (ret < 0)
315*4882a593Smuzhiyun 		return ret;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (ret & MII_CFG1_MASTER_SLAVE)
318*4882a593Smuzhiyun 		phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
319*4882a593Smuzhiyun 	else
320*4882a593Smuzhiyun 		phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	if (phydev->link) {
323*4882a593Smuzhiyun 		ret = phy_read(phydev, MII_COMMSTAT);
324*4882a593Smuzhiyun 		if (ret < 0)
325*4882a593Smuzhiyun 			return ret;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 		if (!(ret & MII_COMMSTAT_LINK_UP))
328*4882a593Smuzhiyun 			phydev->link = 0;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	return 0;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
tja11xx_get_sqi(struct phy_device * phydev)334*4882a593Smuzhiyun static int tja11xx_get_sqi(struct phy_device *phydev)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	int ret;
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_COMMSTAT);
339*4882a593Smuzhiyun 	if (ret < 0)
340*4882a593Smuzhiyun 		return ret;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	return FIELD_GET(MII_COMMSTAT_SQI_STATE, ret);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
tja11xx_get_sqi_max(struct phy_device * phydev)345*4882a593Smuzhiyun static int tja11xx_get_sqi_max(struct phy_device *phydev)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	return MII_COMMSTAT_SQI_MAX;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun 
tja11xx_get_sset_count(struct phy_device * phydev)350*4882a593Smuzhiyun static int tja11xx_get_sset_count(struct phy_device *phydev)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun 	return ARRAY_SIZE(tja11xx_hw_stats);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
tja11xx_get_strings(struct phy_device * phydev,u8 * data)355*4882a593Smuzhiyun static void tja11xx_get_strings(struct phy_device *phydev, u8 *data)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	int i;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++) {
360*4882a593Smuzhiyun 		strncpy(data + i * ETH_GSTRING_LEN,
361*4882a593Smuzhiyun 			tja11xx_hw_stats[i].string, ETH_GSTRING_LEN);
362*4882a593Smuzhiyun 	}
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
tja11xx_get_stats(struct phy_device * phydev,struct ethtool_stats * stats,u64 * data)365*4882a593Smuzhiyun static void tja11xx_get_stats(struct phy_device *phydev,
366*4882a593Smuzhiyun 			      struct ethtool_stats *stats, u64 *data)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	int i, ret;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(tja11xx_hw_stats); i++) {
371*4882a593Smuzhiyun 		ret = phy_read(phydev, tja11xx_hw_stats[i].reg);
372*4882a593Smuzhiyun 		if (ret < 0)
373*4882a593Smuzhiyun 			data[i] = U64_MAX;
374*4882a593Smuzhiyun 		else {
375*4882a593Smuzhiyun 			data[i] = ret & tja11xx_hw_stats[i].mask;
376*4882a593Smuzhiyun 			data[i] >>= tja11xx_hw_stats[i].off;
377*4882a593Smuzhiyun 		}
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
tja11xx_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * value)381*4882a593Smuzhiyun static int tja11xx_hwmon_read(struct device *dev,
382*4882a593Smuzhiyun 			      enum hwmon_sensor_types type,
383*4882a593Smuzhiyun 			      u32 attr, int channel, long *value)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	struct phy_device *phydev = dev_get_drvdata(dev);
386*4882a593Smuzhiyun 	int ret;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (type == hwmon_in && attr == hwmon_in_lcrit_alarm) {
389*4882a593Smuzhiyun 		ret = phy_read(phydev, MII_INTSRC);
390*4882a593Smuzhiyun 		if (ret < 0)
391*4882a593Smuzhiyun 			return ret;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 		*value = !!(ret & MII_INTSRC_TEMP_ERR);
394*4882a593Smuzhiyun 		return 0;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (type == hwmon_temp && attr == hwmon_temp_crit_alarm) {
398*4882a593Smuzhiyun 		ret = phy_read(phydev, MII_INTSRC);
399*4882a593Smuzhiyun 		if (ret < 0)
400*4882a593Smuzhiyun 			return ret;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 		*value = !!(ret & MII_INTSRC_UV_ERR);
403*4882a593Smuzhiyun 		return 0;
404*4882a593Smuzhiyun 	}
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	return -EOPNOTSUPP;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun 
tja11xx_hwmon_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)409*4882a593Smuzhiyun static umode_t tja11xx_hwmon_is_visible(const void *data,
410*4882a593Smuzhiyun 					enum hwmon_sensor_types type,
411*4882a593Smuzhiyun 					u32 attr, int channel)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun 	if (type == hwmon_in && attr == hwmon_in_lcrit_alarm)
414*4882a593Smuzhiyun 		return 0444;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	if (type == hwmon_temp && attr == hwmon_temp_crit_alarm)
417*4882a593Smuzhiyun 		return 0444;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	return 0;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun static const struct hwmon_channel_info *tja11xx_hwmon_info[] = {
423*4882a593Smuzhiyun 	HWMON_CHANNEL_INFO(in, HWMON_I_LCRIT_ALARM),
424*4882a593Smuzhiyun 	HWMON_CHANNEL_INFO(temp, HWMON_T_CRIT_ALARM),
425*4882a593Smuzhiyun 	NULL
426*4882a593Smuzhiyun };
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static const struct hwmon_ops tja11xx_hwmon_hwmon_ops = {
429*4882a593Smuzhiyun 	.is_visible	= tja11xx_hwmon_is_visible,
430*4882a593Smuzhiyun 	.read		= tja11xx_hwmon_read,
431*4882a593Smuzhiyun };
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun static const struct hwmon_chip_info tja11xx_hwmon_chip_info = {
434*4882a593Smuzhiyun 	.ops		= &tja11xx_hwmon_hwmon_ops,
435*4882a593Smuzhiyun 	.info		= tja11xx_hwmon_info,
436*4882a593Smuzhiyun };
437*4882a593Smuzhiyun 
tja11xx_hwmon_register(struct phy_device * phydev,struct tja11xx_priv * priv)438*4882a593Smuzhiyun static int tja11xx_hwmon_register(struct phy_device *phydev,
439*4882a593Smuzhiyun 				  struct tja11xx_priv *priv)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	struct device *dev = &phydev->mdio.dev;
442*4882a593Smuzhiyun 	int i;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
445*4882a593Smuzhiyun 	if (!priv->hwmon_name)
446*4882a593Smuzhiyun 		return -ENOMEM;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	for (i = 0; priv->hwmon_name[i]; i++)
449*4882a593Smuzhiyun 		if (hwmon_is_bad_char(priv->hwmon_name[i]))
450*4882a593Smuzhiyun 			priv->hwmon_name[i] = '_';
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	priv->hwmon_dev =
453*4882a593Smuzhiyun 		devm_hwmon_device_register_with_info(dev, priv->hwmon_name,
454*4882a593Smuzhiyun 						     phydev,
455*4882a593Smuzhiyun 						     &tja11xx_hwmon_chip_info,
456*4882a593Smuzhiyun 						     NULL);
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(priv->hwmon_dev);
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun 
tja11xx_probe(struct phy_device * phydev)461*4882a593Smuzhiyun static int tja11xx_probe(struct phy_device *phydev)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	struct device *dev = &phydev->mdio.dev;
464*4882a593Smuzhiyun 	struct tja11xx_priv *priv;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
467*4882a593Smuzhiyun 	if (!priv)
468*4882a593Smuzhiyun 		return -ENOMEM;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	priv->phydev = phydev;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	return tja11xx_hwmon_register(phydev, priv);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
tja1102_p1_register(struct work_struct * work)475*4882a593Smuzhiyun static void tja1102_p1_register(struct work_struct *work)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	struct tja11xx_priv *priv = container_of(work, struct tja11xx_priv,
478*4882a593Smuzhiyun 						 phy_register_work);
479*4882a593Smuzhiyun 	struct phy_device *phydev_phy0 = priv->phydev;
480*4882a593Smuzhiyun 	struct mii_bus *bus = phydev_phy0->mdio.bus;
481*4882a593Smuzhiyun 	struct device *dev = &phydev_phy0->mdio.dev;
482*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
483*4882a593Smuzhiyun 	struct device_node *child;
484*4882a593Smuzhiyun 	int ret;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	for_each_available_child_of_node(np, child) {
487*4882a593Smuzhiyun 		struct phy_device *phy;
488*4882a593Smuzhiyun 		int addr;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 		addr = of_mdio_parse_addr(dev, child);
491*4882a593Smuzhiyun 		if (addr < 0) {
492*4882a593Smuzhiyun 			dev_err(dev, "Can't parse addr\n");
493*4882a593Smuzhiyun 			continue;
494*4882a593Smuzhiyun 		} else if (addr != phydev_phy0->mdio.addr + 1) {
495*4882a593Smuzhiyun 			/* Currently we care only about double PHY chip TJA1102.
496*4882a593Smuzhiyun 			 * If some day NXP will decide to bring chips with more
497*4882a593Smuzhiyun 			 * PHYs, this logic should be reworked.
498*4882a593Smuzhiyun 			 */
499*4882a593Smuzhiyun 			dev_err(dev, "Unexpected address. Should be: %i\n",
500*4882a593Smuzhiyun 				phydev_phy0->mdio.addr + 1);
501*4882a593Smuzhiyun 			continue;
502*4882a593Smuzhiyun 		}
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 		if (mdiobus_is_registered_device(bus, addr)) {
505*4882a593Smuzhiyun 			dev_err(dev, "device is already registered\n");
506*4882a593Smuzhiyun 			continue;
507*4882a593Smuzhiyun 		}
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 		/* Real PHY ID of Port 1 is 0 */
510*4882a593Smuzhiyun 		phy = phy_device_create(bus, addr, PHY_ID_TJA1102, false, NULL);
511*4882a593Smuzhiyun 		if (IS_ERR(phy)) {
512*4882a593Smuzhiyun 			dev_err(dev, "Can't create PHY device for Port 1: %i\n",
513*4882a593Smuzhiyun 				addr);
514*4882a593Smuzhiyun 			continue;
515*4882a593Smuzhiyun 		}
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 		/* Overwrite parent device. phy_device_create() set parent to
518*4882a593Smuzhiyun 		 * the mii_bus->dev, which is not correct in case.
519*4882a593Smuzhiyun 		 */
520*4882a593Smuzhiyun 		phy->mdio.dev.parent = dev;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 		ret = of_mdiobus_phy_device_register(bus, phy, child, addr);
523*4882a593Smuzhiyun 		if (ret) {
524*4882a593Smuzhiyun 			/* All resources needed for Port 1 should be already
525*4882a593Smuzhiyun 			 * available for Port 0. Both ports use the same
526*4882a593Smuzhiyun 			 * interrupt line, so -EPROBE_DEFER would make no sense
527*4882a593Smuzhiyun 			 * here.
528*4882a593Smuzhiyun 			 */
529*4882a593Smuzhiyun 			dev_err(dev, "Can't register Port 1. Unexpected error: %i\n",
530*4882a593Smuzhiyun 				ret);
531*4882a593Smuzhiyun 			phy_device_free(phy);
532*4882a593Smuzhiyun 		}
533*4882a593Smuzhiyun 	}
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
tja1102_p0_probe(struct phy_device * phydev)536*4882a593Smuzhiyun static int tja1102_p0_probe(struct phy_device *phydev)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun 	struct device *dev = &phydev->mdio.dev;
539*4882a593Smuzhiyun 	struct tja11xx_priv *priv;
540*4882a593Smuzhiyun 	int ret;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
543*4882a593Smuzhiyun 	if (!priv)
544*4882a593Smuzhiyun 		return -ENOMEM;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	priv->phydev = phydev;
547*4882a593Smuzhiyun 	INIT_WORK(&priv->phy_register_work, tja1102_p1_register);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	ret = tja11xx_hwmon_register(phydev, priv);
550*4882a593Smuzhiyun 	if (ret)
551*4882a593Smuzhiyun 		return ret;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	schedule_work(&priv->phy_register_work);
554*4882a593Smuzhiyun 
555*4882a593Smuzhiyun 	return 0;
556*4882a593Smuzhiyun }
557*4882a593Smuzhiyun 
tja1102_match_phy_device(struct phy_device * phydev,bool port0)558*4882a593Smuzhiyun static int tja1102_match_phy_device(struct phy_device *phydev, bool port0)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	int ret;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	if ((phydev->phy_id & PHY_ID_MASK) != PHY_ID_TJA1102)
563*4882a593Smuzhiyun 		return 0;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_PHYSID2);
566*4882a593Smuzhiyun 	if (ret < 0)
567*4882a593Smuzhiyun 		return ret;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	/* TJA1102 Port 1 has phyid 0 and doesn't support temperature
570*4882a593Smuzhiyun 	 * and undervoltage alarms.
571*4882a593Smuzhiyun 	 */
572*4882a593Smuzhiyun 	if (port0)
573*4882a593Smuzhiyun 		return ret ? 1 : 0;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	return !ret;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun 
tja1102_p0_match_phy_device(struct phy_device * phydev)578*4882a593Smuzhiyun static int tja1102_p0_match_phy_device(struct phy_device *phydev)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	return tja1102_match_phy_device(phydev, true);
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
tja1102_p1_match_phy_device(struct phy_device * phydev)583*4882a593Smuzhiyun static int tja1102_p1_match_phy_device(struct phy_device *phydev)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun 	return tja1102_match_phy_device(phydev, false);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
tja11xx_ack_interrupt(struct phy_device * phydev)588*4882a593Smuzhiyun static int tja11xx_ack_interrupt(struct phy_device *phydev)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun 	int ret;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_INTSRC);
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	return (ret < 0) ? ret : 0;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
tja11xx_config_intr(struct phy_device * phydev)597*4882a593Smuzhiyun static int tja11xx_config_intr(struct phy_device *phydev)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	int value = 0;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
602*4882a593Smuzhiyun 		value = MII_INTEN_LINK_FAIL | MII_INTEN_LINK_UP;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	return phy_write(phydev, MII_INTEN, value);
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
tja11xx_cable_test_start(struct phy_device * phydev)607*4882a593Smuzhiyun static int tja11xx_cable_test_start(struct phy_device *phydev)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	int ret;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	ret = phy_clear_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
612*4882a593Smuzhiyun 	if (ret)
613*4882a593Smuzhiyun 		return ret;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	ret = tja11xx_wakeup(phydev);
616*4882a593Smuzhiyun 	if (ret < 0)
617*4882a593Smuzhiyun 		return ret;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	ret = tja11xx_disable_link_control(phydev);
620*4882a593Smuzhiyun 	if (ret < 0)
621*4882a593Smuzhiyun 		return ret;
622*4882a593Smuzhiyun 
623*4882a593Smuzhiyun 	return phy_set_bits(phydev, MII_ECTRL, MII_ECTRL_CABLE_TEST);
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun /*
627*4882a593Smuzhiyun  * | BI_DA+           | BI_DA-                 | Result
628*4882a593Smuzhiyun  * | open             | open                   | open
629*4882a593Smuzhiyun  * | + short to -     | - short to +           | short
630*4882a593Smuzhiyun  * | short to Vdd     | open                   | open
631*4882a593Smuzhiyun  * | open             | shot to Vdd            | open
632*4882a593Smuzhiyun  * | short to Vdd     | short to Vdd           | short
633*4882a593Smuzhiyun  * | shot to GND      | open                   | open
634*4882a593Smuzhiyun  * | open             | shot to GND            | open
635*4882a593Smuzhiyun  * | short to GND     | shot to GND            | short
636*4882a593Smuzhiyun  * | connected to active link partner (master) | shot and open
637*4882a593Smuzhiyun  */
tja11xx_cable_test_report_trans(u32 result)638*4882a593Smuzhiyun static int tja11xx_cable_test_report_trans(u32 result)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun 	u32 mask = MII_EXTSTAT_SHORT_DETECT | MII_EXTSTAT_OPEN_DETECT;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	if ((result & mask) == mask) {
643*4882a593Smuzhiyun 		/* connected to active link partner (master) */
644*4882a593Smuzhiyun 		return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
645*4882a593Smuzhiyun 	} else if ((result & mask) == 0) {
646*4882a593Smuzhiyun 		return ETHTOOL_A_CABLE_RESULT_CODE_OK;
647*4882a593Smuzhiyun 	} else if (result & MII_EXTSTAT_SHORT_DETECT) {
648*4882a593Smuzhiyun 		return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
649*4882a593Smuzhiyun 	} else if (result & MII_EXTSTAT_OPEN_DETECT) {
650*4882a593Smuzhiyun 		return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
651*4882a593Smuzhiyun 	} else {
652*4882a593Smuzhiyun 		return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
653*4882a593Smuzhiyun 	}
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun 
tja11xx_cable_test_report(struct phy_device * phydev)656*4882a593Smuzhiyun static int tja11xx_cable_test_report(struct phy_device *phydev)
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	int ret;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_EXTSTAT);
661*4882a593Smuzhiyun 	if (ret < 0)
662*4882a593Smuzhiyun 		return ret;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
665*4882a593Smuzhiyun 				tja11xx_cable_test_report_trans(ret));
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	return 0;
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun 
tja11xx_cable_test_get_status(struct phy_device * phydev,bool * finished)670*4882a593Smuzhiyun static int tja11xx_cable_test_get_status(struct phy_device *phydev,
671*4882a593Smuzhiyun 					 bool *finished)
672*4882a593Smuzhiyun {
673*4882a593Smuzhiyun 	int ret;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	*finished = false;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	ret = phy_read(phydev, MII_ECTRL);
678*4882a593Smuzhiyun 	if (ret < 0)
679*4882a593Smuzhiyun 		return ret;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	if (!(ret & MII_ECTRL_CABLE_TEST)) {
682*4882a593Smuzhiyun 		*finished = true;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 		ret = phy_set_bits(phydev, MII_COMMCFG, MII_COMMCFG_AUTO_OP);
685*4882a593Smuzhiyun 		if (ret)
686*4882a593Smuzhiyun 			return ret;
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 		return tja11xx_cable_test_report(phydev);
689*4882a593Smuzhiyun 	}
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	return 0;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun static struct phy_driver tja11xx_driver[] = {
695*4882a593Smuzhiyun 	{
696*4882a593Smuzhiyun 		PHY_ID_MATCH_MODEL(PHY_ID_TJA1100),
697*4882a593Smuzhiyun 		.name		= "NXP TJA1100",
698*4882a593Smuzhiyun 		.features       = PHY_BASIC_T1_FEATURES,
699*4882a593Smuzhiyun 		.probe		= tja11xx_probe,
700*4882a593Smuzhiyun 		.soft_reset	= tja11xx_soft_reset,
701*4882a593Smuzhiyun 		.config_aneg	= tja11xx_config_aneg,
702*4882a593Smuzhiyun 		.config_init	= tja11xx_config_init,
703*4882a593Smuzhiyun 		.read_status	= tja11xx_read_status,
704*4882a593Smuzhiyun 		.get_sqi	= tja11xx_get_sqi,
705*4882a593Smuzhiyun 		.get_sqi_max	= tja11xx_get_sqi_max,
706*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
707*4882a593Smuzhiyun 		.resume		= genphy_resume,
708*4882a593Smuzhiyun 		.set_loopback   = genphy_loopback,
709*4882a593Smuzhiyun 		/* Statistics */
710*4882a593Smuzhiyun 		.get_sset_count = tja11xx_get_sset_count,
711*4882a593Smuzhiyun 		.get_strings	= tja11xx_get_strings,
712*4882a593Smuzhiyun 		.get_stats	= tja11xx_get_stats,
713*4882a593Smuzhiyun 	}, {
714*4882a593Smuzhiyun 		PHY_ID_MATCH_MODEL(PHY_ID_TJA1101),
715*4882a593Smuzhiyun 		.name		= "NXP TJA1101",
716*4882a593Smuzhiyun 		.features       = PHY_BASIC_T1_FEATURES,
717*4882a593Smuzhiyun 		.probe		= tja11xx_probe,
718*4882a593Smuzhiyun 		.soft_reset	= tja11xx_soft_reset,
719*4882a593Smuzhiyun 		.config_aneg	= tja11xx_config_aneg,
720*4882a593Smuzhiyun 		.config_init	= tja11xx_config_init,
721*4882a593Smuzhiyun 		.read_status	= tja11xx_read_status,
722*4882a593Smuzhiyun 		.get_sqi	= tja11xx_get_sqi,
723*4882a593Smuzhiyun 		.get_sqi_max	= tja11xx_get_sqi_max,
724*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
725*4882a593Smuzhiyun 		.resume		= genphy_resume,
726*4882a593Smuzhiyun 		.set_loopback   = genphy_loopback,
727*4882a593Smuzhiyun 		/* Statistics */
728*4882a593Smuzhiyun 		.get_sset_count = tja11xx_get_sset_count,
729*4882a593Smuzhiyun 		.get_strings	= tja11xx_get_strings,
730*4882a593Smuzhiyun 		.get_stats	= tja11xx_get_stats,
731*4882a593Smuzhiyun 	}, {
732*4882a593Smuzhiyun 		.name		= "NXP TJA1102 Port 0",
733*4882a593Smuzhiyun 		.features       = PHY_BASIC_T1_FEATURES,
734*4882a593Smuzhiyun 		.flags          = PHY_POLL_CABLE_TEST,
735*4882a593Smuzhiyun 		.probe		= tja1102_p0_probe,
736*4882a593Smuzhiyun 		.soft_reset	= tja11xx_soft_reset,
737*4882a593Smuzhiyun 		.config_aneg	= tja11xx_config_aneg,
738*4882a593Smuzhiyun 		.config_init	= tja11xx_config_init,
739*4882a593Smuzhiyun 		.read_status	= tja11xx_read_status,
740*4882a593Smuzhiyun 		.get_sqi	= tja11xx_get_sqi,
741*4882a593Smuzhiyun 		.get_sqi_max	= tja11xx_get_sqi_max,
742*4882a593Smuzhiyun 		.match_phy_device = tja1102_p0_match_phy_device,
743*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
744*4882a593Smuzhiyun 		.resume		= genphy_resume,
745*4882a593Smuzhiyun 		.set_loopback   = genphy_loopback,
746*4882a593Smuzhiyun 		/* Statistics */
747*4882a593Smuzhiyun 		.get_sset_count = tja11xx_get_sset_count,
748*4882a593Smuzhiyun 		.get_strings	= tja11xx_get_strings,
749*4882a593Smuzhiyun 		.get_stats	= tja11xx_get_stats,
750*4882a593Smuzhiyun 		.ack_interrupt	= tja11xx_ack_interrupt,
751*4882a593Smuzhiyun 		.config_intr	= tja11xx_config_intr,
752*4882a593Smuzhiyun 		.cable_test_start = tja11xx_cable_test_start,
753*4882a593Smuzhiyun 		.cable_test_get_status = tja11xx_cable_test_get_status,
754*4882a593Smuzhiyun 	}, {
755*4882a593Smuzhiyun 		.name		= "NXP TJA1102 Port 1",
756*4882a593Smuzhiyun 		.features       = PHY_BASIC_T1_FEATURES,
757*4882a593Smuzhiyun 		.flags          = PHY_POLL_CABLE_TEST,
758*4882a593Smuzhiyun 		/* currently no probe for Port 1 is need */
759*4882a593Smuzhiyun 		.soft_reset	= tja11xx_soft_reset,
760*4882a593Smuzhiyun 		.config_aneg	= tja11xx_config_aneg,
761*4882a593Smuzhiyun 		.config_init	= tja11xx_config_init,
762*4882a593Smuzhiyun 		.read_status	= tja11xx_read_status,
763*4882a593Smuzhiyun 		.get_sqi	= tja11xx_get_sqi,
764*4882a593Smuzhiyun 		.get_sqi_max	= tja11xx_get_sqi_max,
765*4882a593Smuzhiyun 		.match_phy_device = tja1102_p1_match_phy_device,
766*4882a593Smuzhiyun 		.suspend	= genphy_suspend,
767*4882a593Smuzhiyun 		.resume		= genphy_resume,
768*4882a593Smuzhiyun 		.set_loopback   = genphy_loopback,
769*4882a593Smuzhiyun 		/* Statistics */
770*4882a593Smuzhiyun 		.get_sset_count = tja11xx_get_sset_count,
771*4882a593Smuzhiyun 		.get_strings	= tja11xx_get_strings,
772*4882a593Smuzhiyun 		.get_stats	= tja11xx_get_stats,
773*4882a593Smuzhiyun 		.ack_interrupt	= tja11xx_ack_interrupt,
774*4882a593Smuzhiyun 		.config_intr	= tja11xx_config_intr,
775*4882a593Smuzhiyun 		.cable_test_start = tja11xx_cable_test_start,
776*4882a593Smuzhiyun 		.cable_test_get_status = tja11xx_cable_test_get_status,
777*4882a593Smuzhiyun 	}
778*4882a593Smuzhiyun };
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun module_phy_driver(tja11xx_driver);
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun static struct mdio_device_id __maybe_unused tja11xx_tbl[] = {
783*4882a593Smuzhiyun 	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1100) },
784*4882a593Smuzhiyun 	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1101) },
785*4882a593Smuzhiyun 	{ PHY_ID_MATCH_MODEL(PHY_ID_TJA1102) },
786*4882a593Smuzhiyun 	{ }
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun MODULE_DEVICE_TABLE(mdio, tja11xx_tbl);
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
792*4882a593Smuzhiyun MODULE_DESCRIPTION("NXP TJA11xx BoardR-Reach PHY driver");
793*4882a593Smuzhiyun MODULE_LICENSE("GPL");
794