xref: /openbmc/linux/drivers/net/phy/broadcom.c (revision b627b4ed)
1 /*
2  *	drivers/net/phy/broadcom.c
3  *
4  *	Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
5  *	transceivers.
6  *
7  *	Copyright (c) 2006  Maciej W. Rozycki
8  *
9  *	Inspired by code written by Amy Fong.
10  *
11  *	This program is free software; you can redistribute it and/or
12  *	modify it under the terms of the GNU General Public License
13  *	as published by the Free Software Foundation; either version
14  *	2 of the License, or (at your option) any later version.
15  */
16 
17 #include <linux/module.h>
18 #include <linux/phy.h>
19 
20 #define PHY_ID_BCM50610		0x0143bd60
21 
22 #define MII_BCM54XX_ECR		0x10	/* BCM54xx extended control register */
23 #define MII_BCM54XX_ECR_IM	0x1000	/* Interrupt mask */
24 #define MII_BCM54XX_ECR_IF	0x0800	/* Interrupt force */
25 
26 #define MII_BCM54XX_ESR		0x11	/* BCM54xx extended status register */
27 #define MII_BCM54XX_ESR_IS	0x1000	/* Interrupt status */
28 
29 #define MII_BCM54XX_EXP_DATA	0x15	/* Expansion register data */
30 #define MII_BCM54XX_EXP_SEL	0x17	/* Expansion register select */
31 #define MII_BCM54XX_EXP_SEL_SSD	0x0e00	/* Secondary SerDes select */
32 #define MII_BCM54XX_EXP_SEL_ER	0x0f00	/* Expansion register select */
33 
34 #define MII_BCM54XX_AUX_CTL	0x18	/* Auxiliary control register */
35 #define MII_BCM54XX_ISR		0x1a	/* BCM54xx interrupt status register */
36 #define MII_BCM54XX_IMR		0x1b	/* BCM54xx interrupt mask register */
37 #define MII_BCM54XX_INT_CRCERR	0x0001	/* CRC error */
38 #define MII_BCM54XX_INT_LINK	0x0002	/* Link status changed */
39 #define MII_BCM54XX_INT_SPEED	0x0004	/* Link speed change */
40 #define MII_BCM54XX_INT_DUPLEX	0x0008	/* Duplex mode changed */
41 #define MII_BCM54XX_INT_LRS	0x0010	/* Local receiver status changed */
42 #define MII_BCM54XX_INT_RRS	0x0020	/* Remote receiver status changed */
43 #define MII_BCM54XX_INT_SSERR	0x0040	/* Scrambler synchronization error */
44 #define MII_BCM54XX_INT_UHCD	0x0080	/* Unsupported HCD negotiated */
45 #define MII_BCM54XX_INT_NHCD	0x0100	/* No HCD */
46 #define MII_BCM54XX_INT_NHCDL	0x0200	/* No HCD link */
47 #define MII_BCM54XX_INT_ANPR	0x0400	/* Auto-negotiation page received */
48 #define MII_BCM54XX_INT_LC	0x0800	/* All counters below 128 */
49 #define MII_BCM54XX_INT_HC	0x1000	/* Counter above 32768 */
50 #define MII_BCM54XX_INT_MDIX	0x2000	/* MDIX status change */
51 #define MII_BCM54XX_INT_PSERR	0x4000	/* Pair swap error */
52 
53 #define MII_BCM54XX_SHD		0x1c	/* 0x1c shadow registers */
54 #define MII_BCM54XX_SHD_WRITE	0x8000
55 #define MII_BCM54XX_SHD_VAL(x)	((x & 0x1f) << 10)
56 #define MII_BCM54XX_SHD_DATA(x)	((x & 0x3ff) << 0)
57 
58 /*
59  * AUXILIARY CONTROL SHADOW ACCESS REGISTERS.  (PHY REG 0x18)
60  */
61 #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL	0x0000
62 #define MII_BCM54XX_AUXCTL_ACTL_TX_6DB		0x0400
63 #define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA	0x0800
64 
65 #define MII_BCM54XX_AUXCTL_MISC_WREN	0x8000
66 #define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX	0x0200
67 #define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC	0x7000
68 #define MII_BCM54XX_AUXCTL_SHDWSEL_MISC	0x0007
69 
70 #define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL	0x0000
71 
72 
73 /*
74  * Broadcom LED source encodings.  These are used in BCM5461, BCM5481,
75  * BCM5482, and possibly some others.
76  */
77 #define BCM_LED_SRC_LINKSPD1	0x0
78 #define BCM_LED_SRC_LINKSPD2	0x1
79 #define BCM_LED_SRC_XMITLED	0x2
80 #define BCM_LED_SRC_ACTIVITYLED	0x3
81 #define BCM_LED_SRC_FDXLED	0x4
82 #define BCM_LED_SRC_SLAVE	0x5
83 #define BCM_LED_SRC_INTR	0x6
84 #define BCM_LED_SRC_QUALITY	0x7
85 #define BCM_LED_SRC_RCVLED	0x8
86 #define BCM_LED_SRC_MULTICOLOR1	0xa
87 #define BCM_LED_SRC_OPENSHORT	0xb
88 #define BCM_LED_SRC_OFF		0xe	/* Tied high */
89 #define BCM_LED_SRC_ON		0xf	/* Tied low */
90 
91 /*
92  * BCM5482: Shadow registers
93  * Shadow values go into bits [14:10] of register 0x1c to select a shadow
94  * register to access.
95  */
96 #define BCM5482_SHD_LEDS1	0x0d	/* 01101: LED Selector 1 */
97 					/* LED3 / ~LINKSPD[2] selector */
98 #define BCM5482_SHD_LEDS1_LED3(src)	((src & 0xf) << 4)
99 					/* LED1 / ~LINKSPD[1] selector */
100 #define BCM5482_SHD_LEDS1_LED1(src)	((src & 0xf) << 0)
101 #define BCM5482_SHD_SSD		0x14	/* 10100: Secondary SerDes control */
102 #define BCM5482_SHD_SSD_LEDM	0x0008	/* SSD LED Mode enable */
103 #define BCM5482_SHD_SSD_EN	0x0001	/* SSD enable */
104 #define BCM5482_SHD_MODE	0x1f	/* 11111: Mode Control Register */
105 #define BCM5482_SHD_MODE_1000BX	0x0001	/* Enable 1000BASE-X registers */
106 
107 /*
108  * EXPANSION SHADOW ACCESS REGISTERS.  (PHY REG 0x15, 0x16, and 0x17)
109  */
110 #define MII_BCM54XX_EXP_AADJ1CH0		0x001f
111 #define  MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN	0x0200
112 #define  MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF	0x0100
113 #define MII_BCM54XX_EXP_AADJ1CH3		0x601f
114 #define  MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ	0x0002
115 #define MII_BCM54XX_EXP_EXP08			0x0F08
116 #define  MII_BCM54XX_EXP_EXP08_RJCT_2MHZ	0x0001
117 #define  MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE	0x0200
118 #define MII_BCM54XX_EXP_EXP75			0x0f75
119 #define  MII_BCM54XX_EXP_EXP75_VDACCTRL		0x003c
120 #define MII_BCM54XX_EXP_EXP96			0x0f96
121 #define  MII_BCM54XX_EXP_EXP96_MYST		0x0010
122 #define MII_BCM54XX_EXP_EXP97			0x0f97
123 #define  MII_BCM54XX_EXP_EXP97_MYST		0x0c0c
124 
125 /*
126  * BCM5482: Secondary SerDes registers
127  */
128 #define BCM5482_SSD_1000BX_CTL		0x00	/* 1000BASE-X Control */
129 #define BCM5482_SSD_1000BX_CTL_PWRDOWN	0x0800	/* Power-down SSD */
130 #define BCM5482_SSD_SGMII_SLAVE		0x15	/* SGMII Slave Register */
131 #define BCM5482_SSD_SGMII_SLAVE_EN	0x0002	/* Slave mode enable */
132 #define BCM5482_SSD_SGMII_SLAVE_AD	0x0001	/* Slave auto-detection */
133 
134 /*
135  * Device flags for PHYs that can be configured for different operating
136  * modes.
137  */
138 #define PHY_BCM_FLAGS_VALID		0x80000000
139 #define PHY_BCM_FLAGS_INTF_XAUI		0x00000020
140 #define PHY_BCM_FLAGS_INTF_SGMII	0x00000010
141 #define PHY_BCM_FLAGS_MODE_1000BX	0x00000002
142 #define PHY_BCM_FLAGS_MODE_COPPER	0x00000001
143 
144 MODULE_DESCRIPTION("Broadcom PHY driver");
145 MODULE_AUTHOR("Maciej W. Rozycki");
146 MODULE_LICENSE("GPL");
147 
148 /*
149  * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
150  * 0x1c shadow registers.
151  */
152 static int bcm54xx_shadow_read(struct phy_device *phydev, u16 shadow)
153 {
154 	phy_write(phydev, MII_BCM54XX_SHD, MII_BCM54XX_SHD_VAL(shadow));
155 	return MII_BCM54XX_SHD_DATA(phy_read(phydev, MII_BCM54XX_SHD));
156 }
157 
158 static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
159 {
160 	return phy_write(phydev, MII_BCM54XX_SHD,
161 			 MII_BCM54XX_SHD_WRITE |
162 			 MII_BCM54XX_SHD_VAL(shadow) |
163 			 MII_BCM54XX_SHD_DATA(val));
164 }
165 
166 /* Indirect register access functions for the Expansion Registers */
167 static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum)
168 {
169 	int val;
170 
171 	val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
172 	if (val < 0)
173 		return val;
174 
175 	val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
176 
177 	/* Restore default value.  It's O.K. if this write fails. */
178 	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
179 
180 	return val;
181 }
182 
183 static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
184 {
185 	int ret;
186 
187 	ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
188 	if (ret < 0)
189 		return ret;
190 
191 	ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
192 
193 	/* Restore default value.  It's O.K. if this write fails. */
194 	phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
195 
196 	return ret;
197 }
198 
199 static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
200 {
201 	return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
202 }
203 
204 static int bcm50610_a0_workaround(struct phy_device *phydev)
205 {
206 	int err;
207 
208 	err = bcm54xx_auxctl_write(phydev,
209 				   MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
210 				   MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
211 				   MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
212 	if (err < 0)
213 		return err;
214 
215 	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
216 				MII_BCM54XX_EXP_EXP08_RJCT_2MHZ	|
217 				MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE);
218 	if (err < 0)
219 		goto error;
220 
221 	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
222 				MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
223 				MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
224 	if (err < 0)
225 		goto error;
226 
227 	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
228 					MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
229 	if (err < 0)
230 		goto error;
231 
232 	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
233 				MII_BCM54XX_EXP_EXP75_VDACCTRL);
234 	if (err < 0)
235 		goto error;
236 
237 	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
238 				MII_BCM54XX_EXP_EXP96_MYST);
239 	if (err < 0)
240 		goto error;
241 
242 	err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
243 				MII_BCM54XX_EXP_EXP97_MYST);
244 
245 error:
246 	bcm54xx_auxctl_write(phydev,
247 			     MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
248 			     MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
249 
250 	return err;
251 }
252 
253 static int bcm54xx_config_init(struct phy_device *phydev)
254 {
255 	int reg, err;
256 
257 	reg = phy_read(phydev, MII_BCM54XX_ECR);
258 	if (reg < 0)
259 		return reg;
260 
261 	/* Mask interrupts globally.  */
262 	reg |= MII_BCM54XX_ECR_IM;
263 	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
264 	if (err < 0)
265 		return err;
266 
267 	/* Unmask events we are interested in.  */
268 	reg = ~(MII_BCM54XX_INT_DUPLEX |
269 		MII_BCM54XX_INT_SPEED |
270 		MII_BCM54XX_INT_LINK);
271 	err = phy_write(phydev, MII_BCM54XX_IMR, reg);
272 	if (err < 0)
273 		return err;
274 
275 	if (phydev->drv->phy_id == PHY_ID_BCM50610) {
276 		err = bcm50610_a0_workaround(phydev);
277 		if (err < 0)
278 			return err;
279 	}
280 
281 	return 0;
282 }
283 
284 static int bcm5482_config_init(struct phy_device *phydev)
285 {
286 	int err, reg;
287 
288 	err = bcm54xx_config_init(phydev);
289 
290 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
291 		/*
292 		 * Enable secondary SerDes and its use as an LED source
293 		 */
294 		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
295 		bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
296 				     reg |
297 				     BCM5482_SHD_SSD_LEDM |
298 				     BCM5482_SHD_SSD_EN);
299 
300 		/*
301 		 * Enable SGMII slave mode and auto-detection
302 		 */
303 		reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
304 		err = bcm54xx_exp_read(phydev, reg);
305 		if (err < 0)
306 			return err;
307 		err = bcm54xx_exp_write(phydev, reg, err |
308 					BCM5482_SSD_SGMII_SLAVE_EN |
309 					BCM5482_SSD_SGMII_SLAVE_AD);
310 		if (err < 0)
311 			return err;
312 
313 		/*
314 		 * Disable secondary SerDes powerdown
315 		 */
316 		reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
317 		err = bcm54xx_exp_read(phydev, reg);
318 		if (err < 0)
319 			return err;
320 		err = bcm54xx_exp_write(phydev, reg,
321 					err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
322 		if (err < 0)
323 			return err;
324 
325 		/*
326 		 * Select 1000BASE-X register set (primary SerDes)
327 		 */
328 		reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
329 		bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
330 				     reg | BCM5482_SHD_MODE_1000BX);
331 
332 		/*
333 		 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
334 		 * (Use LED1 as secondary SerDes ACTIVITY LED)
335 		 */
336 		bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
337 			BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
338 			BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
339 
340 		/*
341 		 * Auto-negotiation doesn't seem to work quite right
342 		 * in this mode, so we disable it and force it to the
343 		 * right speed/duplex setting.  Only 'link status'
344 		 * is important.
345 		 */
346 		phydev->autoneg = AUTONEG_DISABLE;
347 		phydev->speed = SPEED_1000;
348 		phydev->duplex = DUPLEX_FULL;
349 	}
350 
351 	return err;
352 }
353 
354 static int bcm5482_read_status(struct phy_device *phydev)
355 {
356 	int err;
357 
358 	err = genphy_read_status(phydev);
359 
360 	if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
361 		/*
362 		 * Only link status matters for 1000Base-X mode, so force
363 		 * 1000 Mbit/s full-duplex status
364 		 */
365 		if (phydev->link) {
366 			phydev->speed = SPEED_1000;
367 			phydev->duplex = DUPLEX_FULL;
368 		}
369 	}
370 
371 	return err;
372 }
373 
374 static int bcm54xx_ack_interrupt(struct phy_device *phydev)
375 {
376 	int reg;
377 
378 	/* Clear pending interrupts.  */
379 	reg = phy_read(phydev, MII_BCM54XX_ISR);
380 	if (reg < 0)
381 		return reg;
382 
383 	return 0;
384 }
385 
386 static int bcm54xx_config_intr(struct phy_device *phydev)
387 {
388 	int reg, err;
389 
390 	reg = phy_read(phydev, MII_BCM54XX_ECR);
391 	if (reg < 0)
392 		return reg;
393 
394 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
395 		reg &= ~MII_BCM54XX_ECR_IM;
396 	else
397 		reg |= MII_BCM54XX_ECR_IM;
398 
399 	err = phy_write(phydev, MII_BCM54XX_ECR, reg);
400 	return err;
401 }
402 
403 static int bcm5481_config_aneg(struct phy_device *phydev)
404 {
405 	int ret;
406 
407 	/* Aneg firsly. */
408 	ret = genphy_config_aneg(phydev);
409 
410 	/* Then we can set up the delay. */
411 	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
412 		u16 reg;
413 
414 		/*
415 		 * There is no BCM5481 specification available, so down
416 		 * here is everything we know about "register 0x18". This
417 		 * at least helps BCM5481 to successfuly receive packets
418 		 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
419 		 * says: "This sets delay between the RXD and RXC signals
420 		 * instead of using trace lengths to achieve timing".
421 		 */
422 
423 		/* Set RDX clk delay. */
424 		reg = 0x7 | (0x7 << 12);
425 		phy_write(phydev, 0x18, reg);
426 
427 		reg = phy_read(phydev, 0x18);
428 		/* Set RDX-RXC skew. */
429 		reg |= (1 << 8);
430 		/* Write bits 14:0. */
431 		reg |= (1 << 15);
432 		phy_write(phydev, 0x18, reg);
433 	}
434 
435 	return ret;
436 }
437 
438 static struct phy_driver bcm5411_driver = {
439 	.phy_id		= 0x00206070,
440 	.phy_id_mask	= 0xfffffff0,
441 	.name		= "Broadcom BCM5411",
442 	.features	= PHY_GBIT_FEATURES |
443 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
444 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
445 	.config_init	= bcm54xx_config_init,
446 	.config_aneg	= genphy_config_aneg,
447 	.read_status	= genphy_read_status,
448 	.ack_interrupt	= bcm54xx_ack_interrupt,
449 	.config_intr	= bcm54xx_config_intr,
450 	.driver 	= { .owner = THIS_MODULE },
451 };
452 
453 static struct phy_driver bcm5421_driver = {
454 	.phy_id		= 0x002060e0,
455 	.phy_id_mask	= 0xfffffff0,
456 	.name		= "Broadcom BCM5421",
457 	.features	= PHY_GBIT_FEATURES |
458 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
459 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
460 	.config_init	= bcm54xx_config_init,
461 	.config_aneg	= genphy_config_aneg,
462 	.read_status	= genphy_read_status,
463 	.ack_interrupt	= bcm54xx_ack_interrupt,
464 	.config_intr	= bcm54xx_config_intr,
465 	.driver 	= { .owner = THIS_MODULE },
466 };
467 
468 static struct phy_driver bcm5461_driver = {
469 	.phy_id		= 0x002060c0,
470 	.phy_id_mask	= 0xfffffff0,
471 	.name		= "Broadcom BCM5461",
472 	.features	= PHY_GBIT_FEATURES |
473 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
474 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
475 	.config_init	= bcm54xx_config_init,
476 	.config_aneg	= genphy_config_aneg,
477 	.read_status	= genphy_read_status,
478 	.ack_interrupt	= bcm54xx_ack_interrupt,
479 	.config_intr	= bcm54xx_config_intr,
480 	.driver 	= { .owner = THIS_MODULE },
481 };
482 
483 static struct phy_driver bcm5464_driver = {
484 	.phy_id		= 0x002060b0,
485 	.phy_id_mask	= 0xfffffff0,
486 	.name		= "Broadcom BCM5464",
487 	.features	= PHY_GBIT_FEATURES |
488 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
489 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
490 	.config_init	= bcm54xx_config_init,
491 	.config_aneg	= genphy_config_aneg,
492 	.read_status	= genphy_read_status,
493 	.ack_interrupt	= bcm54xx_ack_interrupt,
494 	.config_intr	= bcm54xx_config_intr,
495 	.driver 	= { .owner = THIS_MODULE },
496 };
497 
498 static struct phy_driver bcm5481_driver = {
499 	.phy_id		= 0x0143bca0,
500 	.phy_id_mask	= 0xfffffff0,
501 	.name		= "Broadcom BCM5481",
502 	.features	= PHY_GBIT_FEATURES |
503 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
504 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
505 	.config_init	= bcm54xx_config_init,
506 	.config_aneg	= bcm5481_config_aneg,
507 	.read_status	= genphy_read_status,
508 	.ack_interrupt	= bcm54xx_ack_interrupt,
509 	.config_intr	= bcm54xx_config_intr,
510 	.driver 	= { .owner = THIS_MODULE },
511 };
512 
513 static struct phy_driver bcm5482_driver = {
514 	.phy_id		= 0x0143bcb0,
515 	.phy_id_mask	= 0xfffffff0,
516 	.name		= "Broadcom BCM5482",
517 	.features	= PHY_GBIT_FEATURES |
518 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
519 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
520 	.config_init	= bcm5482_config_init,
521 	.config_aneg	= genphy_config_aneg,
522 	.read_status	= bcm5482_read_status,
523 	.ack_interrupt	= bcm54xx_ack_interrupt,
524 	.config_intr	= bcm54xx_config_intr,
525 	.driver 	= { .owner = THIS_MODULE },
526 };
527 
528 static struct phy_driver bcm50610_driver = {
529 	.phy_id		= PHY_ID_BCM50610,
530 	.phy_id_mask	= 0xfffffff0,
531 	.name		= "Broadcom BCM50610",
532 	.features	= PHY_GBIT_FEATURES |
533 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
534 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
535 	.config_init	= bcm54xx_config_init,
536 	.config_aneg	= genphy_config_aneg,
537 	.read_status	= genphy_read_status,
538 	.ack_interrupt	= bcm54xx_ack_interrupt,
539 	.config_intr	= bcm54xx_config_intr,
540 	.driver 	= { .owner = THIS_MODULE },
541 };
542 
543 static struct phy_driver bcm57780_driver = {
544 	.phy_id		= 0x03625d90,
545 	.phy_id_mask	= 0xfffffff0,
546 	.name		= "Broadcom BCM57780",
547 	.features	= PHY_GBIT_FEATURES |
548 			  SUPPORTED_Pause | SUPPORTED_Asym_Pause,
549 	.flags		= PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
550 	.config_init	= bcm54xx_config_init,
551 	.config_aneg	= genphy_config_aneg,
552 	.read_status	= genphy_read_status,
553 	.ack_interrupt	= bcm54xx_ack_interrupt,
554 	.config_intr	= bcm54xx_config_intr,
555 	.driver 	= { .owner = THIS_MODULE },
556 };
557 
558 static int __init broadcom_init(void)
559 {
560 	int ret;
561 
562 	ret = phy_driver_register(&bcm5411_driver);
563 	if (ret)
564 		goto out_5411;
565 	ret = phy_driver_register(&bcm5421_driver);
566 	if (ret)
567 		goto out_5421;
568 	ret = phy_driver_register(&bcm5461_driver);
569 	if (ret)
570 		goto out_5461;
571 	ret = phy_driver_register(&bcm5464_driver);
572 	if (ret)
573 		goto out_5464;
574 	ret = phy_driver_register(&bcm5481_driver);
575 	if (ret)
576 		goto out_5481;
577 	ret = phy_driver_register(&bcm5482_driver);
578 	if (ret)
579 		goto out_5482;
580 	ret = phy_driver_register(&bcm50610_driver);
581 	if (ret)
582 		goto out_50610;
583 	ret = phy_driver_register(&bcm57780_driver);
584 	if (ret)
585 		goto out_57780;
586 	return ret;
587 
588 out_57780:
589 	phy_driver_unregister(&bcm50610_driver);
590 out_50610:
591 	phy_driver_unregister(&bcm5482_driver);
592 out_5482:
593 	phy_driver_unregister(&bcm5481_driver);
594 out_5481:
595 	phy_driver_unregister(&bcm5464_driver);
596 out_5464:
597 	phy_driver_unregister(&bcm5461_driver);
598 out_5461:
599 	phy_driver_unregister(&bcm5421_driver);
600 out_5421:
601 	phy_driver_unregister(&bcm5411_driver);
602 out_5411:
603 	return ret;
604 }
605 
606 static void __exit broadcom_exit(void)
607 {
608 	phy_driver_unregister(&bcm57780_driver);
609 	phy_driver_unregister(&bcm50610_driver);
610 	phy_driver_unregister(&bcm5482_driver);
611 	phy_driver_unregister(&bcm5481_driver);
612 	phy_driver_unregister(&bcm5464_driver);
613 	phy_driver_unregister(&bcm5461_driver);
614 	phy_driver_unregister(&bcm5421_driver);
615 	phy_driver_unregister(&bcm5411_driver);
616 }
617 
618 module_init(broadcom_init);
619 module_exit(broadcom_exit);
620