1118 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * HWMON driver for ASUS motherboards that publish some sensor values4 * via the embedded controller registers.5 *6 * Copyright (C) 2021 Eugene Shalygin <eugene.shalygin@gmail.com>7 8 * EC provides:9 * - Chipset temperature10 * - CPU temperature11 * - Motherboard temperature12 * - T_Sensor temperature13 * - VRM temperature14 * - Water In temperature15 * - Water Out temperature16 * - CPU Optional fan RPM17 * - Chipset fan RPM18 * - VRM Heat Sink fan RPM19 * - Water Flow fan RPM20 * - CPU current21 * - CPU core voltage22 */23 24#include <linux/acpi.h>25#include <linux/bitops.h>26#include <linux/dev_printk.h>27#include <linux/dmi.h>28#include <linux/hwmon.h>29#include <linux/init.h>30#include <linux/jiffies.h>31#include <linux/kernel.h>32#include <linux/module.h>33#include <linux/platform_device.h>34#include <linux/sort.h>35#include <linux/units.h>36 37#include <linux/unaligned.h>38 39static char *mutex_path_override;40 41/* Writing to this EC register switches EC bank */42#define ASUS_EC_BANK_REGISTER 0xff43#define SENSOR_LABEL_LEN 1644 45/*46 * Arbitrary set max. allowed bank number. Required for sorting banks and47 * currently is overkill with just 2 banks used at max, but for the sake48 * of alignment let's set it to a higher value.49 */50#define ASUS_EC_MAX_BANK 351 52#define ACPI_LOCK_DELAY_MS 50053 54/* ACPI mutex for locking access to the EC for the firmware */55#define ASUS_HW_ACCESS_MUTEX_ASMX "\\AMW0.ASMX"56 57#define ASUS_HW_ACCESS_MUTEX_RMTW_ASMX "\\RMTW.ASMX"58 59#define ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0 "\\_SB_.PCI0.SBRG.SIO1.MUT0"60 61#define MAX_IDENTICAL_BOARD_VARIATIONS 362 63/* Moniker for the ACPI global lock (':' is not allowed in ASL identifiers) */64#define ACPI_GLOBAL_LOCK_PSEUDO_PATH ":GLOBAL_LOCK"65 66typedef union {67 u32 value;68 struct {69 u8 index;70 u8 bank;71 u8 size;72 u8 dummy;73 } components;74} sensor_address;75 76#define MAKE_SENSOR_ADDRESS(size, bank, index) { \77 .value = (size << 16) + (bank << 8) + index \78 }79 80static u32 hwmon_attributes[hwmon_max] = {81 [hwmon_chip] = HWMON_C_REGISTER_TZ,82 [hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL,83 [hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL,84 [hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL,85 [hwmon_fan] = HWMON_F_INPUT | HWMON_F_LABEL,86};87 88struct ec_sensor_info {89 char label[SENSOR_LABEL_LEN];90 enum hwmon_sensor_types type;91 sensor_address addr;92};93 94#define EC_SENSOR(sensor_label, sensor_type, size, bank, index) { \95 .label = sensor_label, .type = sensor_type, \96 .addr = MAKE_SENSOR_ADDRESS(size, bank, index), \97 }98 99enum ec_sensors {100 /* chipset temperature [℃] */101 ec_sensor_temp_chipset,102 /* CPU temperature [℃] */103 ec_sensor_temp_cpu,104 /* CPU package temperature [℃] */105 ec_sensor_temp_cpu_package,106 /* motherboard temperature [℃] */107 ec_sensor_temp_mb,108 /* "T_Sensor" temperature sensor reading [℃] */109 ec_sensor_temp_t_sensor,110 /* VRM temperature [℃] */111 ec_sensor_temp_vrm,112 /* CPU Core voltage [mV] */113 ec_sensor_in_cpu_core,114 /* CPU_Opt fan [RPM] */115 ec_sensor_fan_cpu_opt,116 /* VRM heat sink fan [RPM] */117 ec_sensor_fan_vrm_hs,118 /* Chipset fan [RPM] */119 ec_sensor_fan_chipset,120 /* Water flow sensor reading [RPM] */121 ec_sensor_fan_water_flow,122 /* CPU current [A] */123 ec_sensor_curr_cpu,124 /* "Water_In" temperature sensor reading [℃] */125 ec_sensor_temp_water_in,126 /* "Water_Out" temperature sensor reading [℃] */127 ec_sensor_temp_water_out,128 /* "Water_Block_In" temperature sensor reading [℃] */129 ec_sensor_temp_water_block_in,130 /* "Water_Block_Out" temperature sensor reading [℃] */131 ec_sensor_temp_water_block_out,132 /* "T_sensor_2" temperature sensor reading [℃] */133 ec_sensor_temp_t_sensor_2,134 /* "Extra_1" temperature sensor reading [℃] */135 ec_sensor_temp_sensor_extra_1,136 /* "Extra_2" temperature sensor reading [℃] */137 ec_sensor_temp_sensor_extra_2,138 /* "Extra_3" temperature sensor reading [℃] */139 ec_sensor_temp_sensor_extra_3,140};141 142#define SENSOR_TEMP_CHIPSET BIT(ec_sensor_temp_chipset)143#define SENSOR_TEMP_CPU BIT(ec_sensor_temp_cpu)144#define SENSOR_TEMP_CPU_PACKAGE BIT(ec_sensor_temp_cpu_package)145#define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb)146#define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor)147#define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm)148#define SENSOR_IN_CPU_CORE BIT(ec_sensor_in_cpu_core)149#define SENSOR_FAN_CPU_OPT BIT(ec_sensor_fan_cpu_opt)150#define SENSOR_FAN_VRM_HS BIT(ec_sensor_fan_vrm_hs)151#define SENSOR_FAN_CHIPSET BIT(ec_sensor_fan_chipset)152#define SENSOR_FAN_WATER_FLOW BIT(ec_sensor_fan_water_flow)153#define SENSOR_CURR_CPU BIT(ec_sensor_curr_cpu)154#define SENSOR_TEMP_WATER_IN BIT(ec_sensor_temp_water_in)155#define SENSOR_TEMP_WATER_OUT BIT(ec_sensor_temp_water_out)156#define SENSOR_TEMP_WATER_BLOCK_IN BIT(ec_sensor_temp_water_block_in)157#define SENSOR_TEMP_WATER_BLOCK_OUT BIT(ec_sensor_temp_water_block_out)158#define SENSOR_TEMP_T_SENSOR_2 BIT(ec_sensor_temp_t_sensor_2)159#define SENSOR_TEMP_SENSOR_EXTRA_1 BIT(ec_sensor_temp_sensor_extra_1)160#define SENSOR_TEMP_SENSOR_EXTRA_2 BIT(ec_sensor_temp_sensor_extra_2)161#define SENSOR_TEMP_SENSOR_EXTRA_3 BIT(ec_sensor_temp_sensor_extra_3)162 163enum board_family {164 family_unknown,165 family_amd_400_series,166 family_amd_500_series,167 family_amd_600_series,168 family_intel_300_series,169 family_intel_600_series170};171 172/* All the known sensors for ASUS EC controllers */173static const struct ec_sensor_info sensors_family_amd_400[] = {174 [ec_sensor_temp_chipset] =175 EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),176 [ec_sensor_temp_cpu] =177 EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),178 [ec_sensor_temp_mb] =179 EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),180 [ec_sensor_temp_t_sensor] =181 EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),182 [ec_sensor_temp_vrm] =183 EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),184 [ec_sensor_in_cpu_core] =185 EC_SENSOR("CPU Core", hwmon_in, 2, 0x00, 0xa2),186 [ec_sensor_fan_cpu_opt] =187 EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xbc),188 [ec_sensor_fan_vrm_hs] =189 EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),190 [ec_sensor_fan_chipset] =191 /* no chipset fans in this generation */192 EC_SENSOR("Chipset", hwmon_fan, 0, 0x00, 0x00),193 [ec_sensor_fan_water_flow] =194 EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xb4),195 [ec_sensor_curr_cpu] =196 EC_SENSOR("CPU", hwmon_curr, 1, 0x00, 0xf4),197 [ec_sensor_temp_water_in] =198 EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x0d),199 [ec_sensor_temp_water_out] =200 EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x0b),201};202 203static const struct ec_sensor_info sensors_family_amd_500[] = {204 [ec_sensor_temp_chipset] =205 EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),206 [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),207 [ec_sensor_temp_mb] =208 EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),209 [ec_sensor_temp_t_sensor] =210 EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),211 [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),212 [ec_sensor_in_cpu_core] =213 EC_SENSOR("CPU Core", hwmon_in, 2, 0x00, 0xa2),214 [ec_sensor_fan_cpu_opt] =215 EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),216 [ec_sensor_fan_vrm_hs] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),217 [ec_sensor_fan_chipset] =218 EC_SENSOR("Chipset", hwmon_fan, 2, 0x00, 0xb4),219 [ec_sensor_fan_water_flow] =220 EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xbc),221 [ec_sensor_curr_cpu] = EC_SENSOR("CPU", hwmon_curr, 1, 0x00, 0xf4),222 [ec_sensor_temp_water_in] =223 EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),224 [ec_sensor_temp_water_out] =225 EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),226 [ec_sensor_temp_water_block_in] =227 EC_SENSOR("Water_Block_In", hwmon_temp, 1, 0x01, 0x02),228 [ec_sensor_temp_water_block_out] =229 EC_SENSOR("Water_Block_Out", hwmon_temp, 1, 0x01, 0x03),230 [ec_sensor_temp_sensor_extra_1] =231 EC_SENSOR("Extra_1", hwmon_temp, 1, 0x01, 0x09),232 [ec_sensor_temp_t_sensor_2] =233 EC_SENSOR("T_sensor_2", hwmon_temp, 1, 0x01, 0x0a),234 [ec_sensor_temp_sensor_extra_2] =235 EC_SENSOR("Extra_2", hwmon_temp, 1, 0x01, 0x0b),236 [ec_sensor_temp_sensor_extra_3] =237 EC_SENSOR("Extra_3", hwmon_temp, 1, 0x01, 0x0c),238};239 240static const struct ec_sensor_info sensors_family_amd_600[] = {241 [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x30),242 [ec_sensor_temp_cpu_package] = EC_SENSOR("CPU Package", hwmon_temp, 1, 0x00, 0x31),243 [ec_sensor_temp_mb] =244 EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x32),245 [ec_sensor_temp_vrm] =246 EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33),247 [ec_sensor_temp_t_sensor] =248 EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x36),249 [ec_sensor_temp_water_in] =250 EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),251 [ec_sensor_temp_water_out] =252 EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),253};254 255static const struct ec_sensor_info sensors_family_intel_300[] = {256 [ec_sensor_temp_chipset] =257 EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),258 [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),259 [ec_sensor_temp_mb] =260 EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),261 [ec_sensor_temp_t_sensor] =262 EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),263 [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),264 [ec_sensor_fan_cpu_opt] =265 EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),266 [ec_sensor_fan_vrm_hs] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),267 [ec_sensor_fan_water_flow] =268 EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xbc),269 [ec_sensor_temp_water_in] =270 EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),271 [ec_sensor_temp_water_out] =272 EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),273};274 275static const struct ec_sensor_info sensors_family_intel_600[] = {276 [ec_sensor_temp_t_sensor] =277 EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),278 [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),279};280 281/* Shortcuts for common combinations */282#define SENSOR_SET_TEMP_CHIPSET_CPU_MB \283 (SENSOR_TEMP_CHIPSET | SENSOR_TEMP_CPU | SENSOR_TEMP_MB)284#define SENSOR_SET_TEMP_WATER (SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT)285#define SENSOR_SET_WATER_BLOCK \286 (SENSOR_TEMP_WATER_BLOCK_IN | SENSOR_TEMP_WATER_BLOCK_OUT)287 288struct ec_board_info {289 unsigned long sensors;290 /*291 * Defines which mutex to use for guarding access to the state and the292 * hardware. Can be either a full path to an AML mutex or the293 * pseudo-path ACPI_GLOBAL_LOCK_PSEUDO_PATH to use the global ACPI lock,294 * or left empty to use a regular mutex object, in which case access to295 * the hardware is not guarded.296 */297 const char *mutex_path;298 enum board_family family;299};300 301static const struct ec_board_info board_info_prime_x470_pro = {302 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |303 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |304 SENSOR_FAN_CPU_OPT |305 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,306 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,307 .family = family_amd_400_series,308};309 310static const struct ec_board_info board_info_prime_x570_pro = {311 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |312 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,313 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,314 .family = family_amd_500_series,315};316 317static const struct ec_board_info board_info_pro_art_x570_creator_wifi = {318 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |319 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |320 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,321 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,322 .family = family_amd_500_series,323};324 325static const struct ec_board_info board_info_pro_art_x670E_creator_wifi = {326 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |327 SENSOR_TEMP_MB | SENSOR_TEMP_VRM |328 SENSOR_TEMP_T_SENSOR,329 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,330 .family = family_amd_600_series,331};332 333static const struct ec_board_info board_info_pro_art_b550_creator = {334 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |335 SENSOR_TEMP_T_SENSOR |336 SENSOR_FAN_CPU_OPT,337 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,338 .family = family_amd_500_series,339};340 341static const struct ec_board_info board_info_pro_ws_x570_ace = {342 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |343 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET |344 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,345 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,346 .family = family_amd_500_series,347};348 349static const struct ec_board_info board_info_crosshair_x670e_hero = {350 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |351 SENSOR_TEMP_MB | SENSOR_TEMP_VRM |352 SENSOR_SET_TEMP_WATER,353 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,354 .family = family_amd_600_series,355};356 357static const struct ec_board_info board_info_crosshair_x670e_gene = {358 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |359 SENSOR_TEMP_T_SENSOR |360 SENSOR_TEMP_MB | SENSOR_TEMP_VRM,361 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,362 .family = family_amd_600_series,363};364 365static const struct ec_board_info board_info_crosshair_viii_dark_hero = {366 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |367 SENSOR_TEMP_T_SENSOR |368 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |369 SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW |370 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,371 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,372 .family = family_amd_500_series,373};374 375static const struct ec_board_info board_info_crosshair_viii_hero = {376 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |377 SENSOR_TEMP_T_SENSOR |378 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |379 SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |380 SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU |381 SENSOR_IN_CPU_CORE,382 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,383 .family = family_amd_500_series,384};385 386static const struct ec_board_info board_info_maximus_xi_hero = {387 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |388 SENSOR_TEMP_T_SENSOR |389 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |390 SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW,391 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,392 .family = family_intel_300_series,393};394 395static const struct ec_board_info board_info_crosshair_viii_impact = {396 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |397 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |398 SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |399 SENSOR_IN_CPU_CORE,400 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,401 .family = family_amd_500_series,402};403 404static const struct ec_board_info board_info_strix_b550_e_gaming = {405 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |406 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |407 SENSOR_FAN_CPU_OPT,408 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,409 .family = family_amd_500_series,410};411 412static const struct ec_board_info board_info_strix_b550_i_gaming = {413 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |414 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |415 SENSOR_FAN_VRM_HS | SENSOR_CURR_CPU |416 SENSOR_IN_CPU_CORE,417 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,418 .family = family_amd_500_series,419};420 421static const struct ec_board_info board_info_strix_x570_e_gaming = {422 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |423 SENSOR_TEMP_T_SENSOR |424 SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |425 SENSOR_IN_CPU_CORE,426 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,427 .family = family_amd_500_series,428};429 430static const struct ec_board_info board_info_strix_x570_e_gaming_wifi_ii = {431 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |432 SENSOR_TEMP_T_SENSOR | SENSOR_CURR_CPU |433 SENSOR_IN_CPU_CORE,434 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,435 .family = family_amd_500_series,436};437 438static const struct ec_board_info board_info_strix_x570_f_gaming = {439 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |440 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,441 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,442 .family = family_amd_500_series,443};444 445static const struct ec_board_info board_info_strix_x570_i_gaming = {446 .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |447 SENSOR_TEMP_T_SENSOR |448 SENSOR_FAN_VRM_HS | SENSOR_FAN_CHIPSET |449 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,450 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,451 .family = family_amd_500_series,452};453 454static const struct ec_board_info board_info_strix_z390_f_gaming = {455 .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |456 SENSOR_TEMP_T_SENSOR |457 SENSOR_FAN_CPU_OPT,458 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,459 .family = family_intel_300_series,460};461 462static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = {463 .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,464 .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,465 .family = family_intel_600_series,466};467 468static const struct ec_board_info board_info_zenith_ii_extreme = {469 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |470 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |471 SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | SENSOR_FAN_VRM_HS |472 SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE |473 SENSOR_SET_WATER_BLOCK |474 SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 |475 SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,476 .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,477 .family = family_amd_500_series,478};479 480#define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, board_info) \481 { \482 .matches = { \483 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, \484 "ASUSTeK COMPUTER INC."), \485 DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \486 }, \487 .driver_data = (void *)board_info, \488 }489 490static const struct dmi_system_id dmi_table[] = {491 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X470-PRO",492 &board_info_prime_x470_pro),493 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X570-PRO",494 &board_info_prime_x570_pro),495 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X570-CREATOR WIFI",496 &board_info_pro_art_x570_creator_wifi),497 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X670E-CREATOR WIFI",498 &board_info_pro_art_x670E_creator_wifi),499 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR",500 &board_info_pro_art_b550_creator),501 DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE",502 &board_info_pro_ws_x570_ace),503 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII DARK HERO",504 &board_info_crosshair_viii_dark_hero),505 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII FORMULA",506 &board_info_crosshair_viii_hero),507 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO",508 &board_info_crosshair_viii_hero),509 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO (WI-FI)",510 &board_info_crosshair_viii_hero),511 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO",512 &board_info_crosshair_x670e_hero),513 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E GENE",514 &board_info_crosshair_x670e_gene),515 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO",516 &board_info_maximus_xi_hero),517 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)",518 &board_info_maximus_xi_hero),519 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII IMPACT",520 &board_info_crosshair_viii_impact),521 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-E GAMING",522 &board_info_strix_b550_e_gaming),523 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-I GAMING",524 &board_info_strix_b550_i_gaming),525 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING",526 &board_info_strix_x570_e_gaming),527 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING WIFI II",528 &board_info_strix_x570_e_gaming_wifi_ii),529 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-F GAMING",530 &board_info_strix_x570_f_gaming),531 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-I GAMING",532 &board_info_strix_x570_i_gaming),533 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING",534 &board_info_strix_z390_f_gaming),535 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4",536 &board_info_strix_z690_a_gaming_wifi_d4),537 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",538 &board_info_zenith_ii_extreme),539 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA",540 &board_info_zenith_ii_extreme),541 {},542};543 544struct ec_sensor {545 unsigned int info_index;546 s32 cached_value;547};548 549struct lock_data {550 union {551 acpi_handle aml;552 /* global lock handle */553 u32 glk;554 } mutex;555 bool (*lock)(struct lock_data *data);556 bool (*unlock)(struct lock_data *data);557};558 559/*560 * The next function pairs implement options for locking access to the561 * state and the EC562 */563static bool lock_via_acpi_mutex(struct lock_data *data)564{565 /*566 * ASUS DSDT does not specify that access to the EC has to be guarded,567 * but firmware does access it via ACPI568 */569 return ACPI_SUCCESS(acpi_acquire_mutex(data->mutex.aml,570 NULL, ACPI_LOCK_DELAY_MS));571}572 573static bool unlock_acpi_mutex(struct lock_data *data)574{575 return ACPI_SUCCESS(acpi_release_mutex(data->mutex.aml, NULL));576}577 578static bool lock_via_global_acpi_lock(struct lock_data *data)579{580 return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS,581 &data->mutex.glk));582}583 584static bool unlock_global_acpi_lock(struct lock_data *data)585{586 return ACPI_SUCCESS(acpi_release_global_lock(data->mutex.glk));587}588 589struct ec_sensors_data {590 const struct ec_board_info *board_info;591 const struct ec_sensor_info *sensors_info;592 struct ec_sensor *sensors;593 /* EC registers to read from */594 u16 *registers;595 u8 *read_buffer;596 /* sorted list of unique register banks */597 u8 banks[ASUS_EC_MAX_BANK + 1];598 /* in jiffies */599 unsigned long last_updated;600 struct lock_data lock_data;601 /* number of board EC sensors */602 u8 nr_sensors;603 /*604 * number of EC registers to read605 * (sensor might span more than 1 register)606 */607 u8 nr_registers;608 /* number of unique register banks */609 u8 nr_banks;610};611 612static u8 register_bank(u16 reg)613{614 return reg >> 8;615}616 617static u8 register_index(u16 reg)618{619 return reg & 0x00ff;620}621 622static bool is_sensor_data_signed(const struct ec_sensor_info *si)623{624 /*625 * guessed from WMI functions in DSDT code for boards626 * of the X470 generation627 */628 return si->type == hwmon_temp;629}630 631static const struct ec_sensor_info *632get_sensor_info(const struct ec_sensors_data *state, int index)633{634 return state->sensors_info + state->sensors[index].info_index;635}636 637static int find_ec_sensor_index(const struct ec_sensors_data *ec,638 enum hwmon_sensor_types type, int channel)639{640 unsigned int i;641 642 for (i = 0; i < ec->nr_sensors; i++) {643 if (get_sensor_info(ec, i)->type == type) {644 if (channel == 0)645 return i;646 channel--;647 }648 }649 return -ENOENT;650}651 652static int bank_compare(const void *a, const void *b)653{654 return *((const s8 *)a) - *((const s8 *)b);655}656 657static void setup_sensor_data(struct ec_sensors_data *ec)658{659 struct ec_sensor *s = ec->sensors;660 bool bank_found;661 int i, j;662 u8 bank;663 664 ec->nr_banks = 0;665 ec->nr_registers = 0;666 667 for_each_set_bit(i, &ec->board_info->sensors,668 BITS_PER_TYPE(ec->board_info->sensors)) {669 s->info_index = i;670 s->cached_value = 0;671 ec->nr_registers +=672 ec->sensors_info[s->info_index].addr.components.size;673 bank_found = false;674 bank = ec->sensors_info[s->info_index].addr.components.bank;675 for (j = 0; j < ec->nr_banks; j++) {676 if (ec->banks[j] == bank) {677 bank_found = true;678 break;679 }680 }681 if (!bank_found) {682 ec->banks[ec->nr_banks++] = bank;683 }684 s++;685 }686 sort(ec->banks, ec->nr_banks, 1, bank_compare, NULL);687}688 689static void fill_ec_registers(struct ec_sensors_data *ec)690{691 const struct ec_sensor_info *si;692 unsigned int i, j, register_idx = 0;693 694 for (i = 0; i < ec->nr_sensors; ++i) {695 si = get_sensor_info(ec, i);696 for (j = 0; j < si->addr.components.size; ++j, ++register_idx) {697 ec->registers[register_idx] =698 (si->addr.components.bank << 8) +699 si->addr.components.index + j;700 }701 }702}703 704static int setup_lock_data(struct device *dev)705{706 const char *mutex_path;707 int status;708 struct ec_sensors_data *state = dev_get_drvdata(dev);709 710 mutex_path = mutex_path_override ?711 mutex_path_override : state->board_info->mutex_path;712 713 if (!mutex_path || !strlen(mutex_path)) {714 dev_err(dev, "Hardware access guard mutex name is empty");715 return -EINVAL;716 }717 if (!strcmp(mutex_path, ACPI_GLOBAL_LOCK_PSEUDO_PATH)) {718 state->lock_data.mutex.glk = 0;719 state->lock_data.lock = lock_via_global_acpi_lock;720 state->lock_data.unlock = unlock_global_acpi_lock;721 } else {722 status = acpi_get_handle(NULL, (acpi_string)mutex_path,723 &state->lock_data.mutex.aml);724 if (ACPI_FAILURE(status)) {725 dev_err(dev,726 "Failed to get hardware access guard AML mutex '%s': error %d",727 mutex_path, status);728 return -ENOENT;729 }730 state->lock_data.lock = lock_via_acpi_mutex;731 state->lock_data.unlock = unlock_acpi_mutex;732 }733 return 0;734}735 736static int asus_ec_bank_switch(u8 bank, u8 *old)737{738 int status = 0;739 740 if (old) {741 status = ec_read(ASUS_EC_BANK_REGISTER, old);742 }743 if (status || (old && (*old == bank)))744 return status;745 return ec_write(ASUS_EC_BANK_REGISTER, bank);746}747 748static int asus_ec_block_read(const struct device *dev,749 struct ec_sensors_data *ec)750{751 int ireg, ibank, status;752 u8 bank, reg_bank, prev_bank;753 754 bank = 0;755 status = asus_ec_bank_switch(bank, &prev_bank);756 if (status) {757 dev_warn(dev, "EC bank switch failed");758 return status;759 }760 761 if (prev_bank) {762 /* oops... somebody else is working with the EC too */763 dev_warn(dev,764 "Concurrent access to the ACPI EC detected.\nRace condition possible.");765 }766 767 /* read registers minimizing bank switches. */768 for (ibank = 0; ibank < ec->nr_banks; ibank++) {769 if (bank != ec->banks[ibank]) {770 bank = ec->banks[ibank];771 if (asus_ec_bank_switch(bank, NULL)) {772 dev_warn(dev, "EC bank switch to %d failed",773 bank);774 break;775 }776 }777 for (ireg = 0; ireg < ec->nr_registers; ireg++) {778 reg_bank = register_bank(ec->registers[ireg]);779 if (reg_bank < bank) {780 continue;781 }782 ec_read(register_index(ec->registers[ireg]),783 ec->read_buffer + ireg);784 }785 }786 787 status = asus_ec_bank_switch(prev_bank, NULL);788 return status;789}790 791static inline s32 get_sensor_value(const struct ec_sensor_info *si, u8 *data)792{793 if (is_sensor_data_signed(si)) {794 switch (si->addr.components.size) {795 case 1:796 return (s8)*data;797 case 2:798 return (s16)get_unaligned_be16(data);799 case 4:800 return (s32)get_unaligned_be32(data);801 default:802 return 0;803 }804 } else {805 switch (si->addr.components.size) {806 case 1:807 return *data;808 case 2:809 return get_unaligned_be16(data);810 case 4:811 return get_unaligned_be32(data);812 default:813 return 0;814 }815 }816}817 818static void update_sensor_values(struct ec_sensors_data *ec, u8 *data)819{820 const struct ec_sensor_info *si;821 struct ec_sensor *s, *sensor_end;822 823 sensor_end = ec->sensors + ec->nr_sensors;824 for (s = ec->sensors; s != sensor_end; s++) {825 si = ec->sensors_info + s->info_index;826 s->cached_value = get_sensor_value(si, data);827 data += si->addr.components.size;828 }829}830 831static int update_ec_sensors(const struct device *dev,832 struct ec_sensors_data *ec)833{834 int status;835 836 if (!ec->lock_data.lock(&ec->lock_data)) {837 dev_warn(dev, "Failed to acquire mutex");838 return -EBUSY;839 }840 841 status = asus_ec_block_read(dev, ec);842 843 if (!status) {844 update_sensor_values(ec, ec->read_buffer);845 }846 847 if (!ec->lock_data.unlock(&ec->lock_data))848 dev_err(dev, "Failed to release mutex");849 850 return status;851}852 853static long scale_sensor_value(s32 value, int data_type)854{855 switch (data_type) {856 case hwmon_curr:857 case hwmon_temp:858 return value * MILLI;859 default:860 return value;861 }862}863 864static int get_cached_value_or_update(const struct device *dev,865 int sensor_index,866 struct ec_sensors_data *state, s32 *value)867{868 if (time_after(jiffies, state->last_updated + HZ)) {869 if (update_ec_sensors(dev, state)) {870 dev_err(dev, "update_ec_sensors() failure\n");871 return -EIO;872 }873 874 state->last_updated = jiffies;875 }876 877 *value = state->sensors[sensor_index].cached_value;878 return 0;879}880 881/*882 * Now follow the functions that implement the hwmon interface883 */884 885static int asus_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,886 u32 attr, int channel, long *val)887{888 int ret;889 s32 value = 0;890 891 struct ec_sensors_data *state = dev_get_drvdata(dev);892 int sidx = find_ec_sensor_index(state, type, channel);893 894 if (sidx < 0) {895 return sidx;896 }897 898 ret = get_cached_value_or_update(dev, sidx, state, &value);899 if (!ret) {900 *val = scale_sensor_value(value,901 get_sensor_info(state, sidx)->type);902 }903 904 return ret;905}906 907static int asus_ec_hwmon_read_string(struct device *dev,908 enum hwmon_sensor_types type, u32 attr,909 int channel, const char **str)910{911 struct ec_sensors_data *state = dev_get_drvdata(dev);912 int sensor_index = find_ec_sensor_index(state, type, channel);913 *str = get_sensor_info(state, sensor_index)->label;914 915 return 0;916}917 918static umode_t asus_ec_hwmon_is_visible(const void *drvdata,919 enum hwmon_sensor_types type, u32 attr,920 int channel)921{922 const struct ec_sensors_data *state = drvdata;923 924 return find_ec_sensor_index(state, type, channel) >= 0 ? S_IRUGO : 0;925}926 927static int928asus_ec_hwmon_add_chan_info(struct hwmon_channel_info *asus_ec_hwmon_chan,929 struct device *dev, int num,930 enum hwmon_sensor_types type, u32 config)931{932 int i;933 u32 *cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL);934 935 if (!cfg)936 return -ENOMEM;937 938 asus_ec_hwmon_chan->type = type;939 asus_ec_hwmon_chan->config = cfg;940 for (i = 0; i < num; i++, cfg++)941 *cfg = config;942 943 return 0;944}945 946static const struct hwmon_ops asus_ec_hwmon_ops = {947 .is_visible = asus_ec_hwmon_is_visible,948 .read = asus_ec_hwmon_read,949 .read_string = asus_ec_hwmon_read_string,950};951 952static struct hwmon_chip_info asus_ec_chip_info = {953 .ops = &asus_ec_hwmon_ops,954};955 956static const struct ec_board_info *get_board_info(void)957{958 const struct dmi_system_id *dmi_entry;959 960 dmi_entry = dmi_first_match(dmi_table);961 return dmi_entry ? dmi_entry->driver_data : NULL;962}963 964static int asus_ec_probe(struct platform_device *pdev)965{966 const struct hwmon_channel_info **ptr_asus_ec_ci;967 int nr_count[hwmon_max] = { 0 }, nr_types = 0;968 struct hwmon_channel_info *asus_ec_hwmon_chan;969 const struct ec_board_info *pboard_info;970 const struct hwmon_chip_info *chip_info;971 struct device *dev = &pdev->dev;972 struct ec_sensors_data *ec_data;973 const struct ec_sensor_info *si;974 enum hwmon_sensor_types type;975 struct device *hwdev;976 unsigned int i;977 int status;978 979 pboard_info = get_board_info();980 if (!pboard_info)981 return -ENODEV;982 983 ec_data = devm_kzalloc(dev, sizeof(struct ec_sensors_data),984 GFP_KERNEL);985 if (!ec_data)986 return -ENOMEM;987 988 dev_set_drvdata(dev, ec_data);989 ec_data->board_info = pboard_info;990 991 switch (ec_data->board_info->family) {992 case family_amd_400_series:993 ec_data->sensors_info = sensors_family_amd_400;994 break;995 case family_amd_500_series:996 ec_data->sensors_info = sensors_family_amd_500;997 break;998 case family_amd_600_series:999 ec_data->sensors_info = sensors_family_amd_600;1000 break;1001 case family_intel_300_series:1002 ec_data->sensors_info = sensors_family_intel_300;1003 break;1004 case family_intel_600_series:1005 ec_data->sensors_info = sensors_family_intel_600;1006 break;1007 default:1008 dev_err(dev, "Unknown board family: %d",1009 ec_data->board_info->family);1010 return -EINVAL;1011 }1012 1013 ec_data->nr_sensors = hweight_long(ec_data->board_info->sensors);1014 ec_data->sensors = devm_kcalloc(dev, ec_data->nr_sensors,1015 sizeof(struct ec_sensor), GFP_KERNEL);1016 if (!ec_data->sensors)1017 return -ENOMEM;1018 1019 status = setup_lock_data(dev);1020 if (status) {1021 dev_err(dev, "Failed to setup state/EC locking: %d", status);1022 return status;1023 }1024 1025 setup_sensor_data(ec_data);1026 ec_data->registers = devm_kcalloc(dev, ec_data->nr_registers,1027 sizeof(u16), GFP_KERNEL);1028 ec_data->read_buffer = devm_kcalloc(dev, ec_data->nr_registers,1029 sizeof(u8), GFP_KERNEL);1030 1031 if (!ec_data->registers || !ec_data->read_buffer)1032 return -ENOMEM;1033 1034 fill_ec_registers(ec_data);1035 1036 for (i = 0; i < ec_data->nr_sensors; ++i) {1037 si = get_sensor_info(ec_data, i);1038 if (!nr_count[si->type])1039 ++nr_types;1040 ++nr_count[si->type];1041 }1042 1043 if (nr_count[hwmon_temp])1044 nr_count[hwmon_chip]++, nr_types++;1045 1046 asus_ec_hwmon_chan = devm_kcalloc(1047 dev, nr_types, sizeof(*asus_ec_hwmon_chan), GFP_KERNEL);1048 if (!asus_ec_hwmon_chan)1049 return -ENOMEM;1050 1051 ptr_asus_ec_ci = devm_kcalloc(dev, nr_types + 1,1052 sizeof(*ptr_asus_ec_ci), GFP_KERNEL);1053 if (!ptr_asus_ec_ci)1054 return -ENOMEM;1055 1056 asus_ec_chip_info.info = ptr_asus_ec_ci;1057 chip_info = &asus_ec_chip_info;1058 1059 for (type = 0; type < hwmon_max; ++type) {1060 if (!nr_count[type])1061 continue;1062 1063 asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,1064 nr_count[type], type,1065 hwmon_attributes[type]);1066 *ptr_asus_ec_ci++ = asus_ec_hwmon_chan++;1067 }1068 1069 dev_info(dev, "board has %d EC sensors that span %d registers",1070 ec_data->nr_sensors, ec_data->nr_registers);1071 1072 hwdev = devm_hwmon_device_register_with_info(dev, "asusec",1073 ec_data, chip_info, NULL);1074 1075 return PTR_ERR_OR_ZERO(hwdev);1076}1077 1078MODULE_DEVICE_TABLE(dmi, dmi_table);1079 1080static struct platform_driver asus_ec_sensors_platform_driver = {1081 .driver = {1082 .name = "asus-ec-sensors",1083 },1084 .probe = asus_ec_probe,1085};1086 1087static struct platform_device *asus_ec_sensors_platform_device;1088 1089static int __init asus_ec_init(void)1090{1091 asus_ec_sensors_platform_device =1092 platform_create_bundle(&asus_ec_sensors_platform_driver,1093 asus_ec_probe, NULL, 0, NULL, 0);1094 1095 if (IS_ERR(asus_ec_sensors_platform_device))1096 return PTR_ERR(asus_ec_sensors_platform_device);1097 1098 return 0;1099}1100 1101static void __exit asus_ec_exit(void)1102{1103 platform_device_unregister(asus_ec_sensors_platform_device);1104 platform_driver_unregister(&asus_ec_sensors_platform_driver);1105}1106 1107module_init(asus_ec_init);1108module_exit(asus_ec_exit);1109 1110module_param_named(mutex_path, mutex_path_override, charp, 0);1111MODULE_PARM_DESC(mutex_path,1112 "Override ACPI mutex path used to guard access to hardware");1113 1114MODULE_AUTHOR("Eugene Shalygin <eugene.shalygin@gmail.com>");1115MODULE_DESCRIPTION(1116 "HWMON driver for sensors accessible via ACPI EC in ASUS motherboards");1117MODULE_LICENSE("GPL");1118