1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * HWMON support for Realtek PHY's 4 * 5 * Author: Heiner Kallweit <hkallweit1@gmail.com> 6 */ 7 8 #include <linux/hwmon.h> 9 #include <linux/phy.h> 10 11 #include "realtek.h" 12 13 #define RTL822X_VND2_TSALRM 0xa662 14 #define RTL822X_VND2_TSRR 0xbd84 15 #define RTL822X_VND2_TSSR 0xb54c 16 17 static int rtl822x_hwmon_get_temp(int raw) 18 { 19 if (raw >= 512) 20 raw -= 1024; 21 22 return 1000 * raw / 2; 23 } 24 25 static int rtl822x_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 26 u32 attr, int channel, long *val) 27 { 28 struct phy_device *phydev = dev_get_drvdata(dev); 29 int raw; 30 31 switch (attr) { 32 case hwmon_temp_input: 33 raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSRR) & 0x3ff; 34 *val = rtl822x_hwmon_get_temp(raw); 35 break; 36 case hwmon_temp_max: 37 /* Chip reduces speed to 1G if threshold is exceeded */ 38 raw = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSSR) >> 6; 39 *val = rtl822x_hwmon_get_temp(raw); 40 break; 41 default: 42 return -EINVAL; 43 } 44 45 return 0; 46 } 47 48 static const struct hwmon_ops rtl822x_hwmon_ops = { 49 .visible = 0444, 50 .read = rtl822x_hwmon_read, 51 }; 52 53 static const struct hwmon_channel_info * const rtl822x_hwmon_info[] = { 54 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX), 55 NULL 56 }; 57 58 static const struct hwmon_chip_info rtl822x_hwmon_chip_info = { 59 .ops = &rtl822x_hwmon_ops, 60 .info = rtl822x_hwmon_info, 61 }; 62 63 int rtl822x_hwmon_init(struct phy_device *phydev) 64 { 65 struct device *hwdev, *dev = &phydev->mdio.dev; 66 const char *name; 67 68 /* Ensure over-temp alarm is reset. */ 69 phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, RTL822X_VND2_TSALRM, 3); 70 71 name = devm_hwmon_sanitize_name(dev, dev_name(dev)); 72 if (IS_ERR(name)) 73 return PTR_ERR(name); 74 75 hwdev = devm_hwmon_device_register_with_info(dev, name, phydev, 76 &rtl822x_hwmon_chip_info, 77 NULL); 78 return PTR_ERR_OR_ZERO(hwdev); 79 } 80