Skip to content

Commit 4a5aa55

Browse files
dangowrtfrank-w
authored andcommitted
net: phy: mxl-gpy: add PHY support for MaxLinear switches
Add support for the built-in 2500M/1000M/100M/10M copper PHYs found in MaxLinear MXL862xx switches which are mostly identical with the GPY211 family of PHYs. Most notable differences are the internal MAC-side interface as well as the different encoding of the PHY temperature. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
1 parent d3d086e commit 4a5aa55

1 file changed

Lines changed: 67 additions & 3 deletions

File tree

drivers/net/phy/mxl-gpy.c

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
/* PHY ID */
1919
#define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
2020
#define PHY_ID_GPY21xB_MASK 0xFFFFFFF9
21+
#define PHY_ID_MXL862XX_MASK 0xFFFFFF00
2122
#define PHY_ID_GPY2xx 0x67C9DC00
2223
#define PHY_ID_GPY115B 0x67C9DF00
2324
#define PHY_ID_GPY115C 0x67C9DF10
@@ -30,6 +31,7 @@
3031
#define PHY_ID_GPY241B 0x67C9DE40
3132
#define PHY_ID_GPY241BM 0x67C9DE80
3233
#define PHY_ID_GPY245B 0x67C9DEC0
34+
#define PHY_ID_MXL862XX 0xC1335500
3335

3436
#define PHY_CTL1 0x13
3537
#define PHY_CTL1_MDICD BIT(3)
@@ -199,6 +201,29 @@ static int gpy_hwmon_read(struct device *dev,
199201
return 0;
200202
}
201203

204+
static int mxl862xx_hwmon_read(struct device *dev,
205+
enum hwmon_sensor_types type,
206+
u32 attr, int channel, long *value)
207+
{
208+
struct phy_device *phydev = dev_get_drvdata(dev);
209+
long tmp;
210+
int ret;
211+
212+
ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_TEMP_STA);
213+
if (ret < 0)
214+
return ret;
215+
if (!ret)
216+
return -ENODATA;
217+
218+
tmp = (s16)ret;
219+
tmp *= 78125;
220+
tmp /= 10000;
221+
222+
*value = tmp;
223+
224+
return 0;
225+
}
226+
202227
static umode_t gpy_hwmon_is_visible(const void *data,
203228
enum hwmon_sensor_types type,
204229
u32 attr, int channel)
@@ -216,18 +241,33 @@ static const struct hwmon_ops gpy_hwmon_hwmon_ops = {
216241
.read = gpy_hwmon_read,
217242
};
218243

244+
static const struct hwmon_ops mxl862xx_hwmon_hwmon_ops = {
245+
.is_visible = gpy_hwmon_is_visible,
246+
.read = mxl862xx_hwmon_read,
247+
};
248+
219249
static const struct hwmon_chip_info gpy_hwmon_chip_info = {
220250
.ops = &gpy_hwmon_hwmon_ops,
221251
.info = gpy_hwmon_info,
222252
};
223253

254+
static const struct hwmon_chip_info mxl862xx_hwmon_chip_info = {
255+
.ops = &mxl862xx_hwmon_hwmon_ops,
256+
.info = gpy_hwmon_info,
257+
};
258+
224259
static int gpy_hwmon_register(struct phy_device *phydev)
225260
{
226261
struct device *dev = &phydev->mdio.dev;
262+
const struct hwmon_chip_info *info;
227263
struct device *hwmon_dev;
228264

229-
hwmon_dev = devm_hwmon_device_register_with_info(dev, NULL, phydev,
230-
&gpy_hwmon_chip_info,
265+
if ((phydev->phy_id & PHY_ID_MXL862XX_MASK) == PHY_ID_MXL862XX)
266+
info = &mxl862xx_hwmon_chip_info;
267+
else
268+
info = &gpy_hwmon_chip_info;
269+
270+
hwmon_dev = devm_hwmon_device_register_with_info(dev, NULL, phydev, info,
231271
NULL);
232272

233273
return PTR_ERR_OR_ZERO(hwmon_dev);
@@ -540,7 +580,7 @@ static int gpy_update_interface(struct phy_device *phydev)
540580
/* Interface mode is fixed for USXGMII and integrated PHY */
541581
if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
542582
phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
543-
return -EINVAL;
583+
return 0;
544584

545585
/* Automatically switch SERDES interface between SGMII and 2500-BaseX
546586
* according to speed. Disable ANEG in 2500-BaseX mode.
@@ -1268,6 +1308,29 @@ static struct phy_driver gpy_drivers[] = {
12681308
.get_wol = gpy_get_wol,
12691309
.set_loopback = gpy_loopback,
12701310
},
1311+
{
1312+
.phy_id = PHY_ID_MXL862XX,
1313+
.phy_id_mask = PHY_ID_MXL862XX_MASK,
1314+
.name = "MaxLinear Ethernet MxL862XX",
1315+
.get_features = genphy_c45_pma_read_abilities,
1316+
.config_init = gpy_config_init,
1317+
.probe = gpy_probe,
1318+
.suspend = genphy_suspend,
1319+
.resume = genphy_resume,
1320+
.config_aneg = gpy_config_aneg,
1321+
.aneg_done = genphy_c45_aneg_done,
1322+
.read_status = gpy_read_status,
1323+
.config_intr = gpy_config_intr,
1324+
.handle_interrupt = gpy_handle_interrupt,
1325+
.set_wol = gpy_set_wol,
1326+
.get_wol = gpy_get_wol,
1327+
.set_loopback = gpy_loopback,
1328+
.led_brightness_set = gpy_led_brightness_set,
1329+
.led_hw_is_supported = gpy_led_hw_is_supported,
1330+
.led_hw_control_get = gpy_led_hw_control_get,
1331+
.led_hw_control_set = gpy_led_hw_control_set,
1332+
.led_polarity_set = gpy_led_polarity_set,
1333+
},
12711334
};
12721335
module_phy_driver(gpy_drivers);
12731336

@@ -1284,6 +1347,7 @@ static const struct mdio_device_id __maybe_unused gpy_tbl[] = {
12841347
{PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)},
12851348
{PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)},
12861349
{PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)},
1350+
{PHY_ID_MXL862XX, PHY_ID_MXL862XX_MASK},
12871351
{ }
12881352
};
12891353
MODULE_DEVICE_TABLE(mdio, gpy_tbl);

0 commit comments

Comments
 (0)