From: Chad Monroe MXL86211C is a smaller and more efficient version of the GPY211C. Add the PHY ID and phy_driver instance to the mxl-gpy driver. Signed-off-by: Chad Monroe Signed-off-by: Daniel Golle --- drivers/net/phy/mxl-gpy.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index 0c8dc16ee7bde..3320a42ef43cf 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -30,6 +30,7 @@ #define PHY_ID_GPY241B 0x67C9DE40 #define PHY_ID_GPY241BM 0x67C9DE80 #define PHY_ID_GPY245B 0x67C9DEC0 +#define PHY_ID_MXL86211C 0xC1335400 #define PHY_CTL1 0x13 #define PHY_CTL1_MDICD BIT(3) @@ -1268,6 +1269,29 @@ static struct phy_driver gpy_drivers[] = { .get_wol = gpy_get_wol, .set_loopback = gpy_loopback, }, + { + PHY_ID_MATCH_MODEL(PHY_ID_MXL86211C), + .name = "Maxlinear Ethernet MXL86211C", + .get_features = genphy_c45_pma_read_abilities, + .config_init = gpy_config_init, + .probe = gpy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .config_aneg = gpy_config_aneg, + .aneg_done = genphy_c45_aneg_done, + .read_status = gpy_read_status, + .config_intr = gpy_config_intr, + .handle_interrupt = gpy_handle_interrupt, + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, + .link_change_notify = gpy_link_change_notify, + }, }; module_phy_driver(gpy_drivers); -- 2.51.2 Add PHY driver support for Maxlinear 86252 and 86282 switches. The PHYs built-into those switches are just like any other GPY 2.5G PHYs with the exception of the temperature sensor data being encoded in a different way. Signed-off-by: Daniel Golle --- drivers/net/phy/mxl-gpy.c | 70 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c index 3320a42ef43cf..d14520f66a1d5 100644 --- a/drivers/net/phy/mxl-gpy.c +++ b/drivers/net/phy/mxl-gpy.c @@ -18,6 +18,7 @@ /* PHY ID */ #define PHY_ID_GPYx15B_MASK 0xFFFFFFFC #define PHY_ID_GPY21xB_MASK 0xFFFFFFF9 +#define PHY_ID_MXL862XX_MASK 0xFFFFFF00 #define PHY_ID_GPY2xx 0x67C9DC00 #define PHY_ID_GPY115B 0x67C9DF00 #define PHY_ID_GPY115C 0x67C9DF10 @@ -31,6 +32,7 @@ #define PHY_ID_GPY241BM 0x67C9DE80 #define PHY_ID_GPY245B 0x67C9DEC0 #define PHY_ID_MXL86211C 0xC1335400 +#define PHY_ID_MXL862XX 0xC1335500 #define PHY_CTL1 0x13 #define PHY_CTL1_MDICD BIT(3) @@ -200,6 +202,29 @@ static int gpy_hwmon_read(struct device *dev, return 0; } +static int mxl862xx_hwmon_read(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, long *value) +{ + struct phy_device *phydev = dev_get_drvdata(dev); + long tmp; + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_TEMP_STA); + if (ret < 0) + return ret; + if (!ret) + return -ENODATA; + + tmp = (s16)ret; + tmp *= 78125; + tmp /= 10000; + + *value = tmp; + + return 0; +} + static umode_t gpy_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -217,19 +242,34 @@ static const struct hwmon_ops gpy_hwmon_hwmon_ops = { .read = gpy_hwmon_read, }; +static const struct hwmon_ops mxl862xx_hwmon_hwmon_ops = { + .is_visible = gpy_hwmon_is_visible, + .read = mxl862xx_hwmon_read, +}; + static const struct hwmon_chip_info gpy_hwmon_chip_info = { .ops = &gpy_hwmon_hwmon_ops, .info = gpy_hwmon_info, }; +static const struct hwmon_chip_info mxl862xx_hwmon_chip_info = { + .ops = &mxl862xx_hwmon_hwmon_ops, + .info = gpy_hwmon_info, +}; + static int gpy_hwmon_register(struct phy_device *phydev) { struct device *dev = &phydev->mdio.dev; + const struct hwmon_chip_info *info; struct device *hwmon_dev; + if ((phydev->phy_id & PHY_ID_MXL862XX_MASK) == PHY_ID_MXL862XX) + info = &mxl862xx_hwmon_chip_info; + else + info = &gpy_hwmon_chip_info; + hwmon_dev = devm_hwmon_device_register_with_info(dev, NULL, phydev, - &gpy_hwmon_chip_info, - NULL); + info, NULL); return PTR_ERR_OR_ZERO(hwmon_dev); } @@ -541,7 +581,7 @@ static int gpy_update_interface(struct phy_device *phydev) /* Interface mode is fixed for USXGMII and integrated PHY */ if (phydev->interface == PHY_INTERFACE_MODE_USXGMII || phydev->interface == PHY_INTERFACE_MODE_INTERNAL) - return -EINVAL; + return 0; /* Automatically switch SERDES interface between SGMII and 2500-BaseX * according to speed. Disable ANEG in 2500-BaseX mode. @@ -1292,6 +1332,29 @@ static struct phy_driver gpy_drivers[] = { .led_polarity_set = gpy_led_polarity_set, .link_change_notify = gpy_link_change_notify, }, + { + .phy_id = PHY_ID_MXL862XX, + .phy_id_mask = PHY_ID_MXL862XX_MASK, + .name = "MaxLinear Ethernet MxL862XX", + .get_features = genphy_c45_pma_read_abilities, + .config_init = gpy_config_init, + .probe = gpy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .config_aneg = gpy_config_aneg, + .aneg_done = genphy_c45_aneg_done, + .read_status = gpy_read_status, + .config_intr = gpy_config_intr, + .handle_interrupt = gpy_handle_interrupt, + .set_wol = gpy_set_wol, + .get_wol = gpy_get_wol, + .set_loopback = gpy_loopback, + .led_brightness_set = gpy_led_brightness_set, + .led_hw_is_supported = gpy_led_hw_is_supported, + .led_hw_control_get = gpy_led_hw_control_get, + .led_hw_control_set = gpy_led_hw_control_set, + .led_polarity_set = gpy_led_polarity_set, + }, }; module_phy_driver(gpy_drivers); @@ -1308,6 +1371,7 @@ static const struct mdio_device_id __maybe_unused gpy_tbl[] = { {PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)}, {PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)}, {PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)}, + {PHY_ID_MXL862XX, PHY_ID_MXL862XX_MASK}, { } }; MODULE_DEVICE_TABLE(mdio, gpy_tbl); -- 2.51.2