xref: /openbmc/linux/drivers/net/phy/bcm7xxx.c (revision a3622f2c)
1b560a58cSFlorian Fainelli /*
2b560a58cSFlorian Fainelli  * Broadcom BCM7xxx internal transceivers support.
3b560a58cSFlorian Fainelli  *
4b560a58cSFlorian Fainelli  * Copyright (C) 2014, Broadcom Corporation
5b560a58cSFlorian Fainelli  *
6b560a58cSFlorian Fainelli  * This program is free software; you can redistribute it and/or
7b560a58cSFlorian Fainelli  * modify it under the terms of the GNU General Public License
8b560a58cSFlorian Fainelli  * as published by the Free Software Foundation; either version
9b560a58cSFlorian Fainelli  * 2 of the License, or (at your option) any later version.
10b560a58cSFlorian Fainelli  */
11b560a58cSFlorian Fainelli 
12b560a58cSFlorian Fainelli #include <linux/module.h>
13b560a58cSFlorian Fainelli #include <linux/phy.h>
14b560a58cSFlorian Fainelli #include <linux/delay.h>
15b560a58cSFlorian Fainelli #include <linux/bitops.h>
16b560a58cSFlorian Fainelli #include <linux/brcmphy.h>
17b560a58cSFlorian Fainelli 
18b560a58cSFlorian Fainelli /* Broadcom BCM7xxx internal PHY registers */
19b560a58cSFlorian Fainelli #define MII_BCM7XXX_CHANNEL_WIDTH	0x2000
20b560a58cSFlorian Fainelli 
21b560a58cSFlorian Fainelli /* 40nm only register definitions */
22b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_AUX_CTL	0x10
23b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_FALSE_CAR	0x13
24b560a58cSFlorian Fainelli #define MII_BCM7XXX_100TX_DISC		0x14
25b560a58cSFlorian Fainelli #define MII_BCM7XXX_AUX_MODE		0x1d
26b560a58cSFlorian Fainelli #define  MII_BCM7XX_64CLK_MDIO		BIT(12)
27b560a58cSFlorian Fainelli #define MII_BCM7XXX_CORE_BASE1E		0x1e
28b560a58cSFlorian Fainelli #define MII_BCM7XXX_TEST		0x1f
29b560a58cSFlorian Fainelli #define  MII_BCM7XXX_SHD_MODE_2		BIT(2)
30b560a58cSFlorian Fainelli 
31a3622f2cSFlorian Fainelli /* 28nm only register definitions */
32a3622f2cSFlorian Fainelli #define MISC_ADDR(base, channel)	base, channel
33a3622f2cSFlorian Fainelli 
34a3622f2cSFlorian Fainelli #define DSP_TAP10			MISC_ADDR(0x0a, 0)
35a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_1			MISC_ADDR(0x32, 1)
36a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_2			MISC_ADDR(0x32, 2)
37a3622f2cSFlorian Fainelli #define PLL_PLLCTRL_4			MISC_ADDR(0x33, 0)
38a3622f2cSFlorian Fainelli 
39a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_0			MISC_ADDR(0x38, 0)
40a3622f2cSFlorian Fainelli #define AFE_RXCONFIG_1			MISC_ADDR(0x38, 1)
41a3622f2cSFlorian Fainelli #define AFE_RX_LP_COUNTER		MISC_ADDR(0x38, 3)
42a3622f2cSFlorian Fainelli #define AFE_TX_CONFIG			MISC_ADDR(0x39, 0)
43a3622f2cSFlorian Fainelli #define AFE_HPF_TRIM_OTHERS		MISC_ADDR(0x3a, 0)
44a3622f2cSFlorian Fainelli 
45a3622f2cSFlorian Fainelli #define CORE_EXPB0			0xb0
46a3622f2cSFlorian Fainelli 
47b560a58cSFlorian Fainelli static int bcm7445_config_init(struct phy_device *phydev)
48b560a58cSFlorian Fainelli {
49b560a58cSFlorian Fainelli 	int ret;
50b560a58cSFlorian Fainelli 	const struct bcm7445_regs {
51b560a58cSFlorian Fainelli 		int reg;
52b560a58cSFlorian Fainelli 		u16 value;
53b560a58cSFlorian Fainelli 	} bcm7445_regs_cfg[] = {
54b560a58cSFlorian Fainelli 		/* increases ADC latency by 24ns */
55b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x0038 },
56b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0xAB95 },
57b560a58cSFlorian Fainelli 		/* increases internal 1V LDO voltage by 5% */
58b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x2038 },
59b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0xBB22 },
60b560a58cSFlorian Fainelli 		/* reduce RX low pass filter corner frequency */
61b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x6038 },
62b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0xFFC5 },
63b560a58cSFlorian Fainelli 		/* reduce RX high pass filter corner frequency */
64b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_SEL, 0x003a },
65b560a58cSFlorian Fainelli 		{ MII_BCM54XX_EXP_DATA, 0x2002 },
66b560a58cSFlorian Fainelli 	};
67b560a58cSFlorian Fainelli 	unsigned int i;
68b560a58cSFlorian Fainelli 
69b560a58cSFlorian Fainelli 	for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) {
70b560a58cSFlorian Fainelli 		ret = phy_write(phydev,
71b560a58cSFlorian Fainelli 				bcm7445_regs_cfg[i].reg,
72b560a58cSFlorian Fainelli 				bcm7445_regs_cfg[i].value);
73b560a58cSFlorian Fainelli 		if (ret)
74b560a58cSFlorian Fainelli 			return ret;
75b560a58cSFlorian Fainelli 	}
76b560a58cSFlorian Fainelli 
77b560a58cSFlorian Fainelli 	return 0;
78b560a58cSFlorian Fainelli }
79b560a58cSFlorian Fainelli 
80b560a58cSFlorian Fainelli static void phy_write_exp(struct phy_device *phydev,
81b560a58cSFlorian Fainelli 					u16 reg, u16 value)
82b560a58cSFlorian Fainelli {
83b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg);
84b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
85b560a58cSFlorian Fainelli }
86b560a58cSFlorian Fainelli 
87b560a58cSFlorian Fainelli static void phy_write_misc(struct phy_device *phydev,
88b560a58cSFlorian Fainelli 					u16 reg, u16 chl, u16 value)
89b560a58cSFlorian Fainelli {
90b560a58cSFlorian Fainelli 	int tmp;
91b560a58cSFlorian Fainelli 
92b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
93b560a58cSFlorian Fainelli 
94b560a58cSFlorian Fainelli 	tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL);
95b560a58cSFlorian Fainelli 	tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA;
96b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp);
97b560a58cSFlorian Fainelli 
98b560a58cSFlorian Fainelli 	tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg;
99b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp);
100b560a58cSFlorian Fainelli 
101b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM54XX_EXP_DATA, value);
102b560a58cSFlorian Fainelli }
103b560a58cSFlorian Fainelli 
104b560a58cSFlorian Fainelli static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev)
105b560a58cSFlorian Fainelli {
106b560a58cSFlorian Fainelli 	/* write AFE_RXCONFIG_0 */
107a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, AFE_RXCONFIG_0, 0xeb19);
108b560a58cSFlorian Fainelli 
109b560a58cSFlorian Fainelli 	/* write AFE_RXCONFIG_1 */
110a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, AFE_RXCONFIG_1, 0x9a3f);
111b560a58cSFlorian Fainelli 
112b560a58cSFlorian Fainelli 	/* write AFE_RX_LP_COUNTER */
113a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, AFE_RX_LP_COUNTER, 0x7fc7);
114b560a58cSFlorian Fainelli 
115b560a58cSFlorian Fainelli 	/* write AFE_HPF_TRIM_OTHERS */
116a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x000b);
117b560a58cSFlorian Fainelli 
118b560a58cSFlorian Fainelli 	/* write AFTE_TX_CONFIG */
119a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, AFE_TX_CONFIG, 0x0800);
120b560a58cSFlorian Fainelli 
121b560a58cSFlorian Fainelli 	/* Increase VCO range to prevent unlocking problem of PLL at low
122b560a58cSFlorian Fainelli 	 * temp
123b560a58cSFlorian Fainelli 	 */
124a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, PLL_PLLCTRL_1, 0x0048);
125b560a58cSFlorian Fainelli 
126b560a58cSFlorian Fainelli 	/* Change Ki to 011 */
127a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, PLL_PLLCTRL_2, 0x021b);
128b560a58cSFlorian Fainelli 
129b560a58cSFlorian Fainelli 	/* Disable loading of TVCO buffer to bandgap, set bandgap trim
130b560a58cSFlorian Fainelli 	 * to 111
131b560a58cSFlorian Fainelli 	 */
132a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, PLL_PLLCTRL_4, 0x0e20);
133b560a58cSFlorian Fainelli 
134b560a58cSFlorian Fainelli 	/* Adjust bias current trim by -3 */
135a3622f2cSFlorian Fainelli 	phy_write_misc(phydev, DSP_TAP10, 0x690b);
136b560a58cSFlorian Fainelli 
137b560a58cSFlorian Fainelli 	/* Switch to CORE_BASE1E */
138b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd);
139b560a58cSFlorian Fainelli 
140b560a58cSFlorian Fainelli 	/* Reset R_CAL/RC_CAL Engine */
141a3622f2cSFlorian Fainelli 	phy_write_exp(phydev, CORE_EXPB0, 0x0010);
142b560a58cSFlorian Fainelli 
143b560a58cSFlorian Fainelli 	/* Disable Reset R_CAL/RC_CAL Engine */
144a3622f2cSFlorian Fainelli 	phy_write_exp(phydev, CORE_EXPB0, 0x0000);
145b560a58cSFlorian Fainelli 
146b560a58cSFlorian Fainelli 	return 0;
147b560a58cSFlorian Fainelli }
148b560a58cSFlorian Fainelli 
149b560a58cSFlorian Fainelli static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
150b560a58cSFlorian Fainelli {
151b560a58cSFlorian Fainelli 	int ret;
152b560a58cSFlorian Fainelli 
153b560a58cSFlorian Fainelli 	ret = bcm7445_config_init(phydev);
154b560a58cSFlorian Fainelli 	if (ret)
155b560a58cSFlorian Fainelli 		return ret;
156b560a58cSFlorian Fainelli 
157b560a58cSFlorian Fainelli 	return bcm7xxx_28nm_afe_config_init(phydev);
158b560a58cSFlorian Fainelli }
159b560a58cSFlorian Fainelli 
160b560a58cSFlorian Fainelli static int phy_set_clr_bits(struct phy_device *dev, int location,
161b560a58cSFlorian Fainelli 					int set_mask, int clr_mask)
162b560a58cSFlorian Fainelli {
163b560a58cSFlorian Fainelli 	int v, ret;
164b560a58cSFlorian Fainelli 
165b560a58cSFlorian Fainelli 	v = phy_read(dev, location);
166b560a58cSFlorian Fainelli 	if (v < 0)
167b560a58cSFlorian Fainelli 		return v;
168b560a58cSFlorian Fainelli 
169b560a58cSFlorian Fainelli 	v &= ~clr_mask;
170b560a58cSFlorian Fainelli 	v |= set_mask;
171b560a58cSFlorian Fainelli 
172b560a58cSFlorian Fainelli 	ret = phy_write(dev, location, v);
173b560a58cSFlorian Fainelli 	if (ret < 0)
174b560a58cSFlorian Fainelli 		return ret;
175b560a58cSFlorian Fainelli 
176b560a58cSFlorian Fainelli 	return v;
177b560a58cSFlorian Fainelli }
178b560a58cSFlorian Fainelli 
179b560a58cSFlorian Fainelli static int bcm7xxx_config_init(struct phy_device *phydev)
180b560a58cSFlorian Fainelli {
181b560a58cSFlorian Fainelli 	int ret;
182b560a58cSFlorian Fainelli 
183b560a58cSFlorian Fainelli 	/* Enable 64 clock MDIO */
184b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO);
185b560a58cSFlorian Fainelli 	phy_read(phydev, MII_BCM7XXX_AUX_MODE);
186b560a58cSFlorian Fainelli 
187b560a58cSFlorian Fainelli 	/* Workaround only required for 100Mbits/sec */
188b560a58cSFlorian Fainelli 	if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR))
189b560a58cSFlorian Fainelli 		return 0;
190b560a58cSFlorian Fainelli 
191b560a58cSFlorian Fainelli 	/* set shadow mode 2 */
192b560a58cSFlorian Fainelli 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST,
193b560a58cSFlorian Fainelli 			MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2);
194b560a58cSFlorian Fainelli 	if (ret < 0)
195b560a58cSFlorian Fainelli 		return ret;
196b560a58cSFlorian Fainelli 
197b560a58cSFlorian Fainelli 	/* set iddq_clkbias */
198b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00);
199b560a58cSFlorian Fainelli 	udelay(10);
200b560a58cSFlorian Fainelli 
201b560a58cSFlorian Fainelli 	/* reset iddq_clkbias */
202b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00);
203b560a58cSFlorian Fainelli 
204b560a58cSFlorian Fainelli 	phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555);
205b560a58cSFlorian Fainelli 
206b560a58cSFlorian Fainelli 	/* reset shadow mode 2 */
207b560a58cSFlorian Fainelli 	ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0);
208b560a58cSFlorian Fainelli 	if (ret < 0)
209b560a58cSFlorian Fainelli 		return ret;
210b560a58cSFlorian Fainelli 
211b560a58cSFlorian Fainelli 	return 0;
212b560a58cSFlorian Fainelli }
213b560a58cSFlorian Fainelli 
214b560a58cSFlorian Fainelli /* Workaround for putting the PHY in IDDQ mode, required
215b560a58cSFlorian Fainelli  * for all BCM7XXX PHYs
216b560a58cSFlorian Fainelli  */
217b560a58cSFlorian Fainelli static int bcm7xxx_suspend(struct phy_device *phydev)
218b560a58cSFlorian Fainelli {
219b560a58cSFlorian Fainelli 	int ret;
220b560a58cSFlorian Fainelli 	const struct bcm7xxx_regs {
221b560a58cSFlorian Fainelli 		int reg;
222b560a58cSFlorian Fainelli 		u16 value;
223b560a58cSFlorian Fainelli 	} bcm7xxx_suspend_cfg[] = {
224b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x008b },
225b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 },
226b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_DISC, 0x7000 },
227b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x000f },
228b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 },
229b560a58cSFlorian Fainelli 		{ MII_BCM7XXX_TEST, 0x000b },
230b560a58cSFlorian Fainelli 	};
231b560a58cSFlorian Fainelli 	unsigned int i;
232b560a58cSFlorian Fainelli 
233b560a58cSFlorian Fainelli 	for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) {
234b560a58cSFlorian Fainelli 		ret = phy_write(phydev,
235b560a58cSFlorian Fainelli 				bcm7xxx_suspend_cfg[i].reg,
236b560a58cSFlorian Fainelli 				bcm7xxx_suspend_cfg[i].value);
237b560a58cSFlorian Fainelli 		if (ret)
238b560a58cSFlorian Fainelli 			return ret;
239b560a58cSFlorian Fainelli 	}
240b560a58cSFlorian Fainelli 
241b560a58cSFlorian Fainelli 	return 0;
242b560a58cSFlorian Fainelli }
243b560a58cSFlorian Fainelli 
244b560a58cSFlorian Fainelli static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
245b560a58cSFlorian Fainelli {
246b560a58cSFlorian Fainelli 	return 0;
247b560a58cSFlorian Fainelli }
248b560a58cSFlorian Fainelli 
249b560a58cSFlorian Fainelli static struct phy_driver bcm7xxx_driver[] = {
250b560a58cSFlorian Fainelli {
251b560a58cSFlorian Fainelli 	.phy_id		= PHY_ID_BCM7366,
252b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xfffffff0,
253b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7366",
254b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
255b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
256b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
257b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_28nm_afe_config_init,
258b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
259b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
260b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
261b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_28nm_afe_config_init,
262b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
263b560a58cSFlorian Fainelli }, {
264b560a58cSFlorian Fainelli 	.phy_id		= PHY_ID_BCM7439,
265b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xfffffff0,
266b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7439",
267b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
268b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
269b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
270b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_28nm_afe_config_init,
271b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
272b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
273b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
274b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_28nm_afe_config_init,
275b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
276b560a58cSFlorian Fainelli }, {
277b560a58cSFlorian Fainelli 	.phy_id		= PHY_ID_BCM7445,
278b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xfffffff0,
279b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7445",
280b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
281b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
282b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
283b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_28nm_config_init,
284b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
285b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
286b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
287b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_28nm_config_init,
288b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
289b560a58cSFlorian Fainelli }, {
290b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7XXX 28nm",
291b560a58cSFlorian Fainelli 	.phy_id		= PHY_ID_BCM7XXX_28,
292b560a58cSFlorian Fainelli 	.phy_id_mask	= PHY_BCM_OUI_MASK,
293b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
294b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
295b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
296b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_28nm_config_init,
297b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
298b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
299b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
300b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_28nm_config_init,
301b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
302b560a58cSFlorian Fainelli }, {
303b560a58cSFlorian Fainelli 	.phy_id		= PHY_BCM_OUI_4,
304b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xffff0000,
305b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7XXX 40nm",
306b560a58cSFlorian Fainelli 	.features	= PHY_GBIT_FEATURES |
307b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
308b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
309b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_config_init,
310b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
311b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
312b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
313b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_config_init,
314b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
315b560a58cSFlorian Fainelli }, {
316b560a58cSFlorian Fainelli 	.phy_id		= PHY_BCM_OUI_5,
317b560a58cSFlorian Fainelli 	.phy_id_mask	= 0xffffff00,
318b560a58cSFlorian Fainelli 	.name		= "Broadcom BCM7XXX 65nm",
319b560a58cSFlorian Fainelli 	.features	= PHY_BASIC_FEATURES |
320b560a58cSFlorian Fainelli 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
321b560a58cSFlorian Fainelli 	.flags		= PHY_IS_INTERNAL,
322b560a58cSFlorian Fainelli 	.config_init	= bcm7xxx_dummy_config_init,
323b560a58cSFlorian Fainelli 	.config_aneg	= genphy_config_aneg,
324b560a58cSFlorian Fainelli 	.read_status	= genphy_read_status,
325b560a58cSFlorian Fainelli 	.suspend	= bcm7xxx_suspend,
326b560a58cSFlorian Fainelli 	.resume		= bcm7xxx_config_init,
327b560a58cSFlorian Fainelli 	.driver		= { .owner = THIS_MODULE },
328b560a58cSFlorian Fainelli } };
329b560a58cSFlorian Fainelli 
330b560a58cSFlorian Fainelli static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
331b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7366, 0xfffffff0, },
332b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7439, 0xfffffff0, },
333b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7445, 0xfffffff0, },
334b560a58cSFlorian Fainelli 	{ PHY_ID_BCM7XXX_28, 0xfffffc00 },
335b560a58cSFlorian Fainelli 	{ PHY_BCM_OUI_4, 0xffff0000 },
336b560a58cSFlorian Fainelli 	{ PHY_BCM_OUI_5, 0xffffff00 },
337b560a58cSFlorian Fainelli 	{ }
338b560a58cSFlorian Fainelli };
339b560a58cSFlorian Fainelli 
340b560a58cSFlorian Fainelli static int __init bcm7xxx_phy_init(void)
341b560a58cSFlorian Fainelli {
342b560a58cSFlorian Fainelli 	return phy_drivers_register(bcm7xxx_driver,
343b560a58cSFlorian Fainelli 			ARRAY_SIZE(bcm7xxx_driver));
344b560a58cSFlorian Fainelli }
345b560a58cSFlorian Fainelli 
346b560a58cSFlorian Fainelli static void __exit bcm7xxx_phy_exit(void)
347b560a58cSFlorian Fainelli {
348b560a58cSFlorian Fainelli 	phy_drivers_unregister(bcm7xxx_driver,
349b560a58cSFlorian Fainelli 			ARRAY_SIZE(bcm7xxx_driver));
350b560a58cSFlorian Fainelli }
351b560a58cSFlorian Fainelli 
352b560a58cSFlorian Fainelli module_init(bcm7xxx_phy_init);
353b560a58cSFlorian Fainelli module_exit(bcm7xxx_phy_exit);
354b560a58cSFlorian Fainelli 
355b560a58cSFlorian Fainelli MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl);
356b560a58cSFlorian Fainelli 
357b560a58cSFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver");
358b560a58cSFlorian Fainelli MODULE_LICENSE("GPL");
359b560a58cSFlorian Fainelli MODULE_AUTHOR("Broadcom Corporation");
360