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_BCM5464, 553 .phy_id_mask = 0xfffffff0, 554 .name = "Broadcom BCM5464", 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_BCM5481, 566 .phy_id_mask = 0xfffffff0, 567 .name = "Broadcom BCM5481", 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 = bcm5481_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_BCM5482, 579 .phy_id_mask = 0xfffffff0, 580 .name = "Broadcom BCM5482", 581 .features = PHY_GBIT_FEATURES | 582 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 583 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 584 .config_init = bcm5482_config_init, 585 .config_aneg = genphy_config_aneg, 586 .read_status = bcm5482_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_BCM50610, 592 .phy_id_mask = 0xfffffff0, 593 .name = "Broadcom BCM50610", 594 .features = PHY_GBIT_FEATURES | 595 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 596 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 597 .config_init = bcm54xx_config_init, 598 .config_aneg = genphy_config_aneg, 599 .read_status = genphy_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_BCM50610M, 605 .phy_id_mask = 0xfffffff0, 606 .name = "Broadcom BCM50610M", 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_BCM57780, 618 .phy_id_mask = 0xfffffff0, 619 .name = "Broadcom BCM57780", 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_BCMAC131, 631 .phy_id_mask = 0xfffffff0, 632 .name = "Broadcom BCMAC131", 633 .features = PHY_BASIC_FEATURES | 634 SUPPORTED_Pause | SUPPORTED_Asym_Pause, 635 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 636 .config_init = brcm_fet_config_init, 637 .config_aneg = genphy_config_aneg, 638 .read_status = genphy_read_status, 639 .ack_interrupt = brcm_fet_ack_interrupt, 640 .config_intr = brcm_fet_config_intr, 641 .driver = { .owner = THIS_MODULE }, 642 }, { 643 .phy_id = PHY_ID_BCM5241, 644 .phy_id_mask = 0xfffffff0, 645 .name = "Broadcom BCM5241", 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 657 static int __init broadcom_init(void) 658 { 659 return phy_drivers_register(broadcom_drivers, 660 ARRAY_SIZE(broadcom_drivers)); 661 } 662 663 static void __exit broadcom_exit(void) 664 { 665 phy_drivers_unregister(broadcom_drivers, 666 ARRAY_SIZE(broadcom_drivers)); 667 } 668 669 module_init(broadcom_init); 670 module_exit(broadcom_exit); 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_BCM5464, 0xfffffff0 }, 677 { PHY_ID_BCM5482, 0xfffffff0 }, 678 { PHY_ID_BCM5482, 0xfffffff0 }, 679 { PHY_ID_BCM50610, 0xfffffff0 }, 680 { PHY_ID_BCM50610M, 0xfffffff0 }, 681 { PHY_ID_BCM57780, 0xfffffff0 }, 682 { PHY_ID_BCMAC131, 0xfffffff0 }, 683 { PHY_ID_BCM5241, 0xfffffff0 }, 684 { } 685 }; 686 687 MODULE_DEVICE_TABLE(mdio, broadcom_tbl); 688