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 u32 sensor_config = FIELD_PREP(SCMI_SENS_CFG_SENSOR_ENABLED_MASK, 244 SCMI_SENS_CFG_SENSOR_ENABLE); 245 246 if (!handle) 247 return -ENODEV; 248 249 sensor_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_SENSOR, &ph); 250 if (IS_ERR(sensor_ops)) 251 return PTR_ERR(sensor_ops); 252 253 nr_sensors = sensor_ops->count_get(ph); 254 if (!nr_sensors) 255 return -EIO; 256 257 scmi_sensors = devm_kzalloc(dev, sizeof(*scmi_sensors), GFP_KERNEL); 258 if (!scmi_sensors) 259 return -ENOMEM; 260 261 scmi_sensors->ph = ph; 262 263 for (i = 0; i < nr_sensors; i++) { 264 sensor = sensor_ops->info_get(ph, i); 265 if (!sensor) 266 return -EINVAL; 267 268 switch (sensor->type) { 269 case TEMPERATURE_C: 270 case VOLTAGE: 271 case CURRENT: 272 case POWER: 273 case ENERGY: 274 type = scmi_types[sensor->type]; 275 if (!nr_count[type]) 276 nr_types++; 277 nr_count[type]++; 278 break; 279 } 280 } 281 282 if (nr_count[hwmon_temp]) 283 nr_count_temp = nr_count[hwmon_temp]; 284 285 scmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*scmi_hwmon_chan), 286 GFP_KERNEL); 287 if (!scmi_hwmon_chan) 288 return -ENOMEM; 289 290 ptr_scmi_ci = devm_kcalloc(dev, nr_types + 1, sizeof(*ptr_scmi_ci), 291 GFP_KERNEL); 292 if (!ptr_scmi_ci) 293 return -ENOMEM; 294 295 scmi_chip_info.info = ptr_scmi_ci; 296 chip_info = &scmi_chip_info; 297 298 for (type = 0; type < hwmon_max; type++) { 299 if (!nr_count[type]) 300 continue; 301 302 scmi_hwmon_add_chan_info(scmi_hwmon_chan, dev, nr_count[type], 303 type, hwmon_attributes[type]); 304 *ptr_scmi_ci++ = scmi_hwmon_chan++; 305 306 scmi_sensors->info[type] = 307 devm_kcalloc(dev, nr_count[type], 308 sizeof(*scmi_sensors->info), GFP_KERNEL); 309 if (!scmi_sensors->info[type]) 310 return -ENOMEM; 311 } 312 313 for (i = nr_sensors - 1; i >= 0 ; i--) { 314 sensor = sensor_ops->info_get(ph, i); 315 if (!sensor) 316 continue; 317 318 switch (sensor->type) { 319 case TEMPERATURE_C: 320 case VOLTAGE: 321 case CURRENT: 322 case POWER: 323 case ENERGY: 324 type = scmi_types[sensor->type]; 325 idx = --nr_count[type]; 326 *(scmi_sensors->info[type] + idx) = sensor; 327 break; 328 } 329 } 330 331 hwdev = devm_hwmon_device_register_with_info(dev, "scmi_sensors", 332 scmi_sensors, chip_info, 333 NULL); 334 if (IS_ERR(hwdev)) 335 return PTR_ERR(hwdev); 336 337 for (i = 0; i < nr_count_temp; i++) { 338 int ret; 339 340 sensor = *(scmi_sensors->info[hwmon_temp] + i); 341 if (!sensor) 342 continue; 343 344 ret = sensor_ops->config_set(ph, i, sensor_config); 345 if (ret) { 346 dev_err(dev, "Error enabling sensor %s. err=%d\n", 347 sensor->name, ret); 348 continue; 349 } 350 351 /* 352 * Warn on any misconfiguration related to thermal zones but 353 * bail out of probing only on memory errors. 354 */ 355 ret = scmi_thermal_sensor_register(dev, ph, sensor); 356 if (ret) { 357 if (ret == -ENOMEM) 358 return ret; 359 dev_warn(dev, 360 "Thermal zone misconfigured for %s. err=%d\n", 361 sensor->name, ret); 362 } 363 } 364 365 return 0; 366 } 367 368 static const struct scmi_device_id scmi_id_table[] = { 369 { SCMI_PROTOCOL_SENSOR, "hwmon" }, 370 { }, 371 }; 372 MODULE_DEVICE_TABLE(scmi, scmi_id_table); 373 374 static struct scmi_driver scmi_hwmon_drv = { 375 .name = "scmi-hwmon", 376 .probe = scmi_hwmon_probe, 377 .id_table = scmi_id_table, 378 }; 379 module_scmi_driver(scmi_hwmon_drv); 380 381 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); 382 MODULE_DESCRIPTION("ARM SCMI HWMON interface driver"); 383 MODULE_LICENSE("GPL v2"); 384