1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * System Control and Management Interface(SCMI) based hwmon sensor driver 4 * 5 * Copyright (C) 2018-2021 ARM Ltd. 6 * Sudeep Holla <sudeep.holla@arm.com> 7 */ 8 9 #include <linux/hwmon.h> 10 #include <linux/module.h> 11 #include <linux/scmi_protocol.h> 12 #include <linux/slab.h> 13 #include <linux/sysfs.h> 14 #include <linux/thermal.h> 15 16 static const struct scmi_sensor_proto_ops *sensor_ops; 17 18 struct scmi_sensors { 19 const struct scmi_protocol_handle *ph; 20 const struct scmi_sensor_info **info[hwmon_max]; 21 }; 22 23 struct scmi_thermal_sensor { 24 const struct scmi_protocol_handle *ph; 25 const struct scmi_sensor_info *info; 26 }; 27 28 static inline u64 __pow10(u8 x) 29 { 30 u64 r = 1; 31 32 while (x--) 33 r *= 10; 34 35 return r; 36 } 37 38 static int scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 *value) 39 { 40 int scale = sensor->scale; 41 u64 f; 42 43 switch (sensor->type) { 44 case TEMPERATURE_C: 45 case VOLTAGE: 46 case CURRENT: 47 scale += 3; 48 break; 49 case POWER: 50 case ENERGY: 51 scale += 6; 52 break; 53 default: 54 break; 55 } 56 57 if (scale == 0) 58 return 0; 59 60 if (abs(scale) > 19) 61 return -E2BIG; 62 63 f = __pow10(abs(scale)); 64 if (scale > 0) 65 *value *= f; 66 else 67 *value = div64_u64(*value, f); 68 69 return 0; 70 } 71 72 static int scmi_hwmon_read_scaled_value(const struct scmi_protocol_handle *ph, 73 const struct scmi_sensor_info *sensor, 74 long *val) 75 { 76 int ret; 77 u64 value; 78 79 ret = sensor_ops->reading_get(ph, sensor->id, &value); 80 if (ret) 81 return ret; 82 83 ret = scmi_hwmon_scale(sensor, &value); 84 if (!ret) 85 *val = value; 86 87 return ret; 88 } 89 90 static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 91 u32 attr, int channel, long *val) 92 { 93 const struct scmi_sensor_info *sensor; 94 struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev); 95 96 sensor = *(scmi_sensors->info[type] + channel); 97 98 return scmi_hwmon_read_scaled_value(scmi_sensors->ph, sensor, val); 99 } 100 101 static int 102 scmi_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type, 103 u32 attr, int channel, const char **str) 104 { 105 const struct scmi_sensor_info *sensor; 106 struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev); 107 108 sensor = *(scmi_sensors->info[type] + channel); 109 *str = sensor->name; 110 111 return 0; 112 } 113 114 static umode_t 115 scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, 116 u32 attr, int channel) 117 { 118 const struct scmi_sensor_info *sensor; 119 const struct scmi_sensors *scmi_sensors = drvdata; 120 121 sensor = *(scmi_sensors->info[type] + channel); 122 if (sensor) 123 return 0444; 124 125 return 0; 126 } 127 128 static const struct hwmon_ops scmi_hwmon_ops = { 129 .is_visible = scmi_hwmon_is_visible, 130 .read = scmi_hwmon_read, 131 .read_string = scmi_hwmon_read_string, 132 }; 133 134 static struct hwmon_chip_info scmi_chip_info = { 135 .ops = &scmi_hwmon_ops, 136 .info = NULL, 137 }; 138 139 static int scmi_hwmon_thermal_get_temp(struct thermal_zone_device *tz, 140 int *temp) 141 { 142 int ret; 143 long value; 144 struct scmi_thermal_sensor *th_sensor = thermal_zone_device_priv(tz); 145 146 ret = scmi_hwmon_read_scaled_value(th_sensor->ph, th_sensor->info, 147 &value); 148 if (!ret) 149 *temp = value; 150 151 return ret; 152 } 153 154 static const struct thermal_zone_device_ops scmi_hwmon_thermal_ops = { 155 .get_temp = scmi_hwmon_thermal_get_temp, 156 }; 157 158 static int scmi_hwmon_add_chan_info(struct hwmon_channel_info *scmi_hwmon_chan, 159 struct device *dev, int num, 160 enum hwmon_sensor_types type, u32 config) 161 { 162 int i; 163 u32 *cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL); 164 165 if (!cfg) 166 return -ENOMEM; 167 168 scmi_hwmon_chan->type = type; 169 scmi_hwmon_chan->config = cfg; 170 for (i = 0; i < num; i++, cfg++) 171 *cfg = config; 172 173 return 0; 174 } 175 176 static enum hwmon_sensor_types scmi_types[] = { 177 [TEMPERATURE_C] = hwmon_temp, 178 [VOLTAGE] = hwmon_in, 179 [CURRENT] = hwmon_curr, 180 [POWER] = hwmon_power, 181 [ENERGY] = hwmon_energy, 182 }; 183 184 static u32 hwmon_attributes[hwmon_max] = { 185 [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL, 186 [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL, 187 [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL, 188 [hwmon_power] = HWMON_P_INPUT | HWMON_P_LABEL, 189 [hwmon_energy] = HWMON_E_INPUT | HWMON_E_LABEL, 190 }; 191 192 static int scmi_thermal_sensor_register(struct device *dev, 193 const struct scmi_protocol_handle *ph, 194 const struct scmi_sensor_info *sensor) 195 { 196 struct scmi_thermal_sensor *th_sensor; 197 struct thermal_zone_device *tzd; 198 199 th_sensor = devm_kzalloc(dev, sizeof(*th_sensor), GFP_KERNEL); 200 if (!th_sensor) 201 return -ENOMEM; 202 203 th_sensor->ph = ph; 204 th_sensor->info = sensor; 205 206 /* 207 * Try to register a temperature sensor with the Thermal Framework: 208 * skip sensors not defined as part of any thermal zone (-ENODEV) but 209 * report any other errors related to misconfigured zones/sensors. 210 */ 211 tzd = devm_thermal_of_zone_register(dev, th_sensor->info->id, th_sensor, 212 &scmi_hwmon_thermal_ops); 213 if (IS_ERR(tzd)) { 214 devm_kfree(dev, th_sensor); 215 216 if (PTR_ERR(tzd) != -ENODEV) 217 return PTR_ERR(tzd); 218 219 dev_dbg(dev, "Sensor '%s' not attached to any thermal zone.\n", 220 sensor->name); 221 } else { 222 dev_dbg(dev, "Sensor '%s' attached to thermal zone ID:%d\n", 223 sensor->name, thermal_zone_device_id(tzd)); 224 } 225 226 return 0; 227 } 228 229 static int scmi_hwmon_probe(struct scmi_device *sdev) 230 { 231 int i, idx; 232 u16 nr_sensors; 233 enum hwmon_sensor_types type; 234 struct scmi_sensors *scmi_sensors; 235 const struct scmi_sensor_info *sensor; 236 int nr_count[hwmon_max] = {0}, nr_types = 0, nr_count_temp = 0; 237 const struct hwmon_chip_info *chip_info; 238 struct device *hwdev, *dev = &sdev->dev; 239 struct hwmon_channel_info *scmi_hwmon_chan; 240 const struct hwmon_channel_info **ptr_scmi_ci; 241 const struct scmi_handle *handle = sdev->handle; 242 struct scmi_protocol_handle *ph; 243 244 if (!handle) 245 return -ENODEV; 246 247 sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph); 248 if (IS_ERR(sensor_ops)) 249 return PTR_ERR(sensor_ops); 250 251 nr_sensors = sensor_ops->count_get(ph); 252 if (!nr_sensors) 253 return -EIO; 254 255 scmi_sensors = devm_kzalloc(dev, sizeof(*scmi_sensors), GFP_KERNEL); 256 if (!scmi_sensors) 257 return -ENOMEM; 258 259 scmi_sensors->ph = ph; 260 261 for (i = 0; i < nr_sensors; i++) { 262 sensor = sensor_ops->info_get(ph, i); 263 if (!sensor) 264 return -EINVAL; 265 266 switch (sensor->type) { 267 case TEMPERATURE_C: 268 case VOLTAGE: 269 case CURRENT: 270 case POWER: 271 case ENERGY: 272 type = scmi_types[sensor->type]; 273 if (!nr_count[type]) 274 nr_types++; 275 nr_count[type]++; 276 break; 277 } 278 } 279 280 if (nr_count[hwmon_temp]) 281 nr_count_temp = nr_count[hwmon_temp]; 282 283 scmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*scmi_hwmon_chan), 284 GFP_KERNEL); 285 if (!scmi_hwmon_chan) 286 return -ENOMEM; 287 288 ptr_scmi_ci = devm_kcalloc(dev, nr_types + 1, sizeof(*ptr_scmi_ci), 289 GFP_KERNEL); 290 if (!ptr_scmi_ci) 291 return -ENOMEM; 292 293 scmi_chip_info.info = ptr_scmi_ci; 294 chip_info = &scmi_chip_info; 295 296 for (type = 0; type < hwmon_max; type++) { 297 if (!nr_count[type]) 298 continue; 299 300 scmi_hwmon_add_chan_info(scmi_hwmon_chan, dev, nr_count[type], 301 type, hwmon_attributes[type]); 302 *ptr_scmi_ci++ = scmi_hwmon_chan++; 303 304 scmi_sensors->info[type] = 305 devm_kcalloc(dev, nr_count[type], 306 sizeof(*scmi_sensors->info), GFP_KERNEL); 307 if (!scmi_sensors->info[type]) 308 return -ENOMEM; 309 } 310 311 for (i = nr_sensors - 1; i >= 0 ; i--) { 312 sensor = sensor_ops->info_get(ph, i); 313 if (!sensor) 314 continue; 315 316 switch (sensor->type) { 317 case TEMPERATURE_C: 318 case VOLTAGE: 319 case CURRENT: 320 case POWER: 321 case ENERGY: 322 type = scmi_types[sensor->type]; 323 idx = --nr_count[type]; 324 *(scmi_sensors->info[type] + idx) = sensor; 325 break; 326 } 327 } 328 329 hwdev = devm_hwmon_device_register_with_info(dev, "scmi_sensors", 330 scmi_sensors, chip_info, 331 NULL); 332 if (IS_ERR(hwdev)) 333 return PTR_ERR(hwdev); 334 335 for (i = 0; i < nr_count_temp; i++) { 336 int ret; 337 338 sensor = *(scmi_sensors->info[hwmon_temp] + i); 339 if (!sensor) 340 continue; 341 342 /* 343 * Warn on any misconfiguration related to thermal zones but 344 * bail out of probing only on memory errors. 345 */ 346 ret = scmi_thermal_sensor_register(dev, ph, sensor); 347 if (ret) { 348 if (ret == -ENOMEM) 349 return ret; 350 dev_warn(dev, 351 "Thermal zone misconfigured for %s. err=%d\n", 352 sensor->name, ret); 353 } 354 } 355 356 return 0; 357 } 358 359 static const struct scmi_device_id scmi_id_table[] = { 360 { SCMI_PROTOCOL_SENSOR, "hwmon" }, 361 { }, 362 }; 363 MODULE_DEVICE_TABLE(scmi, scmi_id_table); 364 365 static struct scmi_driver scmi_hwmon_drv = { 366 .name = "scmi-hwmon", 367 .probe = scmi_hwmon_probe, 368 .id_table = scmi_id_table, 369 }; 370 module_scmi_driver(scmi_hwmon_drv); 371 372 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); 373 MODULE_DESCRIPTION("ARM SCMI HWMON interface driver"); 374 MODULE_LICENSE("GPL v2"); 375