// SPDX-License-Identifier: GPL-2.0+ /* * HWMON support for Realtek PHY's * * Author: Heiner Kallweit */ #include #include #include "realtek.h" #define RTL822X_VND2_TSALRM 0xa662 #define RTL822X_VND2_TSRR 0xbd84 #define RTL822X_VND2_TSSR 0xb54c static int rtl822x_hwmon_get_temp(int raw) { if (raw >= 512) raw -= 1024; return 1000 * raw / 2; } static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { struct phy_device *phydev = dev_get_drvdata(dev); int raw; switch (attr) { case hwmon_temp_input: raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; *val = rtl822x_hwmon_get_temp(raw); break; case hwmon_temp_max: /* Chip reduces speed to 1G if threshold is exceeded */ raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; *val = rtl822x_hwmon_get_temp(raw); break; default: return -EINVAL; } return 0; } static const struct hwmon_ops rtl822x_hwmon_ops = { .visible = 0444, .read = rtl822x_hwmon_read, }; static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX), NULL }; static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { .ops = &rtl822x_hwmon_ops, .info = rtl822x_hwmon_info, }; int rtl822x_hwmon_init(struct phy_device *phydev) { struct device *hwdev, *dev = &phydev->mdio.dev; const char *name; /* Ensure over-temp alarm is reset. */ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); name = devm_hwmon_sanitize_name(dev, dev_name(dev)); if (IS_ERR(name)) return PTR_ERR(name); hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, &rtl822x_hwmon_chip_info, NULL); return PTR_ERR_OR_ZERO(hwdev); }