]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/phy/broadcom.c
Merge branch 'topic/hda' into for-next
[karo-tx-linux.git] / 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 #include <linux/brcmphy.h>
20
21
22 #define BRCM_PHY_MODEL(phydev) \
23         ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
24
25 #define BRCM_PHY_REV(phydev) \
26         ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
27
28 MODULE_DESCRIPTION("Broadcom PHY driver");
29 MODULE_AUTHOR("Maciej W. Rozycki");
30 MODULE_LICENSE("GPL");
31
32 /* Indirect register access functions for the Expansion Registers */
33 static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
34 {
35         int val;
36
37         val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
38         if (val < 0)
39                 return val;
40
41         val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
42
43         /* Restore default value.  It's O.K. if this write fails. */
44         phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
45
46         return val;
47 }
48
49 static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
50 {
51         int ret;
52
53         ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
54         if (ret < 0)
55                 return ret;
56
57         ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
58
59         /* Restore default value.  It's O.K. if this write fails. */
60         phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
61
62         return ret;
63 }
64
65 static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
66 {
67         return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
68 }
69
70 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
71 static int bcm50610_a0_workaround(struct phy_device *phydev)
72 {
73         int err;
74
75         err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
76                                 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
77                                 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
78         if (err < 0)
79                 return err;
80
81         err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
82                                         MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
83         if (err < 0)
84                 return err;
85
86         err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
87                                 MII_BCM54XX_EXP_EXP75_VDACCTRL);
88         if (err < 0)
89                 return err;
90
91         err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
92                                 MII_BCM54XX_EXP_EXP96_MYST);
93         if (err < 0)
94                 return err;
95
96         err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
97                                 MII_BCM54XX_EXP_EXP97_MYST);
98
99         return err;
100 }
101
102 static int bcm54xx_phydsp_config(struct phy_device *phydev)
103 {
104         int err, err2;
105
106         /* Enable the SMDSP clock */
107         err = bcm54xx_auxctl_write(phydev,
108                                    MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
109                                    MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
110                                    MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
111         if (err < 0)
112                 return err;
113
114         if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
115             BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
116                 /* Clear bit 9 to fix a phy interop issue. */
117                 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
118                                         MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
119                 if (err < 0)
120                         goto error;
121
122                 if (phydev->drv->phy_id == PHY_ID_BCM50610) {
123                         err = bcm50610_a0_workaround(phydev);
124                         if (err < 0)
125                                 goto error;
126                 }
127         }
128
129         if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
130                 int val;
131
132                 val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
133                 if (val < 0)
134                         goto error;
135
136                 val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
137                 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val);
138         }
139
140 error:
141         /* Disable the SMDSP clock */
142         err2 = bcm54xx_auxctl_write(phydev,
143                                     MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
144                                     MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
145
146         /* Return the first error reported. */
147         return err ? err : err2;
148 }
149
150 static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
151 {
152         u32 orig;
153         int val;
154         bool clk125en = true;
155
156         /* Abort if we are using an untested phy. */
157         if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
158             BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
159             BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
160                 return;
161
162         val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
163         if (val < 0)
164                 return;
165
166         orig = val;
167
168         if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
169              BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
170             BRCM_PHY_REV(phydev) >= 0x3) {
171                 /*
172                  * Here, bit 0 _disables_ CLK125 when set.
173                  * This bit is set by default.
174                  */
175                 clk125en = false;
176         } else {
177                 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
178                         /* Here, bit 0 _enables_ CLK125 when set */
179                         val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
180                         clk125en = false;
181                 }
182         }
183
184         if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
185                 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
186         else
187                 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
188
189         if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY)
190                 val |= BCM54XX_SHD_SCR3_TRDDAPD;
191
192         if (orig != val)
193                 bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
194
195         val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
196         if (val < 0)
197                 return;
198
199         orig = val;
200
201         if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
202                 val |= BCM54XX_SHD_APD_EN;
203         else
204                 val &= ~BCM54XX_SHD_APD_EN;
205
206         if (orig != val)
207                 bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
208 }
209
210 static int bcm54xx_config_init(struct phy_device *phydev)
211 {
212         int reg, err;
213
214         reg = phy_read(phydev, MII_BCM54XX_ECR);
215         if (reg < 0)
216                 return reg;
217
218         /* Mask interrupts globally.  */
219         reg |= MII_BCM54XX_ECR_IM;
220         err = phy_write(phydev, MII_BCM54XX_ECR, reg);
221         if (err < 0)
222                 return err;
223
224         /* Unmask events we are interested in.  */
225         reg = ~(MII_BCM54XX_INT_DUPLEX |
226                 MII_BCM54XX_INT_SPEED |
227                 MII_BCM54XX_INT_LINK);
228         err = phy_write(phydev, MII_BCM54XX_IMR, reg);
229         if (err < 0)
230                 return err;
231
232         if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
233              BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
234             (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
235                 bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0);
236
237         if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
238             (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
239             (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
240                 bcm54xx_adjust_rxrefclk(phydev);
241
242         bcm54xx_phydsp_config(phydev);
243
244         return 0;
245 }
246
247 static int bcm5482_config_init(struct phy_device *phydev)
248 {
249         int err, reg;
250
251         err = bcm54xx_config_init(phydev);
252
253         if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
254                 /*
255                  * Enable secondary SerDes and its use as an LED source
256                  */
257                 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
258                 bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
259                                      reg |
260                                      BCM5482_SHD_SSD_LEDM |
261                                      BCM5482_SHD_SSD_EN);
262
263                 /*
264                  * Enable SGMII slave mode and auto-detection
265                  */
266                 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
267                 err = bcm54xx_exp_read(phydev, reg);
268                 if (err < 0)
269                         return err;
270                 err = bcm54xx_exp_write(phydev, reg, err |
271                                         BCM5482_SSD_SGMII_SLAVE_EN |
272                                         BCM5482_SSD_SGMII_SLAVE_AD);
273                 if (err < 0)
274                         return err;
275
276                 /*
277                  * Disable secondary SerDes powerdown
278                  */
279                 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
280                 err = bcm54xx_exp_read(phydev, reg);
281                 if (err < 0)
282                         return err;
283                 err = bcm54xx_exp_write(phydev, reg,
284                                         err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
285                 if (err < 0)
286                         return err;
287
288                 /*
289                  * Select 1000BASE-X register set (primary SerDes)
290                  */
291                 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
292                 bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
293                                      reg | BCM5482_SHD_MODE_1000BX);
294
295                 /*
296                  * LED1=ACTIVITYLED, LED3=LINKSPD[2]
297                  * (Use LED1 as secondary SerDes ACTIVITY LED)
298                  */
299                 bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
300                         BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
301                         BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
302
303                 /*
304                  * Auto-negotiation doesn't seem to work quite right
305                  * in this mode, so we disable it and force it to the
306                  * right speed/duplex setting.  Only 'link status'
307                  * is important.
308                  */
309                 phydev->autoneg = AUTONEG_DISABLE;
310                 phydev->speed = SPEED_1000;
311                 phydev->duplex = DUPLEX_FULL;
312         }
313
314         return err;
315 }
316
317 static int bcm5482_read_status(struct phy_device *phydev)
318 {
319         int err;
320
321         err = genphy_read_status(phydev);
322
323         if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
324                 /*
325                  * Only link status matters for 1000Base-X mode, so force
326                  * 1000 Mbit/s full-duplex status
327                  */
328                 if (phydev->link) {
329                         phydev->speed = SPEED_1000;
330                         phydev->duplex = DUPLEX_FULL;
331                 }
332         }
333
334         return err;
335 }
336
337 static int bcm54xx_ack_interrupt(struct phy_device *phydev)
338 {
339         int reg;
340
341         /* Clear pending interrupts.  */
342         reg = phy_read(phydev, MII_BCM54XX_ISR);
343         if (reg < 0)
344                 return reg;
345
346         return 0;
347 }
348
349 static int bcm54xx_config_intr(struct phy_device *phydev)
350 {
351         int reg, err;
352
353         reg = phy_read(phydev, MII_BCM54XX_ECR);
354         if (reg < 0)
355                 return reg;
356
357         if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
358                 reg &= ~MII_BCM54XX_ECR_IM;
359         else
360                 reg |= MII_BCM54XX_ECR_IM;
361
362         err = phy_write(phydev, MII_BCM54XX_ECR, reg);
363         return err;
364 }
365
366 static int bcm5481_config_aneg(struct phy_device *phydev)
367 {
368         int ret;
369
370         /* Aneg firsly. */
371         ret = genphy_config_aneg(phydev);
372
373         /* Then we can set up the delay. */
374         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
375                 u16 reg;
376
377                 /*
378                  * There is no BCM5481 specification available, so down
379                  * here is everything we know about "register 0x18". This
380                  * at least helps BCM5481 to successfully receive packets
381                  * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
382                  * says: "This sets delay between the RXD and RXC signals
383                  * instead of using trace lengths to achieve timing".
384                  */
385
386                 /* Set RDX clk delay. */
387                 reg = 0x7 | (0x7 << 12);
388                 phy_write(phydev, 0x18, reg);
389
390                 reg = phy_read(phydev, 0x18);
391                 /* Set RDX-RXC skew. */
392                 reg |= (1 << 8);
393                 /* Write bits 14:0. */
394                 reg |= (1 << 15);
395                 phy_write(phydev, 0x18, reg);
396         }
397
398         return ret;
399 }
400
401 static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
402 {
403         int val;
404
405         val = phy_read(phydev, reg);
406         if (val < 0)
407                 return val;
408
409         return phy_write(phydev, reg, val | set);
410 }
411
412 static int brcm_fet_config_init(struct phy_device *phydev)
413 {
414         int reg, err, err2, brcmtest;
415
416         /* Reset the PHY to bring it to a known state. */
417         err = phy_write(phydev, MII_BMCR, BMCR_RESET);
418         if (err < 0)
419                 return err;
420
421         reg = phy_read(phydev, MII_BRCM_FET_INTREG);
422         if (reg < 0)
423                 return reg;
424
425         /* Unmask events we are interested in and mask interrupts globally. */
426         reg = MII_BRCM_FET_IR_DUPLEX_EN |
427               MII_BRCM_FET_IR_SPEED_EN |
428               MII_BRCM_FET_IR_LINK_EN |
429               MII_BRCM_FET_IR_ENABLE |
430               MII_BRCM_FET_IR_MASK;
431
432         err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
433         if (err < 0)
434                 return err;
435
436         /* Enable shadow register access */
437         brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
438         if (brcmtest < 0)
439                 return brcmtest;
440
441         reg = brcmtest | MII_BRCM_FET_BT_SRE;
442
443         err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
444         if (err < 0)
445                 return err;
446
447         /* Set the LED mode */
448         reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
449         if (reg < 0) {
450                 err = reg;
451                 goto done;
452         }
453
454         reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
455         reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
456
457         err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
458         if (err < 0)
459                 goto done;
460
461         /* Enable auto MDIX */
462         err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
463                                        MII_BRCM_FET_SHDW_MC_FAME);
464         if (err < 0)
465                 goto done;
466
467         if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
468                 /* Enable auto power down */
469                 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
470                                                MII_BRCM_FET_SHDW_AS2_APDE);
471         }
472
473 done:
474         /* Disable shadow register access */
475         err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
476         if (!err)
477                 err = err2;
478
479         return err;
480 }
481
482 static int brcm_fet_ack_interrupt(struct phy_device *phydev)
483 {
484         int reg;
485
486         /* Clear pending interrupts.  */
487         reg = phy_read(phydev, MII_BRCM_FET_INTREG);
488         if (reg < 0)
489                 return reg;
490
491         return 0;
492 }
493
494 static int brcm_fet_config_intr(struct phy_device *phydev)
495 {
496         int reg, err;
497
498         reg = phy_read(phydev, MII_BRCM_FET_INTREG);
499         if (reg < 0)
500                 return reg;
501
502         if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
503                 reg &= ~MII_BRCM_FET_IR_MASK;
504         else
505                 reg |= MII_BRCM_FET_IR_MASK;
506
507         err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
508         return err;
509 }
510
511 static struct phy_driver broadcom_drivers[] = {
512 {
513         .phy_id         = PHY_ID_BCM5411,
514         .phy_id_mask    = 0xfffffff0,
515         .name           = "Broadcom BCM5411",
516         .features       = PHY_GBIT_FEATURES |
517                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
518         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
519         .config_init    = bcm54xx_config_init,
520         .config_aneg    = genphy_config_aneg,
521         .read_status    = genphy_read_status,
522         .ack_interrupt  = bcm54xx_ack_interrupt,
523         .config_intr    = bcm54xx_config_intr,
524         .driver         = { .owner = THIS_MODULE },
525 }, {
526         .phy_id         = PHY_ID_BCM5421,
527         .phy_id_mask    = 0xfffffff0,
528         .name           = "Broadcom BCM5421",
529         .features       = PHY_GBIT_FEATURES |
530                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
531         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
532         .config_init    = bcm54xx_config_init,
533         .config_aneg    = genphy_config_aneg,
534         .read_status    = genphy_read_status,
535         .ack_interrupt  = bcm54xx_ack_interrupt,
536         .config_intr    = bcm54xx_config_intr,
537         .driver         = { .owner = THIS_MODULE },
538 }, {
539         .phy_id         = PHY_ID_BCM5461,
540         .phy_id_mask    = 0xfffffff0,
541         .name           = "Broadcom BCM5461",
542         .features       = PHY_GBIT_FEATURES |
543                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
544         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
545         .config_init    = bcm54xx_config_init,
546         .config_aneg    = genphy_config_aneg,
547         .read_status    = genphy_read_status,
548         .ack_interrupt  = bcm54xx_ack_interrupt,
549         .config_intr    = bcm54xx_config_intr,
550         .driver         = { .owner = THIS_MODULE },
551 }, {
552         .phy_id         = PHY_ID_BCM54616S,
553         .phy_id_mask    = 0xfffffff0,
554         .name           = "Broadcom BCM54616S",
555         .features       = PHY_GBIT_FEATURES |
556                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
557         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
558         .config_init    = bcm54xx_config_init,
559         .config_aneg    = genphy_config_aneg,
560         .read_status    = genphy_read_status,
561         .ack_interrupt  = bcm54xx_ack_interrupt,
562         .config_intr    = bcm54xx_config_intr,
563         .driver         = { .owner = THIS_MODULE },
564 }, {
565         .phy_id         = PHY_ID_BCM5464,
566         .phy_id_mask    = 0xfffffff0,
567         .name           = "Broadcom BCM5464",
568         .features       = PHY_GBIT_FEATURES |
569                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
570         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
571         .config_init    = bcm54xx_config_init,
572         .config_aneg    = genphy_config_aneg,
573         .read_status    = genphy_read_status,
574         .ack_interrupt  = bcm54xx_ack_interrupt,
575         .config_intr    = bcm54xx_config_intr,
576         .driver         = { .owner = THIS_MODULE },
577 }, {
578         .phy_id         = PHY_ID_BCM5481,
579         .phy_id_mask    = 0xfffffff0,
580         .name           = "Broadcom BCM5481",
581         .features       = PHY_GBIT_FEATURES |
582                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
583         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
584         .config_init    = bcm54xx_config_init,
585         .config_aneg    = bcm5481_config_aneg,
586         .read_status    = genphy_read_status,
587         .ack_interrupt  = bcm54xx_ack_interrupt,
588         .config_intr    = bcm54xx_config_intr,
589         .driver         = { .owner = THIS_MODULE },
590 }, {
591         .phy_id         = PHY_ID_BCM5482,
592         .phy_id_mask    = 0xfffffff0,
593         .name           = "Broadcom BCM5482",
594         .features       = PHY_GBIT_FEATURES |
595                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
596         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
597         .config_init    = bcm5482_config_init,
598         .config_aneg    = genphy_config_aneg,
599         .read_status    = bcm5482_read_status,
600         .ack_interrupt  = bcm54xx_ack_interrupt,
601         .config_intr    = bcm54xx_config_intr,
602         .driver         = { .owner = THIS_MODULE },
603 }, {
604         .phy_id         = PHY_ID_BCM50610,
605         .phy_id_mask    = 0xfffffff0,
606         .name           = "Broadcom BCM50610",
607         .features       = PHY_GBIT_FEATURES |
608                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
609         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
610         .config_init    = bcm54xx_config_init,
611         .config_aneg    = genphy_config_aneg,
612         .read_status    = genphy_read_status,
613         .ack_interrupt  = bcm54xx_ack_interrupt,
614         .config_intr    = bcm54xx_config_intr,
615         .driver         = { .owner = THIS_MODULE },
616 }, {
617         .phy_id         = PHY_ID_BCM50610M,
618         .phy_id_mask    = 0xfffffff0,
619         .name           = "Broadcom BCM50610M",
620         .features       = PHY_GBIT_FEATURES |
621                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
622         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
623         .config_init    = bcm54xx_config_init,
624         .config_aneg    = genphy_config_aneg,
625         .read_status    = genphy_read_status,
626         .ack_interrupt  = bcm54xx_ack_interrupt,
627         .config_intr    = bcm54xx_config_intr,
628         .driver         = { .owner = THIS_MODULE },
629 }, {
630         .phy_id         = PHY_ID_BCM57780,
631         .phy_id_mask    = 0xfffffff0,
632         .name           = "Broadcom BCM57780",
633         .features       = PHY_GBIT_FEATURES |
634                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
635         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
636         .config_init    = bcm54xx_config_init,
637         .config_aneg    = genphy_config_aneg,
638         .read_status    = genphy_read_status,
639         .ack_interrupt  = bcm54xx_ack_interrupt,
640         .config_intr    = bcm54xx_config_intr,
641         .driver         = { .owner = THIS_MODULE },
642 }, {
643         .phy_id         = PHY_ID_BCMAC131,
644         .phy_id_mask    = 0xfffffff0,
645         .name           = "Broadcom BCMAC131",
646         .features       = PHY_BASIC_FEATURES |
647                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
648         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
649         .config_init    = brcm_fet_config_init,
650         .config_aneg    = genphy_config_aneg,
651         .read_status    = genphy_read_status,
652         .ack_interrupt  = brcm_fet_ack_interrupt,
653         .config_intr    = brcm_fet_config_intr,
654         .driver         = { .owner = THIS_MODULE },
655 }, {
656         .phy_id         = PHY_ID_BCM5241,
657         .phy_id_mask    = 0xfffffff0,
658         .name           = "Broadcom BCM5241",
659         .features       = PHY_BASIC_FEATURES |
660                           SUPPORTED_Pause | SUPPORTED_Asym_Pause,
661         .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
662         .config_init    = brcm_fet_config_init,
663         .config_aneg    = genphy_config_aneg,
664         .read_status    = genphy_read_status,
665         .ack_interrupt  = brcm_fet_ack_interrupt,
666         .config_intr    = brcm_fet_config_intr,
667         .driver         = { .owner = THIS_MODULE },
668 } };
669
670 module_phy_driver(broadcom_drivers);
671
672 static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
673         { PHY_ID_BCM5411, 0xfffffff0 },
674         { PHY_ID_BCM5421, 0xfffffff0 },
675         { PHY_ID_BCM5461, 0xfffffff0 },
676         { PHY_ID_BCM54616S, 0xfffffff0 },
677         { PHY_ID_BCM5464, 0xfffffff0 },
678         { PHY_ID_BCM5482, 0xfffffff0 },
679         { PHY_ID_BCM5482, 0xfffffff0 },
680         { PHY_ID_BCM50610, 0xfffffff0 },
681         { PHY_ID_BCM50610M, 0xfffffff0 },
682         { PHY_ID_BCM57780, 0xfffffff0 },
683         { PHY_ID_BCMAC131, 0xfffffff0 },
684         { PHY_ID_BCM5241, 0xfffffff0 },
685         { }
686 };
687
688 MODULE_DEVICE_TABLE(mdio, broadcom_tbl);