1 // SPDX-License-Identifier: GPL-2.0-or-later
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.
6 * Copyright (C) 2018-2019 Ed Brindley <kernel@maidavale.org>
8 * WMI interface provides:
24 * - Chassis Fan 1 RPM,
25 * - Chassis Fan 2 RPM,
26 * - Chassis Fan 3 RPM,
33 * - CPU Socket Temperature,
34 * - Motherboard Temperature,
35 * - Chipset Temperature,
36 * - Tsensor 1 Temperature,
37 * - CPU VRM Temperature,
40 * - CPU VRM Output Current.
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>
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 */
61 #define ASUS_WMI_MAX_STR_SIZE 32
63 #define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name) { \
65 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), \
66 DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
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("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-F GAMING II"),
81 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B450-I GAMING"),
82 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X399-E GAMING"),
83 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X470-F GAMING"),
84 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X470-I GAMING"),
85 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH EXTREME"),
86 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH EXTREME ALPHA"),
89 MODULE_DEVICE_TABLE(dmi
, asus_wmi_dmi_table
);
91 enum asus_wmi_sensor_class
{
99 enum asus_wmi_location
{
116 enum asus_wmi_source
{
121 static enum hwmon_sensor_types asus_data_types
[] = {
122 [VOLTAGE
] = hwmon_in
,
123 [TEMPERATURE_C
] = hwmon_temp
,
124 [FAN_RPM
] = hwmon_fan
,
125 [CURRENT
] = hwmon_curr
,
126 [WATER_FLOW
] = hwmon_fan
,
129 static u32 hwmon_attributes
[hwmon_max
] = {
130 [hwmon_chip
] = HWMON_C_REGISTER_TZ
,
131 [hwmon_temp
] = HWMON_T_INPUT
| HWMON_T_LABEL
,
132 [hwmon_in
] = HWMON_I_INPUT
| HWMON_I_LABEL
,
133 [hwmon_curr
] = HWMON_C_INPUT
| HWMON_C_LABEL
,
134 [hwmon_fan
] = HWMON_F_INPUT
| HWMON_F_LABEL
,
138 * struct asus_wmi_sensor_info - sensor info.
140 * @data_type: sensor class e.g. voltage, temp etc.
141 * @location: sensor location.
142 * @name: sensor name.
143 * @source: sensor source.
144 * @type: sensor type signed, unsigned etc.
145 * @cached_value: cached sensor value.
147 struct asus_wmi_sensor_info
{
151 char name
[ASUS_WMI_MAX_STR_SIZE
];
157 struct asus_wmi_wmi_info
{
158 unsigned long source_last_updated
[3]; /* in jiffies */
161 const struct asus_wmi_sensor_info
**info
[hwmon_max
];
162 struct asus_wmi_sensor_info
**info_by_id
;
165 struct asus_wmi_sensors
{
166 struct asus_wmi_wmi_info wmi
;
167 /* lock access to internal cache */
172 * Universal method for calling WMI method
174 static int asus_wmi_call_method(u32 method_id
, u32
*args
, struct acpi_buffer
*output
)
176 struct acpi_buffer input
= {(acpi_size
) sizeof(*args
), args
};
179 status
= wmi_evaluate_method(ASUSWMI_MONITORING_GUID
, 0,
180 method_id
, &input
, output
);
181 if (ACPI_FAILURE(status
))
188 * Gets the version of the ASUS sensors interface implemented
190 static int asus_wmi_get_version(u32
*version
)
192 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
193 u32 args
[] = {0, 0, 0};
194 union acpi_object
*obj
;
197 err
= asus_wmi_call_method(ASUSWMI_METHODID_GET_VERSION
, args
, &output
);
201 obj
= output
.pointer
;
205 if (obj
->type
!= ACPI_TYPE_INTEGER
) {
211 *version
= obj
->integer
.value
;
219 * Gets the number of sensor items
221 static int asus_wmi_get_item_count(u32
*count
)
223 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
224 u32 args
[] = {0, 0, 0};
225 union acpi_object
*obj
;
228 err
= asus_wmi_call_method(ASUSWMI_METHODID_GET_NUMBER
, args
, &output
);
232 obj
= output
.pointer
;
236 if (obj
->type
!= ACPI_TYPE_INTEGER
) {
242 *count
= obj
->integer
.value
;
249 static int asus_wmi_hwmon_add_chan_info(struct hwmon_channel_info
*asus_wmi_hwmon_chan
,
250 struct device
*dev
, int num
,
251 enum hwmon_sensor_types type
, u32 config
)
255 cfg
= devm_kcalloc(dev
, num
+ 1, sizeof(*cfg
), GFP_KERNEL
);
259 asus_wmi_hwmon_chan
->type
= type
;
260 asus_wmi_hwmon_chan
->config
= cfg
;
261 memset32(cfg
, config
, num
);
267 * For a given sensor item returns details e.g. type (voltage/temperature/fan speed etc), bank etc
269 static int asus_wmi_sensor_info(int index
, struct asus_wmi_sensor_info
*s
)
271 union acpi_object name_obj
, data_type_obj
, location_obj
, source_obj
, type_obj
;
272 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
273 u32 args
[] = {index
, 0};
274 union acpi_object
*obj
;
277 err
= asus_wmi_call_method(ASUSWMI_METHODID_GET_INFO
, args
, &output
);
283 obj
= output
.pointer
;
287 if (obj
->type
!= ACPI_TYPE_PACKAGE
) {
292 if (obj
->package
.count
!= 5) {
297 name_obj
= obj
->package
.elements
[0];
298 if (name_obj
.type
!= ACPI_TYPE_STRING
) {
303 strscpy(s
->name
, name_obj
.string
.pointer
, sizeof(s
->name
));
305 data_type_obj
= obj
->package
.elements
[1];
306 if (data_type_obj
.type
!= ACPI_TYPE_INTEGER
) {
311 s
->data_type
= data_type_obj
.integer
.value
;
313 location_obj
= obj
->package
.elements
[2];
314 if (location_obj
.type
!= ACPI_TYPE_INTEGER
) {
319 s
->location
= location_obj
.integer
.value
;
321 source_obj
= obj
->package
.elements
[3];
322 if (source_obj
.type
!= ACPI_TYPE_INTEGER
) {
327 s
->source
= source_obj
.integer
.value
;
329 type_obj
= obj
->package
.elements
[4];
330 if (type_obj
.type
!= ACPI_TYPE_INTEGER
) {
336 s
->type
= type_obj
.integer
.value
;
343 static int asus_wmi_update_buffer(int source
)
345 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
346 u32 args
[] = {source
, 0};
348 return asus_wmi_call_method(ASUSWMI_METHODID_UPDATE_BUFFER
, args
, &output
);
351 static int asus_wmi_get_sensor_value(u8 index
, long *value
)
353 struct acpi_buffer output
= { ACPI_ALLOCATE_BUFFER
, NULL
};
354 u32 args
[] = {index
, 0};
355 union acpi_object
*obj
;
358 err
= asus_wmi_call_method(ASUSWMI_METHODID_GET_VALUE
, args
, &output
);
362 obj
= output
.pointer
;
366 if (obj
->type
!= ACPI_TYPE_INTEGER
) {
372 *value
= obj
->integer
.value
;
379 static int asus_wmi_update_values_for_source(u8 source
, struct asus_wmi_sensors
*sensor_data
)
381 struct asus_wmi_sensor_info
*sensor
;
386 for (i
= 0; i
< sensor_data
->wmi
.sensor_count
; i
++) {
387 sensor
= sensor_data
->wmi
.info_by_id
[i
];
388 if (sensor
&& sensor
->source
== source
) {
389 ret
= asus_wmi_get_sensor_value(sensor
->id
, &value
);
393 sensor
->cached_value
= value
;
400 static int asus_wmi_scale_sensor_value(u32 value
, int data_type
)
402 /* FAN_RPM and WATER_FLOW don't need scaling */
405 /* value in microVolts */
406 return DIV_ROUND_CLOSEST(value
, KILO
);
408 /* value in Celsius */
409 return value
* MILLIDEGREE_PER_DEGREE
;
411 /* value in Amperes */
412 return value
* MILLI
;
417 static int asus_wmi_get_cached_value_or_update(const struct asus_wmi_sensor_info
*sensor
,
418 struct asus_wmi_sensors
*sensor_data
,
423 mutex_lock(&sensor_data
->lock
);
425 if (time_after(jiffies
, sensor_data
->wmi
.source_last_updated
[sensor
->source
] + HZ
)) {
426 ret
= asus_wmi_update_buffer(sensor
->source
);
430 ret
= asus_wmi_update_values_for_source(sensor
->source
, sensor_data
);
434 sensor_data
->wmi
.source_last_updated
[sensor
->source
] = jiffies
;
437 *value
= sensor
->cached_value
;
440 mutex_unlock(&sensor_data
->lock
);
445 /* Now follow the functions that implement the hwmon interface */
446 static int asus_wmi_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
447 u32 attr
, int channel
, long *val
)
449 const struct asus_wmi_sensor_info
*sensor
;
453 struct asus_wmi_sensors
*sensor_data
= dev_get_drvdata(dev
);
455 sensor
= *(sensor_data
->wmi
.info
[type
] + channel
);
457 ret
= asus_wmi_get_cached_value_or_update(sensor
, sensor_data
, &value
);
461 *val
= asus_wmi_scale_sensor_value(value
, sensor
->data_type
);
466 static int asus_wmi_hwmon_read_string(struct device
*dev
,
467 enum hwmon_sensor_types type
, u32 attr
,
468 int channel
, const char **str
)
470 struct asus_wmi_sensors
*sensor_data
= dev_get_drvdata(dev
);
471 const struct asus_wmi_sensor_info
*sensor
;
473 sensor
= *(sensor_data
->wmi
.info
[type
] + channel
);
479 static umode_t
asus_wmi_hwmon_is_visible(const void *drvdata
,
480 enum hwmon_sensor_types type
, u32 attr
,
483 const struct asus_wmi_sensors
*sensor_data
= drvdata
;
484 const struct asus_wmi_sensor_info
*sensor
;
486 sensor
= *(sensor_data
->wmi
.info
[type
] + channel
);
493 static const struct hwmon_ops asus_wmi_hwmon_ops
= {
494 .is_visible
= asus_wmi_hwmon_is_visible
,
495 .read
= asus_wmi_hwmon_read
,
496 .read_string
= asus_wmi_hwmon_read_string
,
499 static struct hwmon_chip_info asus_wmi_chip_info
= {
500 .ops
= &asus_wmi_hwmon_ops
,
504 static int asus_wmi_configure_sensor_setup(struct device
*dev
,
505 struct asus_wmi_sensors
*sensor_data
)
507 const struct hwmon_channel_info
**ptr_asus_wmi_ci
;
508 struct hwmon_channel_info
*asus_wmi_hwmon_chan
;
509 int nr_count
[hwmon_max
] = {}, nr_types
= 0;
510 struct asus_wmi_sensor_info
*temp_sensor
;
511 const struct hwmon_chip_info
*chip_info
;
512 enum hwmon_sensor_types type
;
513 struct device
*hwdev
;
517 for (i
= 0; i
< sensor_data
->wmi
.sensor_count
; i
++) {
518 struct asus_wmi_sensor_info sensor
;
520 err
= asus_wmi_sensor_info(i
, &sensor
);
524 switch (sensor
.data_type
) {
530 type
= asus_data_types
[sensor
.data_type
];
538 if (nr_count
[hwmon_temp
])
539 nr_count
[hwmon_chip
]++, nr_types
++;
541 asus_wmi_hwmon_chan
= devm_kcalloc(dev
, nr_types
,
542 sizeof(*asus_wmi_hwmon_chan
),
544 if (!asus_wmi_hwmon_chan
)
547 ptr_asus_wmi_ci
= devm_kcalloc(dev
, nr_types
+ 1,
548 sizeof(*ptr_asus_wmi_ci
), GFP_KERNEL
);
549 if (!ptr_asus_wmi_ci
)
552 asus_wmi_chip_info
.info
= ptr_asus_wmi_ci
;
553 chip_info
= &asus_wmi_chip_info
;
555 sensor_data
->wmi
.info_by_id
= devm_kcalloc(dev
, sensor_data
->wmi
.sensor_count
,
556 sizeof(*sensor_data
->wmi
.info_by_id
),
559 if (!sensor_data
->wmi
.info_by_id
)
562 for (type
= 0; type
< hwmon_max
; type
++) {
566 err
= asus_wmi_hwmon_add_chan_info(asus_wmi_hwmon_chan
, dev
,
567 nr_count
[type
], type
,
568 hwmon_attributes
[type
]);
572 *ptr_asus_wmi_ci
++ = asus_wmi_hwmon_chan
++;
574 sensor_data
->wmi
.info
[type
] = devm_kcalloc(dev
,
576 sizeof(*sensor_data
->wmi
.info
),
578 if (!sensor_data
->wmi
.info
[type
])
582 for (i
= sensor_data
->wmi
.sensor_count
- 1; i
>= 0; i
--) {
583 temp_sensor
= devm_kzalloc(dev
, sizeof(*temp_sensor
), GFP_KERNEL
);
587 err
= asus_wmi_sensor_info(i
, temp_sensor
);
591 switch (temp_sensor
->data_type
) {
597 type
= asus_data_types
[temp_sensor
->data_type
];
598 idx
= --nr_count
[type
];
599 *(sensor_data
->wmi
.info
[type
] + idx
) = temp_sensor
;
600 sensor_data
->wmi
.info_by_id
[i
] = temp_sensor
;
605 dev_dbg(dev
, "board has %d sensors",
606 sensor_data
->wmi
.sensor_count
);
608 hwdev
= devm_hwmon_device_register_with_info(dev
, "asus_wmi_sensors",
609 sensor_data
, chip_info
, NULL
);
611 return PTR_ERR_OR_ZERO(hwdev
);
614 static int asus_wmi_probe(struct wmi_device
*wdev
, const void *context
)
616 struct asus_wmi_sensors
*sensor_data
;
617 struct device
*dev
= &wdev
->dev
;
620 if (!dmi_check_system(asus_wmi_dmi_table
))
623 sensor_data
= devm_kzalloc(dev
, sizeof(*sensor_data
), GFP_KERNEL
);
627 if (asus_wmi_get_version(&version
))
630 if (asus_wmi_get_item_count(&sensor_data
->wmi
.sensor_count
))
633 if (sensor_data
->wmi
.sensor_count
<= 0 || version
< 2) {
634 dev_info(dev
, "version: %u with %d sensors is unsupported\n",
635 version
, sensor_data
->wmi
.sensor_count
);
640 mutex_init(&sensor_data
->lock
);
642 dev_set_drvdata(dev
, sensor_data
);
644 return asus_wmi_configure_sensor_setup(dev
, sensor_data
);
647 static const struct wmi_device_id asus_wmi_id_table
[] = {
648 { ASUSWMI_MONITORING_GUID
, NULL
},
652 static struct wmi_driver asus_sensors_wmi_driver
= {
654 .name
= "asus_wmi_sensors",
656 .id_table
= asus_wmi_id_table
,
657 .probe
= asus_wmi_probe
,
659 module_wmi_driver(asus_sensors_wmi_driver
);
661 MODULE_AUTHOR("Ed Brindley <kernel@maidavale.org>");
662 MODULE_DESCRIPTION("Asus WMI Sensors Driver");
663 MODULE_LICENSE("GPL");