diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c index ed20352a589a..b88f63234b4e 100644 --- a/drivers/net/mdio/mdio-i2c.c +++ b/drivers/net/mdio/mdio-i2c.c @@ -419,6 +419,50 @@ static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad, return 0; } +static int i2c_mii_probe_rollball(struct i2c_adapter *i2c) +{ + u8 data_buf[] = { ROLLBALL_DATA_ADDR, 0x01, 0x00, 0x00 }; + u8 cmd_buf[] = { ROLLBALL_CMD_ADDR, ROLLBALL_CMD_READ }; + u8 cmd_addr = ROLLBALL_CMD_ADDR; + struct i2c_msg msgs[2]; + u8 result; + int ret; + int i; + + msgs[0].addr = ROLLBALL_PHY_I2C_ADDR; + msgs[0].flags = 0; + msgs[0].len = sizeof(data_buf); + msgs[0].buf = data_buf; + msgs[1].addr = ROLLBALL_PHY_I2C_ADDR; + msgs[1].flags = 0; + msgs[1].len = sizeof(cmd_buf); + msgs[1].buf = cmd_buf; + + ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return -ENODEV; + + msgs[0].addr = ROLLBALL_PHY_I2C_ADDR; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = &cmd_addr; + msgs[1].addr = ROLLBALL_PHY_I2C_ADDR; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 1; + msgs[1].buf = &result; + + for (i = 0; i < 10; i++) { + msleep(20); + ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return -ENODEV; + if (result == ROLLBALL_CMD_DONE) + return 0; + } + + return -ENODEV; +} + static int i2c_mii_init_rollball(struct i2c_adapter *i2c) { struct i2c_msg msg; @@ -438,11 +482,11 @@ static int i2c_mii_init_rollball(struct i2c_adapter *i2c) ret = i2c_transfer(i2c, &msg, 1); if (ret < 0) - return ret; - else if (ret != 1) + return -ENODEV; + if (ret != 1) return -EIO; - else - return 0; + + return i2c_mii_probe_rollball(i2c); } static bool mdio_i2c_check_functionality(struct i2c_adapter *i2c, @@ -487,9 +531,10 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, case MDIO_I2C_ROLLBALL: ret = i2c_mii_init_rollball(i2c); if (ret < 0) { - dev_err(parent, - "Cannot initialize RollBall MDIO I2C protocol: %d\n", - ret); + if (ret != -ENODEV) + dev_err(parent, + "Cannot initialize RollBall MDIO I2C protocol: %d\n", + ret); mdiobus_free(mii); return ERR_PTR(ret); } diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 7a865f69a6bd..376c705a909d 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -579,6 +579,7 @@ static const struct sfp_quirk sfp_quirks[] = { // OEM SFP-GE-T is a 1000Base-T module with broken TX_FAULT indicator SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault), + SFP_QUIRK_F("OEM", "SFP-10G-T-I", sfp_fixup_rollball), SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), SFP_QUIRK_S("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), SFP_QUIRK_S("OEM", "SFP-2.5G-BX10-D", sfp_quirk_2500basex), @@ -2024,10 +2025,17 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) static int sfp_sm_add_mdio_bus(struct sfp *sfp) { - if (sfp->mdio_protocol != MDIO_I2C_NONE) - return sfp_i2c_mdiobus_create(sfp); + int ret; - return 0; + if (sfp->mdio_protocol == MDIO_I2C_NONE) + return 0; + + ret = sfp_i2c_mdiobus_create(sfp); + if (ret == -ENODEV) { + sfp->mdio_protocol = MDIO_I2C_NONE; + return 0; + } + return ret; } /* Probe a SFP for a PHY device if the module supports copper - the PHY