airo: reduce stack memory footprint
[linux-2.6] / drivers / net / phy / broadcom.c
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);