brintos

brintos / linux-shallow public Read only

0
0
Text · 33.0 KiB · 9555366 Raw
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