Associate with an SFP cage described in the device tree and provide the module_insert() callback that will set the appropriate DP83869 operation mode when an SFP module is inserted. Signed-off-by: Romain Gantois --- drivers/net/phy/dp83869.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/drivers/net/phy/dp83869.c b/drivers/net/phy/dp83869.c index 143b75842fc7..407518e6077f 100644 --- a/drivers/net/phy/dp83869.c +++ b/drivers/net/phy/dp83869.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -877,6 +878,57 @@ static int dp83869_config_init(struct phy_device *phydev) return ret; } +static void dp83869_module_remove(void *upstream) +{ + struct phy_device *phydev = upstream; + + phydev_info(phydev, "SFP module removed\n"); + + /* Set speed and duplex to unknown to avoid downshifting warning. */ + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; +} + +static int dp83869_module_insert(void *upstream, const struct sfp_eeprom_id *id) +{ + struct phy_device *phydev = upstream; + const struct sfp_module_caps *caps; + struct dp83869_private *dp83869; + int ret; + + caps = sfp_get_module_caps(phydev->sfp_bus); + + if (!linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + caps->link_modes)) { + phydev_err(phydev, "incompatible SFP module inserted\n"); + return -EINVAL; + } + + dp83869 = phydev->priv; + + dp83869->mode = DP83869_RGMII_1000_BASE; + phydev->port = PORT_FIBRE; + + ret = dp83869_configure_mode(phydev, dp83869); + if (ret) + return ret; + + /* Reconfigure advertisement */ + if (mutex_trylock(&phydev->lock)) { + ret = dp83869_config_aneg(phydev); + mutex_unlock(&phydev->lock); + } + + return ret; +} + +static const struct sfp_upstream_ops dp83869_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, + .module_insert = dp83869_module_insert, + .module_remove = dp83869_module_remove, +}; + static int dp83869_probe(struct phy_device *phydev) { struct dp83869_private *dp83869; @@ -893,6 +945,12 @@ static int dp83869_probe(struct phy_device *phydev) if (ret) return ret; + if (of_property_read_bool(phydev->mdio.dev.of_node, "sfp")) { + ret = phy_sfp_probe(phydev, &dp83869_sfp_ops); + if (ret) + return ret; + } + if (dp83869->mode == DP83869_RGMII_100_BASE || dp83869->mode == DP83869_RGMII_1000_BASE) phydev->port = PORT_FIBRE; -- 2.51.2