xref: /linux/drivers/net/phy/mxl-86110.c (revision 1b98f357dadd6ea613a435fbaef1a5dd7b35fd21)
1*b2908a98SStefano Radaelli // SPDX-License-Identifier: GPL-2.0+
2*b2908a98SStefano Radaelli /*
3*b2908a98SStefano Radaelli  * PHY driver for Maxlinear MXL86110
4*b2908a98SStefano Radaelli  *
5*b2908a98SStefano Radaelli  * Copyright 2023 MaxLinear Inc.
6*b2908a98SStefano Radaelli  *
7*b2908a98SStefano Radaelli  */
8*b2908a98SStefano Radaelli 
9*b2908a98SStefano Radaelli #include <linux/bitfield.h>
10*b2908a98SStefano Radaelli #include <linux/etherdevice.h>
11*b2908a98SStefano Radaelli #include <linux/kernel.h>
12*b2908a98SStefano Radaelli #include <linux/module.h>
13*b2908a98SStefano Radaelli #include <linux/of.h>
14*b2908a98SStefano Radaelli #include <linux/phy.h>
15*b2908a98SStefano Radaelli 
16*b2908a98SStefano Radaelli /* PHY ID */
17*b2908a98SStefano Radaelli #define PHY_ID_MXL86110		0xc1335580
18*b2908a98SStefano Radaelli 
19*b2908a98SStefano Radaelli /* required to access extended registers */
20*b2908a98SStefano Radaelli #define MXL86110_EXTD_REG_ADDR_OFFSET			0x1E
21*b2908a98SStefano Radaelli #define MXL86110_EXTD_REG_ADDR_DATA			0x1F
22*b2908a98SStefano Radaelli #define PHY_IRQ_ENABLE_REG				0x12
23*b2908a98SStefano Radaelli #define PHY_IRQ_ENABLE_REG_WOL				BIT(6)
24*b2908a98SStefano Radaelli 
25*b2908a98SStefano Radaelli /* SyncE Configuration Register - COM_EXT SYNCE_CFG */
26*b2908a98SStefano Radaelli #define MXL86110_EXT_SYNCE_CFG_REG			0xA012
27*b2908a98SStefano Radaelli #define MXL86110_EXT_SYNCE_CFG_CLK_FRE_SEL		BIT(4)
28*b2908a98SStefano Radaelli #define MXL86110_EXT_SYNCE_CFG_EN_SYNC_E_DURING_LNKDN	BIT(5)
29*b2908a98SStefano Radaelli #define MXL86110_EXT_SYNCE_CFG_EN_SYNC_E		BIT(6)
30*b2908a98SStefano Radaelli #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK		GENMASK(3, 1)
31*b2908a98SStefano Radaelli #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_125M_PLL	0
32*b2908a98SStefano Radaelli #define MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_25M		4
33*b2908a98SStefano Radaelli 
34*b2908a98SStefano Radaelli /* MAC Address registers */
35*b2908a98SStefano Radaelli #define MXL86110_EXT_MAC_ADDR_CFG1			0xA007
36*b2908a98SStefano Radaelli #define MXL86110_EXT_MAC_ADDR_CFG2			0xA008
37*b2908a98SStefano Radaelli #define MXL86110_EXT_MAC_ADDR_CFG3			0xA009
38*b2908a98SStefano Radaelli 
39*b2908a98SStefano Radaelli #define MXL86110_EXT_WOL_CFG_REG			0xA00A
40*b2908a98SStefano Radaelli #define MXL86110_WOL_CFG_WOL_MASK			BIT(3)
41*b2908a98SStefano Radaelli 
42*b2908a98SStefano Radaelli /* RGMII register */
43*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_REG			0xA003
44*b2908a98SStefano Radaelli /* delay can be adjusted in steps of about 150ps */
45*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_RX_NO_DELAY		(0x0 << 10)
46*b2908a98SStefano Radaelli /* Closest value to 2000 ps */
47*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS		(0xD << 10)
48*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_RX_DELAY_MASK		GENMASK(13, 10)
49*b2908a98SStefano Radaelli 
50*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS	(0xD << 0)
51*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_MASK	GENMASK(3, 0)
52*b2908a98SStefano Radaelli 
53*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS	(0xD << 4)
54*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_MASK	GENMASK(7, 4)
55*b2908a98SStefano Radaelli 
56*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_CFG1_FULL_MASK \
57*b2908a98SStefano Radaelli 			((MXL86110_EXT_RGMII_CFG1_RX_DELAY_MASK) | \
58*b2908a98SStefano Radaelli 			(MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_MASK) | \
59*b2908a98SStefano Radaelli 			(MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_MASK))
60*b2908a98SStefano Radaelli 
61*b2908a98SStefano Radaelli /* EXT Sleep Control register */
62*b2908a98SStefano Radaelli #define MXL86110_UTP_EXT_SLEEP_CTRL_REG			0x27
63*b2908a98SStefano Radaelli #define MXL86110_UTP_EXT_SLEEP_CTRL_EN_SLEEP_SW_OFF	0
64*b2908a98SStefano Radaelli #define MXL86110_UTP_EXT_SLEEP_CTRL_EN_SLEEP_SW_MASK	BIT(15)
65*b2908a98SStefano Radaelli 
66*b2908a98SStefano Radaelli /* RGMII In-Band Status and MDIO Configuration Register */
67*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_MDIO_CFG			0xA005
68*b2908a98SStefano Radaelli #define MXL86110_RGMII_MDIO_CFG_EPA0_MASK		GENMASK(6, 6)
69*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_MDIO_CFG_EBA_MASK		GENMASK(5, 5)
70*b2908a98SStefano Radaelli #define MXL86110_EXT_RGMII_MDIO_CFG_BA_MASK		GENMASK(4, 0)
71*b2908a98SStefano Radaelli 
72*b2908a98SStefano Radaelli #define MXL86110_MAX_LEDS	3
73*b2908a98SStefano Radaelli /* LED registers and defines */
74*b2908a98SStefano Radaelli #define MXL86110_LED0_CFG_REG 0xA00C
75*b2908a98SStefano Radaelli #define MXL86110_LED1_CFG_REG 0xA00D
76*b2908a98SStefano Radaelli #define MXL86110_LED2_CFG_REG 0xA00E
77*b2908a98SStefano Radaelli 
78*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_BLINK				BIT(13)
79*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON	BIT(12)
80*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON	BIT(11)
81*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON		BIT(10)
82*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON		BIT(9)
83*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_TX_ON			BIT(8)
84*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_RX_ON			BIT(7)
85*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_1GB_ON		BIT(6)
86*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_100MB_ON		BIT(5)
87*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_10MB_ON		BIT(4)
88*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_COLLISION		BIT(3)
89*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_1GB_BLINK		BIT(2)
90*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_100MB_BLINK		BIT(1)
91*b2908a98SStefano Radaelli #define MXL86110_LEDX_CFG_LINK_UP_10MB_BLINK		BIT(0)
92*b2908a98SStefano Radaelli 
93*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_REG			0xA00F
94*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_2HZ		0
95*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_4HZ		BIT(0)
96*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_8HZ		BIT(1)
97*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE1_16HZ		(BIT(1) | BIT(0))
98*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_2HZ		0
99*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_4HZ		BIT(2)
100*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_8HZ		BIT(3)
101*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_FREQ_MODE2_16HZ		(BIT(3) | BIT(2))
102*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_50_ON		0
103*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_67_ON		(BIT(4))
104*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_75_ON		(BIT(5))
105*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_83_ON		(BIT(5) | BIT(4))
106*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_50_OFF	(BIT(6))
107*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_33_ON		(BIT(6) | BIT(4))
108*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_25_ON		(BIT(6) | BIT(5))
109*b2908a98SStefano Radaelli #define MXL86110_LED_BLINK_CFG_DUTY_CYCLE_17_ON	(BIT(6) | BIT(5) | BIT(4))
110*b2908a98SStefano Radaelli 
111*b2908a98SStefano Radaelli /* Chip Configuration Register - COM_EXT_CHIP_CFG */
112*b2908a98SStefano Radaelli #define MXL86110_EXT_CHIP_CFG_REG			0xA001
113*b2908a98SStefano Radaelli #define MXL86110_EXT_CHIP_CFG_RXDLY_ENABLE		BIT(8)
114*b2908a98SStefano Radaelli #define MXL86110_EXT_CHIP_CFG_SW_RST_N_MODE		BIT(15)
115*b2908a98SStefano Radaelli 
116*b2908a98SStefano Radaelli /**
117*b2908a98SStefano Radaelli  * __mxl86110_write_extended_reg() - write to a PHY's extended register
118*b2908a98SStefano Radaelli  * @phydev: pointer to the PHY device structure
119*b2908a98SStefano Radaelli  * @regnum: register number to write
120*b2908a98SStefano Radaelli  * @val: value to write to @regnum
121*b2908a98SStefano Radaelli  *
122*b2908a98SStefano Radaelli  * Unlocked version of mxl86110_write_extended_reg
123*b2908a98SStefano Radaelli  *
124*b2908a98SStefano Radaelli  * Note: This function assumes the caller already holds the MDIO bus lock
125*b2908a98SStefano Radaelli  * or otherwise has exclusive access to the PHY.
126*b2908a98SStefano Radaelli  *
127*b2908a98SStefano Radaelli  * Return: 0 or negative error code
128*b2908a98SStefano Radaelli  */
129*b2908a98SStefano Radaelli static int __mxl86110_write_extended_reg(struct phy_device *phydev,
130*b2908a98SStefano Radaelli 					 u16 regnum, u16 val)
131*b2908a98SStefano Radaelli {
132*b2908a98SStefano Radaelli 	int ret;
133*b2908a98SStefano Radaelli 
134*b2908a98SStefano Radaelli 	ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum);
135*b2908a98SStefano Radaelli 	if (ret < 0)
136*b2908a98SStefano Radaelli 		return ret;
137*b2908a98SStefano Radaelli 
138*b2908a98SStefano Radaelli 	return __phy_write(phydev, MXL86110_EXTD_REG_ADDR_DATA, val);
139*b2908a98SStefano Radaelli }
140*b2908a98SStefano Radaelli 
141*b2908a98SStefano Radaelli /**
142*b2908a98SStefano Radaelli  * __mxl86110_read_extended_reg - Read a PHY's extended register
143*b2908a98SStefano Radaelli  * @phydev: pointer to the PHY device structure
144*b2908a98SStefano Radaelli  * @regnum: extended register number to read (address written to reg 30)
145*b2908a98SStefano Radaelli  *
146*b2908a98SStefano Radaelli  * Unlocked version of mxl86110_read_extended_reg
147*b2908a98SStefano Radaelli  *
148*b2908a98SStefano Radaelli  * Reads the content of a PHY extended register using the MaxLinear
149*b2908a98SStefano Radaelli  * 2-step access mechanism: write the register address to reg 30 (0x1E),
150*b2908a98SStefano Radaelli  * then read the value from reg 31 (0x1F).
151*b2908a98SStefano Radaelli  *
152*b2908a98SStefano Radaelli  * Note: This function assumes the caller already holds the MDIO bus lock
153*b2908a98SStefano Radaelli  * or otherwise has exclusive access to the PHY.
154*b2908a98SStefano Radaelli  *
155*b2908a98SStefano Radaelli  * Return: 16-bit register value on success, or negative errno code on failure.
156*b2908a98SStefano Radaelli  */
157*b2908a98SStefano Radaelli static int __mxl86110_read_extended_reg(struct phy_device *phydev, u16 regnum)
158*b2908a98SStefano Radaelli {
159*b2908a98SStefano Radaelli 	int ret;
160*b2908a98SStefano Radaelli 
161*b2908a98SStefano Radaelli 	ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum);
162*b2908a98SStefano Radaelli 	if (ret < 0)
163*b2908a98SStefano Radaelli 		return ret;
164*b2908a98SStefano Radaelli 	return __phy_read(phydev, MXL86110_EXTD_REG_ADDR_DATA);
165*b2908a98SStefano Radaelli }
166*b2908a98SStefano Radaelli 
167*b2908a98SStefano Radaelli /**
168*b2908a98SStefano Radaelli  * __mxl86110_modify_extended_reg() - modify bits of a PHY's extended register
169*b2908a98SStefano Radaelli  * @phydev: pointer to the PHY device structure
170*b2908a98SStefano Radaelli  * @regnum: register number to write
171*b2908a98SStefano Radaelli  * @mask: bit mask of bits to clear
172*b2908a98SStefano Radaelli  * @set: bit mask of bits to set
173*b2908a98SStefano Radaelli  *
174*b2908a98SStefano Radaelli  * Note: register value = (old register value & ~mask) | set.
175*b2908a98SStefano Radaelli  * This function assumes the caller already holds the MDIO bus lock
176*b2908a98SStefano Radaelli  * or otherwise has exclusive access to the PHY.
177*b2908a98SStefano Radaelli  *
178*b2908a98SStefano Radaelli  * Return: 0 or negative error code
179*b2908a98SStefano Radaelli  */
180*b2908a98SStefano Radaelli static int __mxl86110_modify_extended_reg(struct phy_device *phydev,
181*b2908a98SStefano Radaelli 					  u16 regnum, u16 mask, u16 set)
182*b2908a98SStefano Radaelli {
183*b2908a98SStefano Radaelli 	int ret;
184*b2908a98SStefano Radaelli 
185*b2908a98SStefano Radaelli 	ret = __phy_write(phydev, MXL86110_EXTD_REG_ADDR_OFFSET, regnum);
186*b2908a98SStefano Radaelli 	if (ret < 0)
187*b2908a98SStefano Radaelli 		return ret;
188*b2908a98SStefano Radaelli 
189*b2908a98SStefano Radaelli 	return __phy_modify(phydev, MXL86110_EXTD_REG_ADDR_DATA, mask, set);
190*b2908a98SStefano Radaelli }
191*b2908a98SStefano Radaelli 
192*b2908a98SStefano Radaelli /**
193*b2908a98SStefano Radaelli  * mxl86110_write_extended_reg() - Write to a PHY's extended register
194*b2908a98SStefano Radaelli  * @phydev: pointer to the PHY device structure
195*b2908a98SStefano Radaelli  * @regnum: register number to write
196*b2908a98SStefano Radaelli  * @val: value to write to @regnum
197*b2908a98SStefano Radaelli  *
198*b2908a98SStefano Radaelli  * This function writes to an extended register of the PHY using the
199*b2908a98SStefano Radaelli  * MaxLinear two-step access method (reg 0x1E/0x1F). It handles acquiring
200*b2908a98SStefano Radaelli  * and releasing the MDIO bus lock internally.
201*b2908a98SStefano Radaelli  *
202*b2908a98SStefano Radaelli  * Return: 0 or negative error code
203*b2908a98SStefano Radaelli  */
204*b2908a98SStefano Radaelli static int mxl86110_write_extended_reg(struct phy_device *phydev,
205*b2908a98SStefano Radaelli 				       u16 regnum, u16 val)
206*b2908a98SStefano Radaelli {
207*b2908a98SStefano Radaelli 	int ret;
208*b2908a98SStefano Radaelli 
209*b2908a98SStefano Radaelli 	phy_lock_mdio_bus(phydev);
210*b2908a98SStefano Radaelli 	ret = __mxl86110_write_extended_reg(phydev, regnum, val);
211*b2908a98SStefano Radaelli 	phy_unlock_mdio_bus(phydev);
212*b2908a98SStefano Radaelli 
213*b2908a98SStefano Radaelli 	return ret;
214*b2908a98SStefano Radaelli }
215*b2908a98SStefano Radaelli 
216*b2908a98SStefano Radaelli /**
217*b2908a98SStefano Radaelli  * mxl86110_read_extended_reg() - Read a PHY's extended register
218*b2908a98SStefano Radaelli  * @phydev: pointer to the PHY device structure
219*b2908a98SStefano Radaelli  * @regnum: extended register number to read
220*b2908a98SStefano Radaelli  *
221*b2908a98SStefano Radaelli  * This function reads from an extended register of the PHY using the
222*b2908a98SStefano Radaelli  * MaxLinear two-step access method (reg 0x1E/0x1F). It handles acquiring
223*b2908a98SStefano Radaelli  * and releasing the MDIO bus lock internally.
224*b2908a98SStefano Radaelli  *
225*b2908a98SStefano Radaelli  * Return: 16-bit register value on success, or negative errno code on failure
226*b2908a98SStefano Radaelli  */
227*b2908a98SStefano Radaelli static int mxl86110_read_extended_reg(struct phy_device *phydev, u16 regnum)
228*b2908a98SStefano Radaelli {
229*b2908a98SStefano Radaelli 	int ret;
230*b2908a98SStefano Radaelli 
231*b2908a98SStefano Radaelli 	phy_lock_mdio_bus(phydev);
232*b2908a98SStefano Radaelli 	ret = __mxl86110_read_extended_reg(phydev, regnum);
233*b2908a98SStefano Radaelli 	phy_unlock_mdio_bus(phydev);
234*b2908a98SStefano Radaelli 
235*b2908a98SStefano Radaelli 	return ret;
236*b2908a98SStefano Radaelli }
237*b2908a98SStefano Radaelli 
238*b2908a98SStefano Radaelli /**
239*b2908a98SStefano Radaelli  * mxl86110_get_wol() - report if wake-on-lan is enabled
240*b2908a98SStefano Radaelli  * @phydev: pointer to the phy_device
241*b2908a98SStefano Radaelli  * @wol: a pointer to a &struct ethtool_wolinfo
242*b2908a98SStefano Radaelli  */
243*b2908a98SStefano Radaelli static void mxl86110_get_wol(struct phy_device *phydev,
244*b2908a98SStefano Radaelli 			     struct ethtool_wolinfo *wol)
245*b2908a98SStefano Radaelli {
246*b2908a98SStefano Radaelli 	int val;
247*b2908a98SStefano Radaelli 
248*b2908a98SStefano Radaelli 	wol->supported = WAKE_MAGIC;
249*b2908a98SStefano Radaelli 	wol->wolopts = 0;
250*b2908a98SStefano Radaelli 	val = mxl86110_read_extended_reg(phydev, MXL86110_EXT_WOL_CFG_REG);
251*b2908a98SStefano Radaelli 	if (val >= 0 && (val & MXL86110_WOL_CFG_WOL_MASK))
252*b2908a98SStefano Radaelli 		wol->wolopts |= WAKE_MAGIC;
253*b2908a98SStefano Radaelli }
254*b2908a98SStefano Radaelli 
255*b2908a98SStefano Radaelli /**
256*b2908a98SStefano Radaelli  * mxl86110_set_wol() - enable/disable wake-on-lan
257*b2908a98SStefano Radaelli  * @phydev: pointer to the phy_device
258*b2908a98SStefano Radaelli  * @wol: a pointer to a &struct ethtool_wolinfo
259*b2908a98SStefano Radaelli  *
260*b2908a98SStefano Radaelli  * Configures the WOL Magic Packet MAC
261*b2908a98SStefano Radaelli  *
262*b2908a98SStefano Radaelli  * Return: 0 or negative errno code
263*b2908a98SStefano Radaelli  */
264*b2908a98SStefano Radaelli static int mxl86110_set_wol(struct phy_device *phydev,
265*b2908a98SStefano Radaelli 			    struct ethtool_wolinfo *wol)
266*b2908a98SStefano Radaelli {
267*b2908a98SStefano Radaelli 	struct net_device *netdev;
268*b2908a98SStefano Radaelli 	const unsigned char *mac;
269*b2908a98SStefano Radaelli 	int ret = 0;
270*b2908a98SStefano Radaelli 
271*b2908a98SStefano Radaelli 	phy_lock_mdio_bus(phydev);
272*b2908a98SStefano Radaelli 
273*b2908a98SStefano Radaelli 	if (wol->wolopts & WAKE_MAGIC) {
274*b2908a98SStefano Radaelli 		netdev = phydev->attached_dev;
275*b2908a98SStefano Radaelli 		if (!netdev) {
276*b2908a98SStefano Radaelli 			ret = -ENODEV;
277*b2908a98SStefano Radaelli 			goto out;
278*b2908a98SStefano Radaelli 		}
279*b2908a98SStefano Radaelli 
280*b2908a98SStefano Radaelli 		/* Configure the MAC address of the WOL magic packet */
281*b2908a98SStefano Radaelli 		mac = netdev->dev_addr;
282*b2908a98SStefano Radaelli 		ret = __mxl86110_write_extended_reg(phydev,
283*b2908a98SStefano Radaelli 						    MXL86110_EXT_MAC_ADDR_CFG1,
284*b2908a98SStefano Radaelli 						    ((mac[0] << 8) | mac[1]));
285*b2908a98SStefano Radaelli 		if (ret < 0)
286*b2908a98SStefano Radaelli 			goto out;
287*b2908a98SStefano Radaelli 
288*b2908a98SStefano Radaelli 		ret = __mxl86110_write_extended_reg(phydev,
289*b2908a98SStefano Radaelli 						    MXL86110_EXT_MAC_ADDR_CFG2,
290*b2908a98SStefano Radaelli 						    ((mac[2] << 8) | mac[3]));
291*b2908a98SStefano Radaelli 		if (ret < 0)
292*b2908a98SStefano Radaelli 			goto out;
293*b2908a98SStefano Radaelli 
294*b2908a98SStefano Radaelli 		ret = __mxl86110_write_extended_reg(phydev,
295*b2908a98SStefano Radaelli 						    MXL86110_EXT_MAC_ADDR_CFG3,
296*b2908a98SStefano Radaelli 						    ((mac[4] << 8) | mac[5]));
297*b2908a98SStefano Radaelli 		if (ret < 0)
298*b2908a98SStefano Radaelli 			goto out;
299*b2908a98SStefano Radaelli 
300*b2908a98SStefano Radaelli 		ret = __mxl86110_modify_extended_reg(phydev,
301*b2908a98SStefano Radaelli 						     MXL86110_EXT_WOL_CFG_REG,
302*b2908a98SStefano Radaelli 						     MXL86110_WOL_CFG_WOL_MASK,
303*b2908a98SStefano Radaelli 						     MXL86110_WOL_CFG_WOL_MASK);
304*b2908a98SStefano Radaelli 		if (ret < 0)
305*b2908a98SStefano Radaelli 			goto out;
306*b2908a98SStefano Radaelli 
307*b2908a98SStefano Radaelli 		/* Enables Wake-on-LAN interrupt in the PHY. */
308*b2908a98SStefano Radaelli 		ret = __phy_modify(phydev, PHY_IRQ_ENABLE_REG, 0,
309*b2908a98SStefano Radaelli 				   PHY_IRQ_ENABLE_REG_WOL);
310*b2908a98SStefano Radaelli 		if (ret < 0)
311*b2908a98SStefano Radaelli 			goto out;
312*b2908a98SStefano Radaelli 
313*b2908a98SStefano Radaelli 		phydev_dbg(phydev,
314*b2908a98SStefano Radaelli 			   "%s, MAC Addr: %02X:%02X:%02X:%02X:%02X:%02X\n",
315*b2908a98SStefano Radaelli 			   __func__,
316*b2908a98SStefano Radaelli 			   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
317*b2908a98SStefano Radaelli 	} else {
318*b2908a98SStefano Radaelli 		ret = __mxl86110_modify_extended_reg(phydev,
319*b2908a98SStefano Radaelli 						     MXL86110_EXT_WOL_CFG_REG,
320*b2908a98SStefano Radaelli 						     MXL86110_WOL_CFG_WOL_MASK,
321*b2908a98SStefano Radaelli 						     0);
322*b2908a98SStefano Radaelli 		if (ret < 0)
323*b2908a98SStefano Radaelli 			goto out;
324*b2908a98SStefano Radaelli 
325*b2908a98SStefano Radaelli 		/* Disables Wake-on-LAN interrupt in the PHY. */
326*b2908a98SStefano Radaelli 		ret = __phy_modify(phydev, PHY_IRQ_ENABLE_REG,
327*b2908a98SStefano Radaelli 				   PHY_IRQ_ENABLE_REG_WOL, 0);
328*b2908a98SStefano Radaelli 	}
329*b2908a98SStefano Radaelli 
330*b2908a98SStefano Radaelli out:
331*b2908a98SStefano Radaelli 	phy_unlock_mdio_bus(phydev);
332*b2908a98SStefano Radaelli 	return ret;
333*b2908a98SStefano Radaelli }
334*b2908a98SStefano Radaelli 
335*b2908a98SStefano Radaelli static const unsigned long supported_trgs = (BIT(TRIGGER_NETDEV_LINK_10) |
336*b2908a98SStefano Radaelli 					     BIT(TRIGGER_NETDEV_LINK_100) |
337*b2908a98SStefano Radaelli 					     BIT(TRIGGER_NETDEV_LINK_1000) |
338*b2908a98SStefano Radaelli 					     BIT(TRIGGER_NETDEV_HALF_DUPLEX) |
339*b2908a98SStefano Radaelli 					     BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
340*b2908a98SStefano Radaelli 					     BIT(TRIGGER_NETDEV_TX) |
341*b2908a98SStefano Radaelli 					     BIT(TRIGGER_NETDEV_RX));
342*b2908a98SStefano Radaelli 
343*b2908a98SStefano Radaelli static int mxl86110_led_hw_is_supported(struct phy_device *phydev, u8 index,
344*b2908a98SStefano Radaelli 					unsigned long rules)
345*b2908a98SStefano Radaelli {
346*b2908a98SStefano Radaelli 	if (index >= MXL86110_MAX_LEDS)
347*b2908a98SStefano Radaelli 		return -EINVAL;
348*b2908a98SStefano Radaelli 
349*b2908a98SStefano Radaelli 	/* All combinations of the supported triggers are allowed */
350*b2908a98SStefano Radaelli 	if (rules & ~supported_trgs)
351*b2908a98SStefano Radaelli 		return -EOPNOTSUPP;
352*b2908a98SStefano Radaelli 
353*b2908a98SStefano Radaelli 	return 0;
354*b2908a98SStefano Radaelli }
355*b2908a98SStefano Radaelli 
356*b2908a98SStefano Radaelli static int mxl86110_led_hw_control_get(struct phy_device *phydev, u8 index,
357*b2908a98SStefano Radaelli 				       unsigned long *rules)
358*b2908a98SStefano Radaelli {
359*b2908a98SStefano Radaelli 	int val;
360*b2908a98SStefano Radaelli 
361*b2908a98SStefano Radaelli 	if (index >= MXL86110_MAX_LEDS)
362*b2908a98SStefano Radaelli 		return -EINVAL;
363*b2908a98SStefano Radaelli 
364*b2908a98SStefano Radaelli 	val = mxl86110_read_extended_reg(phydev,
365*b2908a98SStefano Radaelli 					 MXL86110_LED0_CFG_REG + index);
366*b2908a98SStefano Radaelli 	if (val < 0)
367*b2908a98SStefano Radaelli 		return val;
368*b2908a98SStefano Radaelli 
369*b2908a98SStefano Radaelli 	if (val & MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON)
370*b2908a98SStefano Radaelli 		*rules |= BIT(TRIGGER_NETDEV_TX);
371*b2908a98SStefano Radaelli 
372*b2908a98SStefano Radaelli 	if (val & MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON)
373*b2908a98SStefano Radaelli 		*rules |= BIT(TRIGGER_NETDEV_RX);
374*b2908a98SStefano Radaelli 
375*b2908a98SStefano Radaelli 	if (val & MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON)
376*b2908a98SStefano Radaelli 		*rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX);
377*b2908a98SStefano Radaelli 
378*b2908a98SStefano Radaelli 	if (val & MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON)
379*b2908a98SStefano Radaelli 		*rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX);
380*b2908a98SStefano Radaelli 
381*b2908a98SStefano Radaelli 	if (val & MXL86110_LEDX_CFG_LINK_UP_10MB_ON)
382*b2908a98SStefano Radaelli 		*rules |= BIT(TRIGGER_NETDEV_LINK_10);
383*b2908a98SStefano Radaelli 
384*b2908a98SStefano Radaelli 	if (val & MXL86110_LEDX_CFG_LINK_UP_100MB_ON)
385*b2908a98SStefano Radaelli 		*rules |= BIT(TRIGGER_NETDEV_LINK_100);
386*b2908a98SStefano Radaelli 
387*b2908a98SStefano Radaelli 	if (val & MXL86110_LEDX_CFG_LINK_UP_1GB_ON)
388*b2908a98SStefano Radaelli 		*rules |= BIT(TRIGGER_NETDEV_LINK_1000);
389*b2908a98SStefano Radaelli 
390*b2908a98SStefano Radaelli 	return 0;
391*b2908a98SStefano Radaelli }
392*b2908a98SStefano Radaelli 
393*b2908a98SStefano Radaelli static int mxl86110_led_hw_control_set(struct phy_device *phydev, u8 index,
394*b2908a98SStefano Radaelli 				       unsigned long rules)
395*b2908a98SStefano Radaelli {
396*b2908a98SStefano Radaelli 	u16 val = 0;
397*b2908a98SStefano Radaelli 
398*b2908a98SStefano Radaelli 	if (index >= MXL86110_MAX_LEDS)
399*b2908a98SStefano Radaelli 		return -EINVAL;
400*b2908a98SStefano Radaelli 
401*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_LINK_10))
402*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_LINK_UP_10MB_ON;
403*b2908a98SStefano Radaelli 
404*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_LINK_100))
405*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_LINK_UP_100MB_ON;
406*b2908a98SStefano Radaelli 
407*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_LINK_1000))
408*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_LINK_UP_1GB_ON;
409*b2908a98SStefano Radaelli 
410*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_TX))
411*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_LINK_UP_TX_ACT_ON;
412*b2908a98SStefano Radaelli 
413*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_RX))
414*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_LINK_UP_RX_ACT_ON;
415*b2908a98SStefano Radaelli 
416*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
417*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_LINK_UP_HALF_DUPLEX_ON;
418*b2908a98SStefano Radaelli 
419*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
420*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_LINK_UP_FULL_DUPLEX_ON;
421*b2908a98SStefano Radaelli 
422*b2908a98SStefano Radaelli 	if (rules & BIT(TRIGGER_NETDEV_TX) ||
423*b2908a98SStefano Radaelli 	    rules & BIT(TRIGGER_NETDEV_RX))
424*b2908a98SStefano Radaelli 		val |= MXL86110_LEDX_CFG_BLINK;
425*b2908a98SStefano Radaelli 
426*b2908a98SStefano Radaelli 	return mxl86110_write_extended_reg(phydev,
427*b2908a98SStefano Radaelli 					  MXL86110_LED0_CFG_REG + index, val);
428*b2908a98SStefano Radaelli }
429*b2908a98SStefano Radaelli 
430*b2908a98SStefano Radaelli /**
431*b2908a98SStefano Radaelli  * mxl86110_synce_clk_cfg() - applies syncE/clk output configuration
432*b2908a98SStefano Radaelli  * @phydev: pointer to the phy_device
433*b2908a98SStefano Radaelli  *
434*b2908a98SStefano Radaelli  * Note: This function assumes the caller already holds the MDIO bus lock
435*b2908a98SStefano Radaelli  * or otherwise has exclusive access to the PHY.
436*b2908a98SStefano Radaelli  *
437*b2908a98SStefano Radaelli  * Return: 0 or negative errno code
438*b2908a98SStefano Radaelli  */
439*b2908a98SStefano Radaelli static int mxl86110_synce_clk_cfg(struct phy_device *phydev)
440*b2908a98SStefano Radaelli {
441*b2908a98SStefano Radaelli 	u16 mask = 0, val = 0;
442*b2908a98SStefano Radaelli 
443*b2908a98SStefano Radaelli 	/*
444*b2908a98SStefano Radaelli 	 * Configures the clock output to its default
445*b2908a98SStefano Radaelli 	 * setting as per the datasheet.
446*b2908a98SStefano Radaelli 	 * This results in a 25MHz clock output being selected in the
447*b2908a98SStefano Radaelli 	 * COM_EXT_SYNCE_CFG register for SyncE configuration.
448*b2908a98SStefano Radaelli 	 */
449*b2908a98SStefano Radaelli 	val = MXL86110_EXT_SYNCE_CFG_EN_SYNC_E |
450*b2908a98SStefano Radaelli 			FIELD_PREP(MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK,
451*b2908a98SStefano Radaelli 				   MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_25M);
452*b2908a98SStefano Radaelli 	mask = MXL86110_EXT_SYNCE_CFG_EN_SYNC_E |
453*b2908a98SStefano Radaelli 	       MXL86110_EXT_SYNCE_CFG_CLK_SRC_SEL_MASK |
454*b2908a98SStefano Radaelli 	       MXL86110_EXT_SYNCE_CFG_CLK_FRE_SEL;
455*b2908a98SStefano Radaelli 
456*b2908a98SStefano Radaelli 	/* Write clock output configuration */
457*b2908a98SStefano Radaelli 	return __mxl86110_modify_extended_reg(phydev,
458*b2908a98SStefano Radaelli 					      MXL86110_EXT_SYNCE_CFG_REG,
459*b2908a98SStefano Radaelli 					      mask, val);
460*b2908a98SStefano Radaelli }
461*b2908a98SStefano Radaelli 
462*b2908a98SStefano Radaelli /**
463*b2908a98SStefano Radaelli  * mxl86110_broadcast_cfg - Configure MDIO broadcast setting for PHY
464*b2908a98SStefano Radaelli  * @phydev: Pointer to the PHY device structure
465*b2908a98SStefano Radaelli  *
466*b2908a98SStefano Radaelli  * This function configures the MDIO broadcast behavior of the MxL86110 PHY.
467*b2908a98SStefano Radaelli  * Currently, broadcast mode is explicitly disabled by clearing the EPA0 bit
468*b2908a98SStefano Radaelli  * in the RGMII_MDIO_CFG extended register.
469*b2908a98SStefano Radaelli  *
470*b2908a98SStefano Radaelli  * Note: This function assumes the caller already holds the MDIO bus lock
471*b2908a98SStefano Radaelli  * or otherwise has exclusive access to the PHY.
472*b2908a98SStefano Radaelli  *
473*b2908a98SStefano Radaelli  * Return: 0 on success or a negative errno code on failure.
474*b2908a98SStefano Radaelli  */
475*b2908a98SStefano Radaelli static int mxl86110_broadcast_cfg(struct phy_device *phydev)
476*b2908a98SStefano Radaelli {
477*b2908a98SStefano Radaelli 	return __mxl86110_modify_extended_reg(phydev,
478*b2908a98SStefano Radaelli 					      MXL86110_EXT_RGMII_MDIO_CFG,
479*b2908a98SStefano Radaelli 					      MXL86110_RGMII_MDIO_CFG_EPA0_MASK,
480*b2908a98SStefano Radaelli 					      0);
481*b2908a98SStefano Radaelli }
482*b2908a98SStefano Radaelli 
483*b2908a98SStefano Radaelli /**
484*b2908a98SStefano Radaelli  * mxl86110_enable_led_activity_blink - Enable LEDs activity blink on PHY
485*b2908a98SStefano Radaelli  * @phydev: Pointer to the PHY device structure
486*b2908a98SStefano Radaelli  *
487*b2908a98SStefano Radaelli  * Configure all PHY LEDs to blink on traffic activity regardless of whether
488*b2908a98SStefano Radaelli  * they are ON or OFF. This behavior allows each LED to serve as a pure activity
489*b2908a98SStefano Radaelli  * indicator, independently of its use as a link status indicator.
490*b2908a98SStefano Radaelli  *
491*b2908a98SStefano Radaelli  * By default, each LED blinks only when it is also in the ON state.
492*b2908a98SStefano Radaelli  * This function modifies the appropriate registers (LABx fields)
493*b2908a98SStefano Radaelli  * to enable blinking even when the LEDs are OFF, to allow the LED to be used
494*b2908a98SStefano Radaelli  * as a traffic indicator without requiring it to also serve
495*b2908a98SStefano Radaelli  * as a link status LED.
496*b2908a98SStefano Radaelli  *
497*b2908a98SStefano Radaelli  * Note: Any further LED customization can be performed via the
498*b2908a98SStefano Radaelli  * /sys/class/leds interface; the functions led_hw_is_supported,
499*b2908a98SStefano Radaelli  * led_hw_control_get, and led_hw_control_set are used
500*b2908a98SStefano Radaelli  * to support this mechanism.
501*b2908a98SStefano Radaelli  *
502*b2908a98SStefano Radaelli  * This function assumes the caller already holds the MDIO bus lock
503*b2908a98SStefano Radaelli  * or otherwise has exclusive access to the PHY.
504*b2908a98SStefano Radaelli  *
505*b2908a98SStefano Radaelli  * Return: 0 on success or a negative errno code on failure.
506*b2908a98SStefano Radaelli  */
507*b2908a98SStefano Radaelli static int mxl86110_enable_led_activity_blink(struct phy_device *phydev)
508*b2908a98SStefano Radaelli {
509*b2908a98SStefano Radaelli 	int i, ret = 0;
510*b2908a98SStefano Radaelli 
511*b2908a98SStefano Radaelli 	for (i = 0; i < MXL86110_MAX_LEDS; i++) {
512*b2908a98SStefano Radaelli 		ret = __mxl86110_modify_extended_reg(phydev,
513*b2908a98SStefano Radaelli 						     MXL86110_LED0_CFG_REG + i,
514*b2908a98SStefano Radaelli 						     0,
515*b2908a98SStefano Radaelli 						     MXL86110_LEDX_CFG_BLINK);
516*b2908a98SStefano Radaelli 		if (ret < 0)
517*b2908a98SStefano Radaelli 			break;
518*b2908a98SStefano Radaelli 	}
519*b2908a98SStefano Radaelli 
520*b2908a98SStefano Radaelli 	return ret;
521*b2908a98SStefano Radaelli }
522*b2908a98SStefano Radaelli 
523*b2908a98SStefano Radaelli /**
524*b2908a98SStefano Radaelli  * mxl86110_config_init() - initialize the PHY
525*b2908a98SStefano Radaelli  * @phydev: pointer to the phy_device
526*b2908a98SStefano Radaelli  *
527*b2908a98SStefano Radaelli  * Return: 0 or negative errno code
528*b2908a98SStefano Radaelli  */
529*b2908a98SStefano Radaelli static int mxl86110_config_init(struct phy_device *phydev)
530*b2908a98SStefano Radaelli {
531*b2908a98SStefano Radaelli 	u16 val = 0;
532*b2908a98SStefano Radaelli 	int ret;
533*b2908a98SStefano Radaelli 
534*b2908a98SStefano Radaelli 	phy_lock_mdio_bus(phydev);
535*b2908a98SStefano Radaelli 
536*b2908a98SStefano Radaelli 	/* configure syncE / clk output */
537*b2908a98SStefano Radaelli 	ret = mxl86110_synce_clk_cfg(phydev);
538*b2908a98SStefano Radaelli 	if (ret < 0)
539*b2908a98SStefano Radaelli 		goto out;
540*b2908a98SStefano Radaelli 
541*b2908a98SStefano Radaelli 	switch (phydev->interface) {
542*b2908a98SStefano Radaelli 	case PHY_INTERFACE_MODE_RGMII:
543*b2908a98SStefano Radaelli 		val = 0;
544*b2908a98SStefano Radaelli 		break;
545*b2908a98SStefano Radaelli 	case PHY_INTERFACE_MODE_RGMII_RXID:
546*b2908a98SStefano Radaelli 		val = MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS;
547*b2908a98SStefano Radaelli 		break;
548*b2908a98SStefano Radaelli 	case PHY_INTERFACE_MODE_RGMII_TXID:
549*b2908a98SStefano Radaelli 		val = MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS |
550*b2908a98SStefano Radaelli 			MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS;
551*b2908a98SStefano Radaelli 		break;
552*b2908a98SStefano Radaelli 	case PHY_INTERFACE_MODE_RGMII_ID:
553*b2908a98SStefano Radaelli 		val = MXL86110_EXT_RGMII_CFG1_TX_1G_DELAY_1950PS |
554*b2908a98SStefano Radaelli 			MXL86110_EXT_RGMII_CFG1_TX_10MB_100MB_DELAY_1950PS |
555*b2908a98SStefano Radaelli 			MXL86110_EXT_RGMII_CFG1_RX_DELAY_1950PS;
556*b2908a98SStefano Radaelli 		break;
557*b2908a98SStefano Radaelli 	default:
558*b2908a98SStefano Radaelli 		ret = -EINVAL;
559*b2908a98SStefano Radaelli 		goto out;
560*b2908a98SStefano Radaelli 	}
561*b2908a98SStefano Radaelli 
562*b2908a98SStefano Radaelli 	ret = __mxl86110_modify_extended_reg(phydev,
563*b2908a98SStefano Radaelli 					     MXL86110_EXT_RGMII_CFG1_REG,
564*b2908a98SStefano Radaelli 					     MXL86110_EXT_RGMII_CFG1_FULL_MASK,
565*b2908a98SStefano Radaelli 					     val);
566*b2908a98SStefano Radaelli 	if (ret < 0)
567*b2908a98SStefano Radaelli 		goto out;
568*b2908a98SStefano Radaelli 
569*b2908a98SStefano Radaelli 	/* Configure RXDLY (RGMII Rx Clock Delay) to disable
570*b2908a98SStefano Radaelli 	 * the default additional delay value on RX_CLK
571*b2908a98SStefano Radaelli 	 * (2 ns for 125 MHz, 8 ns for 25 MHz/2.5 MHz)
572*b2908a98SStefano Radaelli 	 * and use just the digital one selected before
573*b2908a98SStefano Radaelli 	 */
574*b2908a98SStefano Radaelli 	ret = __mxl86110_modify_extended_reg(phydev,
575*b2908a98SStefano Radaelli 					     MXL86110_EXT_CHIP_CFG_REG,
576*b2908a98SStefano Radaelli 					     MXL86110_EXT_CHIP_CFG_RXDLY_ENABLE,
577*b2908a98SStefano Radaelli 					     0);
578*b2908a98SStefano Radaelli 	if (ret < 0)
579*b2908a98SStefano Radaelli 		goto out;
580*b2908a98SStefano Radaelli 
581*b2908a98SStefano Radaelli 	ret = mxl86110_enable_led_activity_blink(phydev);
582*b2908a98SStefano Radaelli 	if (ret < 0)
583*b2908a98SStefano Radaelli 		goto out;
584*b2908a98SStefano Radaelli 
585*b2908a98SStefano Radaelli 	ret = mxl86110_broadcast_cfg(phydev);
586*b2908a98SStefano Radaelli 
587*b2908a98SStefano Radaelli out:
588*b2908a98SStefano Radaelli 	phy_unlock_mdio_bus(phydev);
589*b2908a98SStefano Radaelli 	return ret;
590*b2908a98SStefano Radaelli }
591*b2908a98SStefano Radaelli 
592*b2908a98SStefano Radaelli static struct phy_driver mxl_phy_drvs[] = {
593*b2908a98SStefano Radaelli 	{
594*b2908a98SStefano Radaelli 		PHY_ID_MATCH_EXACT(PHY_ID_MXL86110),
595*b2908a98SStefano Radaelli 		.name			= "MXL86110 Gigabit Ethernet",
596*b2908a98SStefano Radaelli 		.config_init		= mxl86110_config_init,
597*b2908a98SStefano Radaelli 		.get_wol		= mxl86110_get_wol,
598*b2908a98SStefano Radaelli 		.set_wol		= mxl86110_set_wol,
599*b2908a98SStefano Radaelli 		.led_hw_is_supported	= mxl86110_led_hw_is_supported,
600*b2908a98SStefano Radaelli 		.led_hw_control_get     = mxl86110_led_hw_control_get,
601*b2908a98SStefano Radaelli 		.led_hw_control_set     = mxl86110_led_hw_control_set,
602*b2908a98SStefano Radaelli 	},
603*b2908a98SStefano Radaelli };
604*b2908a98SStefano Radaelli 
605*b2908a98SStefano Radaelli module_phy_driver(mxl_phy_drvs);
606*b2908a98SStefano Radaelli 
607*b2908a98SStefano Radaelli static const struct mdio_device_id __maybe_unused mxl_tbl[] = {
608*b2908a98SStefano Radaelli 	{ PHY_ID_MATCH_EXACT(PHY_ID_MXL86110) },
609*b2908a98SStefano Radaelli 	{  }
610*b2908a98SStefano Radaelli };
611*b2908a98SStefano Radaelli 
612*b2908a98SStefano Radaelli MODULE_DEVICE_TABLE(mdio, mxl_tbl);
613*b2908a98SStefano Radaelli 
614*b2908a98SStefano Radaelli MODULE_DESCRIPTION("MaxLinear MXL86110 PHY driver");
615*b2908a98SStefano Radaelli MODULE_AUTHOR("Stefano Radaelli");
616*b2908a98SStefano Radaelli MODULE_LICENSE("GPL");
617