| .. | .. |
|---|
| 326 | 326 | return genphy_config_aneg(phydev); |
|---|
| 327 | 327 | } |
|---|
| 328 | 328 | |
|---|
| 329 | +static void lan88xx_link_change_notify(struct phy_device *phydev) |
|---|
| 330 | +{ |
|---|
| 331 | + int temp; |
|---|
| 332 | + |
|---|
| 333 | + /* At forced 100 F/H mode, chip may fail to set mode correctly |
|---|
| 334 | + * when cable is switched between long(~50+m) and short one. |
|---|
| 335 | + * As workaround, set to 10 before setting to 100 |
|---|
| 336 | + * at forced 100 F/H mode. |
|---|
| 337 | + */ |
|---|
| 338 | + if (!phydev->autoneg && phydev->speed == 100) { |
|---|
| 339 | + /* disable phy interrupt */ |
|---|
| 340 | + temp = phy_read(phydev, LAN88XX_INT_MASK); |
|---|
| 341 | + temp &= ~LAN88XX_INT_MASK_MDINTPIN_EN_; |
|---|
| 342 | + phy_write(phydev, LAN88XX_INT_MASK, temp); |
|---|
| 343 | + |
|---|
| 344 | + temp = phy_read(phydev, MII_BMCR); |
|---|
| 345 | + temp &= ~(BMCR_SPEED100 | BMCR_SPEED1000); |
|---|
| 346 | + phy_write(phydev, MII_BMCR, temp); /* set to 10 first */ |
|---|
| 347 | + temp |= BMCR_SPEED100; |
|---|
| 348 | + phy_write(phydev, MII_BMCR, temp); /* set to 100 later */ |
|---|
| 349 | + |
|---|
| 350 | + /* clear pending interrupt generated while workaround */ |
|---|
| 351 | + temp = phy_read(phydev, LAN88XX_INT_STS); |
|---|
| 352 | + |
|---|
| 353 | + /* enable phy interrupt back */ |
|---|
| 354 | + temp = phy_read(phydev, LAN88XX_INT_MASK); |
|---|
| 355 | + temp |= LAN88XX_INT_MASK_MDINTPIN_EN_; |
|---|
| 356 | + phy_write(phydev, LAN88XX_INT_MASK, temp); |
|---|
| 357 | + } |
|---|
| 358 | +} |
|---|
| 359 | + |
|---|
| 329 | 360 | static struct phy_driver microchip_phy_driver[] = { |
|---|
| 330 | 361 | { |
|---|
| 331 | 362 | .phy_id = 0x0007c130, |
|---|
| .. | .. |
|---|
| 339 | 370 | |
|---|
| 340 | 371 | .config_init = lan88xx_config_init, |
|---|
| 341 | 372 | .config_aneg = lan88xx_config_aneg, |
|---|
| 373 | + .link_change_notify = lan88xx_link_change_notify, |
|---|
| 342 | 374 | |
|---|
| 343 | 375 | .ack_interrupt = lan88xx_phy_ack_interrupt, |
|---|
| 344 | 376 | .config_intr = lan88xx_phy_config_intr, |
|---|