1 // SPDX-License-Identifier: GPL-2.0 2 /* HWMON driver for Aquantia PHY 3 * 4 * Author: Nikita Yushchenko <nikita.yoush@cogentembedded.com> 5 * Author: Andrew Lunn <andrew@lunn.ch> 6 * Author: Heiner Kallweit <hkallweit1@gmail.com> 7 */ 8 9 #include <linux/phy.h> 10 #include <linux/device.h> 11 #include <linux/ctype.h> 12 #include <linux/hwmon.h> 13 14 #include "aquantia.h" 15 16 #if IS_REACHABLE(CONFIG_HWMON) 17 18 static umode_t aqr_hwmon_is_visible(const void *data, 19 enum hwmon_sensor_types type, 20 u32 attr, int channel) 21 { 22 if (type != hwmon_temp) 23 return 0; 24 25 switch (attr) { 26 case hwmon_temp_input: 27 case hwmon_temp_min_alarm: 28 case hwmon_temp_max_alarm: 29 case hwmon_temp_lcrit_alarm: 30 case hwmon_temp_crit_alarm: 31 return 0444; 32 case hwmon_temp_min: 33 case hwmon_temp_max: 34 case hwmon_temp_lcrit: 35 case hwmon_temp_crit: 36 return 0644; 37 default: 38 return 0; 39 } 40 } 41 42 static int aqr_hwmon_get(struct phy_device *phydev, int reg, long *value) 43 { 44 int temp = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg); 45 46 if (temp < 0) 47 return temp; 48 49 /* 16 bit value is 2's complement with LSB = 1/256th degree Celsius */ 50 *value = (s16)temp * 1000 / 256; 51 52 return 0; 53 } 54 55 static int aqr_hwmon_set(struct phy_device *phydev, int reg, long value) 56 { 57 int temp; 58 59 if (value >= 128000 || value < -128000) 60 return -ERANGE; 61 62 temp = value * 256 / 1000; 63 64 /* temp is in s16 range and we're interested in lower 16 bits only */ 65 return phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, (u16)temp); 66 } 67 68 static int aqr_hwmon_test_bit(struct phy_device *phydev, int reg, int bit) 69 { 70 int val = phy_read_mmd(phydev, MDIO_MMD_VEND1, reg); 71 72 if (val < 0) 73 return val; 74 75 return !!(val & bit); 76 } 77 78 static int aqr_hwmon_status1(struct phy_device *phydev, int bit, long *value) 79 { 80 int val = aqr_hwmon_test_bit(phydev, VEND1_GENERAL_STAT1, bit); 81 82 if (val < 0) 83 return val; 84 85 *value = val; 86 87 return 0; 88 } 89 90 static int aqr_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 91 u32 attr, int channel, long *value) 92 { 93 struct phy_device *phydev = dev_get_drvdata(dev); 94 int reg; 95 96 if (type != hwmon_temp) 97 return -EOPNOTSUPP; 98 99 switch (attr) { 100 case hwmon_temp_input: 101 reg = aqr_hwmon_test_bit(phydev, VEND1_THERMAL_STAT2, 102 VEND1_THERMAL_STAT2_VALID); 103 if (reg < 0) 104 return reg; 105 if (!reg) 106 return -EBUSY; 107 108 return aqr_hwmon_get(phydev, VEND1_THERMAL_STAT1, value); 109 110 case hwmon_temp_lcrit: 111 return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL, 112 value); 113 case hwmon_temp_min: 114 return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN, 115 value); 116 case hwmon_temp_max: 117 return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN, 118 value); 119 case hwmon_temp_crit: 120 return aqr_hwmon_get(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL, 121 value); 122 case hwmon_temp_lcrit_alarm: 123 return aqr_hwmon_status1(phydev, 124 VEND1_GENERAL_STAT1_LOW_TEMP_FAIL, 125 value); 126 case hwmon_temp_min_alarm: 127 return aqr_hwmon_status1(phydev, 128 VEND1_GENERAL_STAT1_LOW_TEMP_WARN, 129 value); 130 case hwmon_temp_max_alarm: 131 return aqr_hwmon_status1(phydev, 132 VEND1_GENERAL_STAT1_HIGH_TEMP_WARN, 133 value); 134 case hwmon_temp_crit_alarm: 135 return aqr_hwmon_status1(phydev, 136 VEND1_GENERAL_STAT1_HIGH_TEMP_FAIL, 137 value); 138 default: 139 return -EOPNOTSUPP; 140 } 141 } 142 143 static int aqr_hwmon_write(struct device *dev, enum hwmon_sensor_types type, 144 u32 attr, int channel, long value) 145 { 146 struct phy_device *phydev = dev_get_drvdata(dev); 147 148 if (type != hwmon_temp) 149 return -EOPNOTSUPP; 150 151 switch (attr) { 152 case hwmon_temp_lcrit: 153 return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_FAIL, 154 value); 155 case hwmon_temp_min: 156 return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_LOW_TEMP_WARN, 157 value); 158 case hwmon_temp_max: 159 return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_WARN, 160 value); 161 case hwmon_temp_crit: 162 return aqr_hwmon_set(phydev, VEND1_THERMAL_PROV_HIGH_TEMP_FAIL, 163 value); 164 default: 165 return -EOPNOTSUPP; 166 } 167 } 168 169 static const struct hwmon_ops aqr_hwmon_ops = { 170 .is_visible = aqr_hwmon_is_visible, 171 .read = aqr_hwmon_read, 172 .write = aqr_hwmon_write, 173 }; 174 175 static u32 aqr_hwmon_chip_config[] = { 176 HWMON_C_REGISTER_TZ, 177 0, 178 }; 179 180 static const struct hwmon_channel_info aqr_hwmon_chip = { 181 .type = hwmon_chip, 182 .config = aqr_hwmon_chip_config, 183 }; 184 185 static u32 aqr_hwmon_temp_config[] = { 186 HWMON_T_INPUT | 187 HWMON_T_MAX | HWMON_T_MIN | 188 HWMON_T_MAX_ALARM | HWMON_T_MIN_ALARM | 189 HWMON_T_CRIT | HWMON_T_LCRIT | 190 HWMON_T_CRIT_ALARM | HWMON_T_LCRIT_ALARM, 191 0, 192 }; 193 194 static const struct hwmon_channel_info aqr_hwmon_temp = { 195 .type = hwmon_temp, 196 .config = aqr_hwmon_temp_config, 197 }; 198 199 static const struct hwmon_channel_info * const aqr_hwmon_info[] = { 200 &aqr_hwmon_chip, 201 &aqr_hwmon_temp, 202 NULL, 203 }; 204 205 static const struct hwmon_chip_info aqr_hwmon_chip_info = { 206 .ops = &aqr_hwmon_ops, 207 .info = aqr_hwmon_info, 208 }; 209 210 int aqr_hwmon_probe(struct phy_device *phydev) 211 { 212 struct device *dev = &phydev->mdio.dev; 213 struct device *hwmon_dev; 214 char *hwmon_name; 215 int i, j; 216 217 hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL); 218 if (!hwmon_name) 219 return -ENOMEM; 220 221 for (i = j = 0; hwmon_name[i]; i++) { 222 if (isalnum(hwmon_name[i])) { 223 if (i != j) 224 hwmon_name[j] = hwmon_name[i]; 225 j++; 226 } 227 } 228 hwmon_name[j] = '\0'; 229 230 hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name, 231 phydev, &aqr_hwmon_chip_info, NULL); 232 233 return PTR_ERR_OR_ZERO(hwmon_dev); 234 } 235 236 #endif 237