2 * drivers/net/phy/broadcom.c
4 * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
7 * Copyright (c) 2006 Maciej W. Rozycki
9 * Inspired by code written by Amy Fong.
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.
17 #include <linux/module.h>
18 #include <linux/phy.h>
19 #include <linux/brcmphy.h>
22 #define BRCM_PHY_MODEL(phydev) \
23 ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
25 #define BRCM_PHY_REV(phydev) \
26 ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
28 MODULE_DESCRIPTION("Broadcom PHY driver");
29 MODULE_AUTHOR("Maciej W. Rozycki");
30 MODULE_LICENSE("GPL");
33 * Indirect register access functions for the 1000BASE-T/100BASE-TX/10BASE-T
34 * 0x1c shadow registers.
36 static int bcm54xx_shadow_read(struct phy_device
*phydev
, u16 shadow
)
38 phy_write(phydev
, MII_BCM54XX_SHD
, MII_BCM54XX_SHD_VAL(shadow
));
39 return MII_BCM54XX_SHD_DATA(phy_read(phydev
, MII_BCM54XX_SHD
));
42 static int bcm54xx_shadow_write(struct phy_device
*phydev
, u16 shadow
, u16 val
)
44 return phy_write(phydev
, MII_BCM54XX_SHD
,
45 MII_BCM54XX_SHD_WRITE
|
46 MII_BCM54XX_SHD_VAL(shadow
) |
47 MII_BCM54XX_SHD_DATA(val
));
50 /* Indirect register access functions for the Expansion Registers */
51 static int bcm54xx_exp_read(struct phy_device
*phydev
, u16 regnum
)
55 val
= phy_write(phydev
, MII_BCM54XX_EXP_SEL
, regnum
);
59 val
= phy_read(phydev
, MII_BCM54XX_EXP_DATA
);
61 /* Restore default value. It's O.K. if this write fails. */
62 phy_write(phydev
, MII_BCM54XX_EXP_SEL
, 0);
67 static int bcm54xx_exp_write(struct phy_device
*phydev
, u16 regnum
, u16 val
)
71 ret
= phy_write(phydev
, MII_BCM54XX_EXP_SEL
, regnum
);
75 ret
= phy_write(phydev
, MII_BCM54XX_EXP_DATA
, val
);
77 /* Restore default value. It's O.K. if this write fails. */
78 phy_write(phydev
, MII_BCM54XX_EXP_SEL
, 0);
83 static int bcm54xx_auxctl_write(struct phy_device
*phydev
, u16 regnum
, u16 val
)
85 return phy_write(phydev
, MII_BCM54XX_AUX_CTL
, regnum
| val
);
88 /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
89 static int bcm50610_a0_workaround(struct phy_device
*phydev
)
93 err
= bcm54xx_exp_write(phydev
, MII_BCM54XX_EXP_AADJ1CH0
,
94 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN
|
95 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF
);
99 err
= bcm54xx_exp_write(phydev
, MII_BCM54XX_EXP_AADJ1CH3
,
100 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ
);
104 err
= bcm54xx_exp_write(phydev
, MII_BCM54XX_EXP_EXP75
,
105 MII_BCM54XX_EXP_EXP75_VDACCTRL
);
109 err
= bcm54xx_exp_write(phydev
, MII_BCM54XX_EXP_EXP96
,
110 MII_BCM54XX_EXP_EXP96_MYST
);
114 err
= bcm54xx_exp_write(phydev
, MII_BCM54XX_EXP_EXP97
,
115 MII_BCM54XX_EXP_EXP97_MYST
);
120 static int bcm54xx_phydsp_config(struct phy_device
*phydev
)
124 /* Enable the SMDSP clock */
125 err
= bcm54xx_auxctl_write(phydev
,
126 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL
,
127 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA
|
128 MII_BCM54XX_AUXCTL_ACTL_TX_6DB
);
132 if (BRCM_PHY_MODEL(phydev
) == PHY_ID_BCM50610
||
133 BRCM_PHY_MODEL(phydev
) == PHY_ID_BCM50610M
) {
134 /* Clear bit 9 to fix a phy interop issue. */
135 err
= bcm54xx_exp_write(phydev
, MII_BCM54XX_EXP_EXP08
,
136 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ
);
140 if (phydev
->drv
->phy_id
== PHY_ID_BCM50610
) {
141 err
= bcm50610_a0_workaround(phydev
);
147 if (BRCM_PHY_MODEL(phydev
) == PHY_ID_BCM57780
) {
150 val
= bcm54xx_exp_read(phydev
, MII_BCM54XX_EXP_EXP75
);
154 val
|= MII_BCM54XX_EXP_EXP75_CM_OSC
;
155 err
= bcm54xx_exp_write(phydev
, MII_BCM54XX_EXP_EXP75
, val
);
159 /* Disable the SMDSP clock */
160 err2
= bcm54xx_auxctl_write(phydev
,
161 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL
,
162 MII_BCM54XX_AUXCTL_ACTL_TX_6DB
);
164 /* Return the first error reported. */
165 return err
? err
: err2
;
168 static void bcm54xx_adjust_rxrefclk(struct phy_device
*phydev
)
172 bool clk125en
= true;
174 /* Abort if we are using an untested phy. */
175 if (BRCM_PHY_MODEL(phydev
) != PHY_ID_BCM57780
&&
176 BRCM_PHY_MODEL(phydev
) != PHY_ID_BCM50610
&&
177 BRCM_PHY_MODEL(phydev
) != PHY_ID_BCM50610M
)
180 val
= bcm54xx_shadow_read(phydev
, BCM54XX_SHD_SCR3
);
186 if ((BRCM_PHY_MODEL(phydev
) == PHY_ID_BCM50610
||
187 BRCM_PHY_MODEL(phydev
) == PHY_ID_BCM50610M
) &&
188 BRCM_PHY_REV(phydev
) >= 0x3) {
190 * Here, bit 0 _disables_ CLK125 when set.
191 * This bit is set by default.
195 if (phydev
->dev_flags
& PHY_BRCM_RX_REFCLK_UNUSED
) {
196 /* Here, bit 0 _enables_ CLK125 when set */
197 val
&= ~BCM54XX_SHD_SCR3_DEF_CLK125
;
202 if (!clk125en
|| (phydev
->dev_flags
& PHY_BRCM_AUTO_PWRDWN_ENABLE
))
203 val
&= ~BCM54XX_SHD_SCR3_DLLAPD_DIS
;
205 val
|= BCM54XX_SHD_SCR3_DLLAPD_DIS
;
207 if (phydev
->dev_flags
& PHY_BRCM_DIS_TXCRXC_NOENRGY
)
208 val
|= BCM54XX_SHD_SCR3_TRDDAPD
;
211 bcm54xx_shadow_write(phydev
, BCM54XX_SHD_SCR3
, val
);
213 val
= bcm54xx_shadow_read(phydev
, BCM54XX_SHD_APD
);
219 if (!clk125en
|| (phydev
->dev_flags
& PHY_BRCM_AUTO_PWRDWN_ENABLE
))
220 val
|= BCM54XX_SHD_APD_EN
;
222 val
&= ~BCM54XX_SHD_APD_EN
;
225 bcm54xx_shadow_write(phydev
, BCM54XX_SHD_APD
, val
);
228 static int bcm54xx_config_init(struct phy_device
*phydev
)
232 reg
= phy_read(phydev
, MII_BCM54XX_ECR
);
236 /* Mask interrupts globally. */
237 reg
|= MII_BCM54XX_ECR_IM
;
238 err
= phy_write(phydev
, MII_BCM54XX_ECR
, reg
);
242 /* Unmask events we are interested in. */
243 reg
= ~(MII_BCM54XX_INT_DUPLEX
|
244 MII_BCM54XX_INT_SPEED
|
245 MII_BCM54XX_INT_LINK
);
246 err
= phy_write(phydev
, MII_BCM54XX_IMR
, reg
);
250 if ((BRCM_PHY_MODEL(phydev
) == PHY_ID_BCM50610
||
251 BRCM_PHY_MODEL(phydev
) == PHY_ID_BCM50610M
) &&
252 (phydev
->dev_flags
& PHY_BRCM_CLEAR_RGMII_MODE
))
253 bcm54xx_shadow_write(phydev
, BCM54XX_SHD_RGMII_MODE
, 0);
255 if ((phydev
->dev_flags
& PHY_BRCM_RX_REFCLK_UNUSED
) ||
256 (phydev
->dev_flags
& PHY_BRCM_DIS_TXCRXC_NOENRGY
) ||
257 (phydev
->dev_flags
& PHY_BRCM_AUTO_PWRDWN_ENABLE
))
258 bcm54xx_adjust_rxrefclk(phydev
);
260 bcm54xx_phydsp_config(phydev
);
265 static int bcm5482_config_init(struct phy_device
*phydev
)
269 err
= bcm54xx_config_init(phydev
);
271 if (phydev
->dev_flags
& PHY_BCM_FLAGS_MODE_1000BX
) {
273 * Enable secondary SerDes and its use as an LED source
275 reg
= bcm54xx_shadow_read(phydev
, BCM5482_SHD_SSD
);
276 bcm54xx_shadow_write(phydev
, BCM5482_SHD_SSD
,
278 BCM5482_SHD_SSD_LEDM
|
282 * Enable SGMII slave mode and auto-detection
284 reg
= BCM5482_SSD_SGMII_SLAVE
| MII_BCM54XX_EXP_SEL_SSD
;
285 err
= bcm54xx_exp_read(phydev
, reg
);
288 err
= bcm54xx_exp_write(phydev
, reg
, err
|
289 BCM5482_SSD_SGMII_SLAVE_EN
|
290 BCM5482_SSD_SGMII_SLAVE_AD
);
295 * Disable secondary SerDes powerdown
297 reg
= BCM5482_SSD_1000BX_CTL
| MII_BCM54XX_EXP_SEL_SSD
;
298 err
= bcm54xx_exp_read(phydev
, reg
);
301 err
= bcm54xx_exp_write(phydev
, reg
,
302 err
& ~BCM5482_SSD_1000BX_CTL_PWRDOWN
);
307 * Select 1000BASE-X register set (primary SerDes)
309 reg
= bcm54xx_shadow_read(phydev
, BCM5482_SHD_MODE
);
310 bcm54xx_shadow_write(phydev
, BCM5482_SHD_MODE
,
311 reg
| BCM5482_SHD_MODE_1000BX
);
314 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
315 * (Use LED1 as secondary SerDes ACTIVITY LED)
317 bcm54xx_shadow_write(phydev
, BCM5482_SHD_LEDS1
,
318 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED
) |
319 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2
));
322 * Auto-negotiation doesn't seem to work quite right
323 * in this mode, so we disable it and force it to the
324 * right speed/duplex setting. Only 'link status'
327 phydev
->autoneg
= AUTONEG_DISABLE
;
328 phydev
->speed
= SPEED_1000
;
329 phydev
->duplex
= DUPLEX_FULL
;
335 static int bcm5482_read_status(struct phy_device
*phydev
)
339 err
= genphy_read_status(phydev
);
341 if (phydev
->dev_flags
& PHY_BCM_FLAGS_MODE_1000BX
) {
343 * Only link status matters for 1000Base-X mode, so force
344 * 1000 Mbit/s full-duplex status
347 phydev
->speed
= SPEED_1000
;
348 phydev
->duplex
= DUPLEX_FULL
;
355 static int bcm54xx_ack_interrupt(struct phy_device
*phydev
)
359 /* Clear pending interrupts. */
360 reg
= phy_read(phydev
, MII_BCM54XX_ISR
);
367 static int bcm54xx_config_intr(struct phy_device
*phydev
)
371 reg
= phy_read(phydev
, MII_BCM54XX_ECR
);
375 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
)
376 reg
&= ~MII_BCM54XX_ECR_IM
;
378 reg
|= MII_BCM54XX_ECR_IM
;
380 err
= phy_write(phydev
, MII_BCM54XX_ECR
, reg
);
384 static int bcm5481_config_aneg(struct phy_device
*phydev
)
389 ret
= genphy_config_aneg(phydev
);
391 /* Then we can set up the delay. */
392 if (phydev
->interface
== PHY_INTERFACE_MODE_RGMII_RXID
) {
396 * There is no BCM5481 specification available, so down
397 * here is everything we know about "register 0x18". This
398 * at least helps BCM5481 to successfully receive packets
399 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
400 * says: "This sets delay between the RXD and RXC signals
401 * instead of using trace lengths to achieve timing".
404 /* Set RDX clk delay. */
405 reg
= 0x7 | (0x7 << 12);
406 phy_write(phydev
, 0x18, reg
);
408 reg
= phy_read(phydev
, 0x18);
409 /* Set RDX-RXC skew. */
411 /* Write bits 14:0. */
413 phy_write(phydev
, 0x18, reg
);
419 static int brcm_phy_setbits(struct phy_device
*phydev
, int reg
, int set
)
423 val
= phy_read(phydev
, reg
);
427 return phy_write(phydev
, reg
, val
| set
);
430 static int brcm_fet_config_init(struct phy_device
*phydev
)
432 int reg
, err
, err2
, brcmtest
;
434 /* Reset the PHY to bring it to a known state. */
435 err
= phy_write(phydev
, MII_BMCR
, BMCR_RESET
);
439 reg
= phy_read(phydev
, MII_BRCM_FET_INTREG
);
443 /* Unmask events we are interested in and mask interrupts globally. */
444 reg
= MII_BRCM_FET_IR_DUPLEX_EN
|
445 MII_BRCM_FET_IR_SPEED_EN
|
446 MII_BRCM_FET_IR_LINK_EN
|
447 MII_BRCM_FET_IR_ENABLE
|
448 MII_BRCM_FET_IR_MASK
;
450 err
= phy_write(phydev
, MII_BRCM_FET_INTREG
, reg
);
454 /* Enable shadow register access */
455 brcmtest
= phy_read(phydev
, MII_BRCM_FET_BRCMTEST
);
459 reg
= brcmtest
| MII_BRCM_FET_BT_SRE
;
461 err
= phy_write(phydev
, MII_BRCM_FET_BRCMTEST
, reg
);
465 /* Set the LED mode */
466 reg
= phy_read(phydev
, MII_BRCM_FET_SHDW_AUXMODE4
);
472 reg
&= ~MII_BRCM_FET_SHDW_AM4_LED_MASK
;
473 reg
|= MII_BRCM_FET_SHDW_AM4_LED_MODE1
;
475 err
= phy_write(phydev
, MII_BRCM_FET_SHDW_AUXMODE4
, reg
);
479 /* Enable auto MDIX */
480 err
= brcm_phy_setbits(phydev
, MII_BRCM_FET_SHDW_MISCCTRL
,
481 MII_BRCM_FET_SHDW_MC_FAME
);
485 if (phydev
->dev_flags
& PHY_BRCM_AUTO_PWRDWN_ENABLE
) {
486 /* Enable auto power down */
487 err
= brcm_phy_setbits(phydev
, MII_BRCM_FET_SHDW_AUXSTAT2
,
488 MII_BRCM_FET_SHDW_AS2_APDE
);
492 /* Disable shadow register access */
493 err2
= phy_write(phydev
, MII_BRCM_FET_BRCMTEST
, brcmtest
);
500 static int brcm_fet_ack_interrupt(struct phy_device
*phydev
)
504 /* Clear pending interrupts. */
505 reg
= phy_read(phydev
, MII_BRCM_FET_INTREG
);
512 static int brcm_fet_config_intr(struct phy_device
*phydev
)
516 reg
= phy_read(phydev
, MII_BRCM_FET_INTREG
);
520 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
)
521 reg
&= ~MII_BRCM_FET_IR_MASK
;
523 reg
|= MII_BRCM_FET_IR_MASK
;
525 err
= phy_write(phydev
, MII_BRCM_FET_INTREG
, reg
);
529 static struct phy_driver broadcom_drivers
[] = {
531 .phy_id
= PHY_ID_BCM5411
,
532 .phy_id_mask
= 0xfffffff0,
533 .name
= "Broadcom BCM5411",
534 .features
= PHY_GBIT_FEATURES
|
535 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
536 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
537 .config_init
= bcm54xx_config_init
,
538 .config_aneg
= genphy_config_aneg
,
539 .read_status
= genphy_read_status
,
540 .ack_interrupt
= bcm54xx_ack_interrupt
,
541 .config_intr
= bcm54xx_config_intr
,
542 .driver
= { .owner
= THIS_MODULE
},
544 .phy_id
= PHY_ID_BCM5421
,
545 .phy_id_mask
= 0xfffffff0,
546 .name
= "Broadcom BCM5421",
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
},
557 .phy_id
= PHY_ID_BCM5461
,
558 .phy_id_mask
= 0xfffffff0,
559 .name
= "Broadcom BCM5461",
560 .features
= PHY_GBIT_FEATURES
|
561 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
562 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
563 .config_init
= bcm54xx_config_init
,
564 .config_aneg
= genphy_config_aneg
,
565 .read_status
= genphy_read_status
,
566 .ack_interrupt
= bcm54xx_ack_interrupt
,
567 .config_intr
= bcm54xx_config_intr
,
568 .driver
= { .owner
= THIS_MODULE
},
570 .phy_id
= PHY_ID_BCM5464
,
571 .phy_id_mask
= 0xfffffff0,
572 .name
= "Broadcom BCM5464",
573 .features
= PHY_GBIT_FEATURES
|
574 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
575 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
576 .config_init
= bcm54xx_config_init
,
577 .config_aneg
= genphy_config_aneg
,
578 .read_status
= genphy_read_status
,
579 .ack_interrupt
= bcm54xx_ack_interrupt
,
580 .config_intr
= bcm54xx_config_intr
,
581 .driver
= { .owner
= THIS_MODULE
},
583 .phy_id
= PHY_ID_BCM5481
,
584 .phy_id_mask
= 0xfffffff0,
585 .name
= "Broadcom BCM5481",
586 .features
= PHY_GBIT_FEATURES
|
587 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
588 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
589 .config_init
= bcm54xx_config_init
,
590 .config_aneg
= bcm5481_config_aneg
,
591 .read_status
= genphy_read_status
,
592 .ack_interrupt
= bcm54xx_ack_interrupt
,
593 .config_intr
= bcm54xx_config_intr
,
594 .driver
= { .owner
= THIS_MODULE
},
596 .phy_id
= PHY_ID_BCM5482
,
597 .phy_id_mask
= 0xfffffff0,
598 .name
= "Broadcom BCM5482",
599 .features
= PHY_GBIT_FEATURES
|
600 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
601 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
602 .config_init
= bcm5482_config_init
,
603 .config_aneg
= genphy_config_aneg
,
604 .read_status
= bcm5482_read_status
,
605 .ack_interrupt
= bcm54xx_ack_interrupt
,
606 .config_intr
= bcm54xx_config_intr
,
607 .driver
= { .owner
= THIS_MODULE
},
609 .phy_id
= PHY_ID_BCM50610
,
610 .phy_id_mask
= 0xfffffff0,
611 .name
= "Broadcom BCM50610",
612 .features
= PHY_GBIT_FEATURES
|
613 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
614 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
615 .config_init
= bcm54xx_config_init
,
616 .config_aneg
= genphy_config_aneg
,
617 .read_status
= genphy_read_status
,
618 .ack_interrupt
= bcm54xx_ack_interrupt
,
619 .config_intr
= bcm54xx_config_intr
,
620 .driver
= { .owner
= THIS_MODULE
},
622 .phy_id
= PHY_ID_BCM50610M
,
623 .phy_id_mask
= 0xfffffff0,
624 .name
= "Broadcom BCM50610M",
625 .features
= PHY_GBIT_FEATURES
|
626 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
627 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
628 .config_init
= bcm54xx_config_init
,
629 .config_aneg
= genphy_config_aneg
,
630 .read_status
= genphy_read_status
,
631 .ack_interrupt
= bcm54xx_ack_interrupt
,
632 .config_intr
= bcm54xx_config_intr
,
633 .driver
= { .owner
= THIS_MODULE
},
635 .phy_id
= PHY_ID_BCM57780
,
636 .phy_id_mask
= 0xfffffff0,
637 .name
= "Broadcom BCM57780",
638 .features
= PHY_GBIT_FEATURES
|
639 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
640 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
641 .config_init
= bcm54xx_config_init
,
642 .config_aneg
= genphy_config_aneg
,
643 .read_status
= genphy_read_status
,
644 .ack_interrupt
= bcm54xx_ack_interrupt
,
645 .config_intr
= bcm54xx_config_intr
,
646 .driver
= { .owner
= THIS_MODULE
},
648 .phy_id
= PHY_ID_BCMAC131
,
649 .phy_id_mask
= 0xfffffff0,
650 .name
= "Broadcom BCMAC131",
651 .features
= PHY_BASIC_FEATURES
|
652 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
653 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
654 .config_init
= brcm_fet_config_init
,
655 .config_aneg
= genphy_config_aneg
,
656 .read_status
= genphy_read_status
,
657 .ack_interrupt
= brcm_fet_ack_interrupt
,
658 .config_intr
= brcm_fet_config_intr
,
659 .driver
= { .owner
= THIS_MODULE
},
661 .phy_id
= PHY_ID_BCM5241
,
662 .phy_id_mask
= 0xfffffff0,
663 .name
= "Broadcom BCM5241",
664 .features
= PHY_BASIC_FEATURES
|
665 SUPPORTED_Pause
| SUPPORTED_Asym_Pause
,
666 .flags
= PHY_HAS_MAGICANEG
| PHY_HAS_INTERRUPT
,
667 .config_init
= brcm_fet_config_init
,
668 .config_aneg
= genphy_config_aneg
,
669 .read_status
= genphy_read_status
,
670 .ack_interrupt
= brcm_fet_ack_interrupt
,
671 .config_intr
= brcm_fet_config_intr
,
672 .driver
= { .owner
= THIS_MODULE
},
675 static int __init
broadcom_init(void)
677 return phy_drivers_register(broadcom_drivers
,
678 ARRAY_SIZE(broadcom_drivers
));
681 static void __exit
broadcom_exit(void)
683 phy_drivers_unregister(broadcom_drivers
,
684 ARRAY_SIZE(broadcom_drivers
));
687 module_init(broadcom_init
);
688 module_exit(broadcom_exit
);
690 static struct mdio_device_id __maybe_unused broadcom_tbl
[] = {
691 { PHY_ID_BCM5411
, 0xfffffff0 },
692 { PHY_ID_BCM5421
, 0xfffffff0 },
693 { PHY_ID_BCM5461
, 0xfffffff0 },
694 { PHY_ID_BCM5464
, 0xfffffff0 },
695 { PHY_ID_BCM5482
, 0xfffffff0 },
696 { PHY_ID_BCM5482
, 0xfffffff0 },
697 { PHY_ID_BCM50610
, 0xfffffff0 },
698 { PHY_ID_BCM50610M
, 0xfffffff0 },
699 { PHY_ID_BCM57780
, 0xfffffff0 },
700 { PHY_ID_BCMAC131
, 0xfffffff0 },
701 { PHY_ID_BCM5241
, 0xfffffff0 },
705 MODULE_DEVICE_TABLE(mdio
, broadcom_tbl
);