1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * HWMON driver for ASUS motherboards that provides sensor readouts via WMI 4 * interface present in the UEFI of the X370/X470/B450/X399 Ryzen motherboards. 5 * 6 * Copyright (C) 2018-2019 Ed Brindley <kernel@maidavale.org> 7 * 8 * WMI interface provides: 9 * - CPU Core Voltage, 10 * - CPU SOC Voltage, 11 * - DRAM Voltage, 12 * - VDDP Voltage, 13 * - 1.8V PLL Voltage, 14 * - +12V Voltage, 15 * - +5V Voltage, 16 * - 3VSB Voltage, 17 * - VBAT Voltage, 18 * - AVCC3 Voltage, 19 * - SB 1.05V Voltage, 20 * - CPU Core Voltage, 21 * - CPU SOC Voltage, 22 * - DRAM Voltage, 23 * - CPU Fan RPM, 24 * - Chassis Fan 1 RPM, 25 * - Chassis Fan 2 RPM, 26 * - Chassis Fan 3 RPM, 27 * - HAMP Fan RPM, 28 * - Water Pump RPM, 29 * - CPU OPT RPM, 30 * - Water Flow RPM, 31 * - AIO Pump RPM, 32 * - CPU Temperature, 33 * - CPU Socket Temperature, 34 * - Motherboard Temperature, 35 * - Chipset Temperature, 36 * - Tsensor 1 Temperature, 37 * - CPU VRM Temperature, 38 * - Water In, 39 * - Water Out, 40 * - CPU VRM Output Current. 41 */ 42 43 #include <linux/acpi.h> 44 #include <linux/dmi.h> 45 #include <linux/hwmon.h> 46 #include <linux/init.h> 47 #include <linux/jiffies.h> 48 #include <linux/kernel.h> 49 #include <linux/module.h> 50 #include <linux/mutex.h> 51 #include <linux/units.h> 52 #include <linux/wmi.h> 53 54 #define ASUSWMI_MONITORING_GUID "466747A0-70EC-11DE-8A39-0800200C9A66" 55 #define ASUSWMI_METHODID_GET_VALUE 0x52574543 /* RWEC */ 56 #define ASUSWMI_METHODID_UPDATE_BUFFER 0x51574543 /* QWEC */ 57 #define ASUSWMI_METHODID_GET_INFO 0x50574543 /* PWEC */ 58 #define ASUSWMI_METHODID_GET_NUMBER 0x50574572 /* PWEr */ 59 #define ASUSWMI_METHODID_GET_VERSION 0x50574574 /* PWEt */ 60 61 #define ASUS_WMI_MAX_STR_SIZE 32 62 63 #define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name) { \ 64 .matches = { \ 65 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), \ 66 DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \ 67 }, \ 68 } 69 70 static const struct dmi_system_id asus_wmi_dmi_table[] = { 71 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X399-A"), 72 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X470-PRO"), 73 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VI EXTREME"), 74 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VI HERO"), 75 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VI HERO (WI-FI AC)"), 76 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VII HERO"), 77 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VII HERO (WI-FI)"), 78 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-E GAMING"), 79 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-F GAMING"), 80 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-I GAMING"), 81 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X399-E GAMING"), 82 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X470-F GAMING"), 83 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X470-I GAMING"), 84 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH EXTREME"), 85 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH EXTREME ALPHA"), 86 {} 87 }; 88 MODULE_DEVICE_TABLE(dmi, asus_wmi_dmi_table); 89 90 enum asus_wmi_sensor_class { 91 VOLTAGE = 0x0, 92 TEMPERATURE_C = 0x1, 93 FAN_RPM = 0x2, 94 CURRENT = 0x3, 95 WATER_FLOW = 0x4, 96 }; 97 98 enum asus_wmi_location { 99 CPU = 0x0, 100 CPU_SOC = 0x1, 101 DRAM = 0x2, 102 MOTHERBOARD = 0x3, 103 CHIPSET = 0x4, 104 AUX = 0x5, 105 VRM = 0x6, 106 COOLER = 0x7 107 }; 108 109 enum asus_wmi_type { 110 SIGNED_INT = 0x0, 111 UNSIGNED_INT = 0x1, 112 SCALED = 0x3, 113 }; 114 115 enum asus_wmi_source { 116 SIO = 0x1, 117 EC = 0x2 118 }; 119 120 static enum hwmon_sensor_types asus_data_types[] = { 121 [VOLTAGE] = hwmon_in, 122 [TEMPERATURE_C] = hwmon_temp, 123 [FAN_RPM] = hwmon_fan, 124 [CURRENT] = hwmon_curr, 125 [WATER_FLOW] = hwmon_fan, 126 }; 127 128 static u32 hwmon_attributes[hwmon_max] = { 129 [hwmon_chip] = HWMON_C_REGISTER_TZ, 130 [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL, 131 [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL, 132 [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL, 133 [hwmon_fan] = HWMON_F_INPUT | HWMON_F_LABEL, 134 }; 135 136 /** 137 * struct asus_wmi_sensor_info - sensor info. 138 * @id: sensor id. 139 * @data_type: sensor class e.g. voltage, temp etc. 140 * @location: sensor location. 141 * @name: sensor name. 142 * @source: sensor source. 143 * @type: sensor type signed, unsigned etc. 144 * @cached_value: cached sensor value. 145 */ 146 struct asus_wmi_sensor_info { 147 u32 id; 148 int data_type; 149 int location; 150 char name[ASUS_WMI_MAX_STR_SIZE]; 151 int source; 152 int type; 153 long cached_value; 154 }; 155 156 struct asus_wmi_wmi_info { 157 unsigned long source_last_updated[3]; /* in jiffies */ 158 int sensor_count; 159 160 const struct asus_wmi_sensor_info **info[hwmon_max]; 161 struct asus_wmi_sensor_info **info_by_id; 162 }; 163 164 struct asus_wmi_sensors { 165 struct asus_wmi_wmi_info wmi; 166 /* lock access to internal cache */ 167 struct mutex lock; 168 }; 169 170 /* 171 * Universal method for calling WMI method 172 */ 173 static int asus_wmi_call_method(u32 method_id, u32 *args, struct acpi_buffer *output) 174 { 175 struct acpi_buffer input = {(acpi_size) sizeof(*args), args }; 176 acpi_status status; 177 178 status = wmi_evaluate_method(ASUSWMI_MONITORING_GUID, 0, 179 method_id, &input, output); 180 if (ACPI_FAILURE(status)) 181 return -EIO; 182 183 return 0; 184 } 185 186 /* 187 * Gets the version of the ASUS sensors interface implemented 188 */ 189 static int asus_wmi_get_version(u32 *version) 190 { 191 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 192 u32 args[] = {0, 0, 0}; 193 union acpi_object *obj; 194 int err; 195 196 err = asus_wmi_call_method(ASUSWMI_METHODID_GET_VERSION, args, &output); 197 if (err) 198 return err; 199 200 obj = output.pointer; 201 if (!obj) 202 return -EIO; 203 204 if (obj->type != ACPI_TYPE_INTEGER) { 205 err = -EIO; 206 goto out_free_obj; 207 } 208 209 err = 0; 210 *version = obj->integer.value; 211 212 out_free_obj: 213 ACPI_FREE(obj); 214 return err; 215 } 216 217 /* 218 * Gets the number of sensor items 219 */ 220 static int asus_wmi_get_item_count(u32 *count) 221 { 222 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 223 u32 args[] = {0, 0, 0}; 224 union acpi_object *obj; 225 int err; 226 227 err = asus_wmi_call_method(ASUSWMI_METHODID_GET_NUMBER, args, &output); 228 if (err) 229 return err; 230 231 obj = output.pointer; 232 if (!obj) 233 return -EIO; 234 235 if (obj->type != ACPI_TYPE_INTEGER) { 236 err = -EIO; 237 goto out_free_obj; 238 } 239 240 err = 0; 241 *count = obj->integer.value; 242 243 out_free_obj: 244 ACPI_FREE(obj); 245 return err; 246 } 247 248 static int asus_wmi_hwmon_add_chan_info(struct hwmon_channel_info *asus_wmi_hwmon_chan, 249 struct device *dev, int num, 250 enum hwmon_sensor_types type, u32 config) 251 { 252 u32 *cfg; 253 254 cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL); 255 if (!cfg) 256 return -ENOMEM; 257 258 asus_wmi_hwmon_chan->type = type; 259 asus_wmi_hwmon_chan->config = cfg; 260 memset32(cfg, config, num); 261 262 return 0; 263 } 264 265 /* 266 * For a given sensor item returns details e.g. type (voltage/temperature/fan speed etc), bank etc 267 */ 268 static int asus_wmi_sensor_info(int index, struct asus_wmi_sensor_info *s) 269 { 270 union acpi_object name_obj, data_type_obj, location_obj, source_obj, type_obj; 271 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 272 u32 args[] = {index, 0}; 273 union acpi_object *obj; 274 int err; 275 276 err = asus_wmi_call_method(ASUSWMI_METHODID_GET_INFO, args, &output); 277 if (err) 278 return err; 279 280 s->id = index; 281 282 obj = output.pointer; 283 if (!obj) 284 return -EIO; 285 286 if (obj->type != ACPI_TYPE_PACKAGE) { 287 err = -EIO; 288 goto out_free_obj; 289 } 290 291 if (obj->package.count != 5) { 292 err = -EIO; 293 goto out_free_obj; 294 } 295 296 name_obj = obj->package.elements[0]; 297 if (name_obj.type != ACPI_TYPE_STRING) { 298 err = -EIO; 299 goto out_free_obj; 300 } 301 302 strncpy(s->name, name_obj.string.pointer, sizeof(s->name) - 1); 303 304 data_type_obj = obj->package.elements[1]; 305 if (data_type_obj.type != ACPI_TYPE_INTEGER) { 306 err = -EIO; 307 goto out_free_obj; 308 } 309 310 s->data_type = data_type_obj.integer.value; 311 312 location_obj = obj->package.elements[2]; 313 if (location_obj.type != ACPI_TYPE_INTEGER) { 314 err = -EIO; 315 goto out_free_obj; 316 } 317 318 s->location = location_obj.integer.value; 319 320 source_obj = obj->package.elements[3]; 321 if (source_obj.type != ACPI_TYPE_INTEGER) { 322 err = -EIO; 323 goto out_free_obj; 324 } 325 326 s->source = source_obj.integer.value; 327 328 type_obj = obj->package.elements[4]; 329 if (type_obj.type != ACPI_TYPE_INTEGER) { 330 err = -EIO; 331 goto out_free_obj; 332 } 333 334 err = 0; 335 s->type = type_obj.integer.value; 336 337 out_free_obj: 338 ACPI_FREE(obj); 339 return err; 340 } 341 342 static int asus_wmi_update_buffer(int source) 343 { 344 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 345 u32 args[] = {source, 0}; 346 347 return asus_wmi_call_method(ASUSWMI_METHODID_UPDATE_BUFFER, args, &output); 348 } 349 350 static int asus_wmi_get_sensor_value(u8 index, long *value) 351 { 352 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 353 u32 args[] = {index, 0}; 354 union acpi_object *obj; 355 int err; 356 357 err = asus_wmi_call_method(ASUSWMI_METHODID_GET_VALUE, args, &output); 358 if (err) 359 return err; 360 361 obj = output.pointer; 362 if (!obj) 363 return -EIO; 364 365 if (obj->type != ACPI_TYPE_INTEGER) { 366 err = -EIO; 367 goto out_free_obj; 368 } 369 370 err = 0; 371 *value = obj->integer.value; 372 373 out_free_obj: 374 ACPI_FREE(obj); 375 return err; 376 } 377 378 static int asus_wmi_update_values_for_source(u8 source, struct asus_wmi_sensors *sensor_data) 379 { 380 struct asus_wmi_sensor_info *sensor; 381 long value = 0; 382 int ret; 383 int i; 384 385 for (i = 0; i < sensor_data->wmi.sensor_count; i++) { 386 sensor = sensor_data->wmi.info_by_id[i]; 387 if (sensor && sensor->source == source) { 388 ret = asus_wmi_get_sensor_value(sensor->id, &value); 389 if (ret) 390 return ret; 391 392 sensor->cached_value = value; 393 } 394 } 395 396 return 0; 397 } 398 399 static int asus_wmi_scale_sensor_value(u32 value, int data_type) 400 { 401 /* FAN_RPM and WATER_FLOW don't need scaling */ 402 switch (data_type) { 403 case VOLTAGE: 404 /* value in microVolts */ 405 return DIV_ROUND_CLOSEST(value, KILO); 406 case TEMPERATURE_C: 407 /* value in Celsius */ 408 return value * MILLIDEGREE_PER_DEGREE; 409 case CURRENT: 410 /* value in Amperes */ 411 return value * MILLI; 412 } 413 return value; 414 } 415 416 static int asus_wmi_get_cached_value_or_update(const struct asus_wmi_sensor_info *sensor, 417 struct asus_wmi_sensors *sensor_data, 418 u32 *value) 419 { 420 int ret = 0; 421 422 mutex_lock(&sensor_data->lock); 423 424 if (time_after(jiffies, sensor_data->wmi.source_last_updated[sensor->source] + HZ)) { 425 ret = asus_wmi_update_buffer(sensor->source); 426 if (ret) 427 goto unlock; 428 429 ret = asus_wmi_update_values_for_source(sensor->source, sensor_data); 430 if (ret) 431 goto unlock; 432 433 sensor_data->wmi.source_last_updated[sensor->source] = jiffies; 434 } 435 436 *value = sensor->cached_value; 437 438 unlock: 439 mutex_unlock(&sensor_data->lock); 440 441 return ret; 442 } 443 444 /* Now follow the functions that implement the hwmon interface */ 445 static int asus_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 446 u32 attr, int channel, long *val) 447 { 448 const struct asus_wmi_sensor_info *sensor; 449 u32 value = 0; 450 int ret; 451 452 struct asus_wmi_sensors *sensor_data = dev_get_drvdata(dev); 453 454 sensor = *(sensor_data->wmi.info[type] + channel); 455 456 ret = asus_wmi_get_cached_value_or_update(sensor, sensor_data, &value); 457 if (ret) 458 return ret; 459 460 *val = asus_wmi_scale_sensor_value(value, sensor->data_type); 461 462 return ret; 463 } 464 465 static int asus_wmi_hwmon_read_string(struct device *dev, 466 enum hwmon_sensor_types type, u32 attr, 467 int channel, const char **str) 468 { 469 struct asus_wmi_sensors *sensor_data = dev_get_drvdata(dev); 470 const struct asus_wmi_sensor_info *sensor; 471 472 sensor = *(sensor_data->wmi.info[type] + channel); 473 *str = sensor->name; 474 475 return 0; 476 } 477 478 static umode_t asus_wmi_hwmon_is_visible(const void *drvdata, 479 enum hwmon_sensor_types type, u32 attr, 480 int channel) 481 { 482 const struct asus_wmi_sensors *sensor_data = drvdata; 483 const struct asus_wmi_sensor_info *sensor; 484 485 sensor = *(sensor_data->wmi.info[type] + channel); 486 if (sensor) 487 return 0444; 488 489 return 0; 490 } 491 492 static const struct hwmon_ops asus_wmi_hwmon_ops = { 493 .is_visible = asus_wmi_hwmon_is_visible, 494 .read = asus_wmi_hwmon_read, 495 .read_string = asus_wmi_hwmon_read_string, 496 }; 497 498 static struct hwmon_chip_info asus_wmi_chip_info = { 499 .ops = &asus_wmi_hwmon_ops, 500 .info = NULL, 501 }; 502 503 static int asus_wmi_configure_sensor_setup(struct device *dev, 504 struct asus_wmi_sensors *sensor_data) 505 { 506 const struct hwmon_channel_info **ptr_asus_wmi_ci; 507 struct hwmon_channel_info *asus_wmi_hwmon_chan; 508 int nr_count[hwmon_max] = {}, nr_types = 0; 509 struct asus_wmi_sensor_info *temp_sensor; 510 const struct hwmon_chip_info *chip_info; 511 enum hwmon_sensor_types type; 512 struct device *hwdev; 513 int i, idx; 514 int err; 515 516 temp_sensor = devm_kcalloc(dev, 1, sizeof(*temp_sensor), GFP_KERNEL); 517 if (!temp_sensor) 518 return -ENOMEM; 519 520 for (i = 0; i < sensor_data->wmi.sensor_count; i++) { 521 err = asus_wmi_sensor_info(i, temp_sensor); 522 if (err) 523 return err; 524 525 switch (temp_sensor->data_type) { 526 case TEMPERATURE_C: 527 case VOLTAGE: 528 case CURRENT: 529 case FAN_RPM: 530 case WATER_FLOW: 531 type = asus_data_types[temp_sensor->data_type]; 532 if (!nr_count[type]) 533 nr_types++; 534 nr_count[type]++; 535 break; 536 } 537 } 538 539 if (nr_count[hwmon_temp]) 540 nr_count[hwmon_chip]++, nr_types++; 541 542 asus_wmi_hwmon_chan = devm_kcalloc(dev, nr_types, 543 sizeof(*asus_wmi_hwmon_chan), 544 GFP_KERNEL); 545 if (!asus_wmi_hwmon_chan) 546 return -ENOMEM; 547 548 ptr_asus_wmi_ci = devm_kcalloc(dev, nr_types + 1, 549 sizeof(*ptr_asus_wmi_ci), GFP_KERNEL); 550 if (!ptr_asus_wmi_ci) 551 return -ENOMEM; 552 553 asus_wmi_chip_info.info = ptr_asus_wmi_ci; 554 chip_info = &asus_wmi_chip_info; 555 556 sensor_data->wmi.info_by_id = devm_kcalloc(dev, sensor_data->wmi.sensor_count, 557 sizeof(*sensor_data->wmi.info_by_id), 558 GFP_KERNEL); 559 560 if (!sensor_data->wmi.info_by_id) 561 return -ENOMEM; 562 563 for (type = 0; type < hwmon_max; type++) { 564 if (!nr_count[type]) 565 continue; 566 567 err = asus_wmi_hwmon_add_chan_info(asus_wmi_hwmon_chan, dev, 568 nr_count[type], type, 569 hwmon_attributes[type]); 570 if (err) 571 return err; 572 573 *ptr_asus_wmi_ci++ = asus_wmi_hwmon_chan++; 574 575 sensor_data->wmi.info[type] = devm_kcalloc(dev, 576 nr_count[type], 577 sizeof(*sensor_data->wmi.info), 578 GFP_KERNEL); 579 if (!sensor_data->wmi.info[type]) 580 return -ENOMEM; 581 } 582 583 for (i = sensor_data->wmi.sensor_count - 1; i >= 0; i--) { 584 temp_sensor = devm_kzalloc(dev, sizeof(*temp_sensor), GFP_KERNEL); 585 if (!temp_sensor) 586 return -ENOMEM; 587 588 err = asus_wmi_sensor_info(i, temp_sensor); 589 if (err) 590 continue; 591 592 switch (temp_sensor->data_type) { 593 case TEMPERATURE_C: 594 case VOLTAGE: 595 case CURRENT: 596 case FAN_RPM: 597 case WATER_FLOW: 598 type = asus_data_types[temp_sensor->data_type]; 599 idx = --nr_count[type]; 600 *(sensor_data->wmi.info[type] + idx) = temp_sensor; 601 sensor_data->wmi.info_by_id[i] = temp_sensor; 602 break; 603 } 604 } 605 606 dev_dbg(dev, "board has %d sensors", 607 sensor_data->wmi.sensor_count); 608 609 hwdev = devm_hwmon_device_register_with_info(dev, "asus_wmi_sensors", 610 sensor_data, chip_info, NULL); 611 612 return PTR_ERR_OR_ZERO(hwdev); 613 } 614 615 static int asus_wmi_probe(struct wmi_device *wdev, const void *context) 616 { 617 struct asus_wmi_sensors *sensor_data; 618 struct device *dev = &wdev->dev; 619 u32 version = 0; 620 621 if (!dmi_check_system(asus_wmi_dmi_table)) 622 return -ENODEV; 623 624 sensor_data = devm_kzalloc(dev, sizeof(*sensor_data), GFP_KERNEL); 625 if (!sensor_data) 626 return -ENOMEM; 627 628 if (asus_wmi_get_version(&version)) 629 return -ENODEV; 630 631 if (asus_wmi_get_item_count(&sensor_data->wmi.sensor_count)) 632 return -ENODEV; 633 634 if (sensor_data->wmi.sensor_count <= 0 || version < 2) { 635 dev_info(dev, "version: %u with %d sensors is unsupported\n", 636 version, sensor_data->wmi.sensor_count); 637 638 return -ENODEV; 639 } 640 641 mutex_init(&sensor_data->lock); 642 643 dev_set_drvdata(dev, sensor_data); 644 645 return asus_wmi_configure_sensor_setup(dev, sensor_data); 646 } 647 648 static const struct wmi_device_id asus_wmi_id_table[] = { 649 { ASUSWMI_MONITORING_GUID, NULL }, 650 { } 651 }; 652 653 static struct wmi_driver asus_sensors_wmi_driver = { 654 .driver = { 655 .name = "asus_wmi_sensors", 656 }, 657 .id_table = asus_wmi_id_table, 658 .probe = asus_wmi_probe, 659 }; 660 module_wmi_driver(asus_sensors_wmi_driver); 661 662 MODULE_AUTHOR("Ed Brindley <kernel@maidavale.org>"); 663 MODULE_DESCRIPTION("Asus WMI Sensors Driver"); 664 MODULE_LICENSE("GPL"); 665