1 // SPDX-License-Identifier: GPL-2.0+
3 * HWMON driver for ASUS motherboards that publish some sensor values
4 * via the embedded controller registers.
6 * Copyright (C) 2021 Eugene Shalygin <eugene.shalygin@gmail.com>
9 * - Chipset temperature
11 * - Motherboard temperature
12 * - T_Sensor temperature
14 * - Water In temperature
15 * - Water Out temperature
16 * - CPU Optional fan RPM
18 * - VRM Heat Sink fan RPM
19 * - Water Flow fan RPM
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>
37 #include <linux/unaligned.h>
39 static char *mutex_path_override
;
41 /* Writing to this EC register switches EC bank */
42 #define ASUS_EC_BANK_REGISTER 0xff
43 #define SENSOR_LABEL_LEN 16
46 * Arbitrary set max. allowed bank number. Required for sorting banks and
47 * currently is overkill with just 2 banks used at max, but for the sake
48 * of alignment let's set it to a higher value.
50 #define ASUS_EC_MAX_BANK 3
52 #define ACPI_LOCK_DELAY_MS 500
54 /* ACPI mutex for locking access to the EC for the firmware */
55 #define ASUS_HW_ACCESS_MUTEX_ASMX "\\AMW0.ASMX"
57 #define ASUS_HW_ACCESS_MUTEX_RMTW_ASMX "\\RMTW.ASMX"
59 #define ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0 "\\_SB_.PCI0.SBRG.SIO1.MUT0"
61 #define MAX_IDENTICAL_BOARD_VARIATIONS 3
63 /* Moniker for the ACPI global lock (':' is not allowed in ASL identifiers) */
64 #define ACPI_GLOBAL_LOCK_PSEUDO_PATH ":GLOBAL_LOCK"
76 #define MAKE_SENSOR_ADDRESS(size, bank, index) { \
77 .value = (size << 16) + (bank << 8) + index \
80 static 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
,
88 struct ec_sensor_info
{
89 char label
[SENSOR_LABEL_LEN
];
90 enum hwmon_sensor_types type
;
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), \
100 /* chipset temperature [℃] */
101 ec_sensor_temp_chipset
,
102 /* CPU temperature [℃] */
104 /* CPU package temperature [℃] */
105 ec_sensor_temp_cpu_package
,
106 /* motherboard temperature [℃] */
108 /* "T_Sensor" temperature sensor reading [℃] */
109 ec_sensor_temp_t_sensor
,
110 /* VRM temperature [℃] */
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] */
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
,
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)
165 family_amd_400_series
,
166 family_amd_500_series
,
167 family_amd_600_series
,
168 family_intel_300_series
,
169 family_intel_600_series
172 /* All the known sensors for ASUS EC controllers */
173 static 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),
203 static 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),
240 static 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),
255 static 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),
275 static 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),
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)
288 struct ec_board_info
{
289 unsigned long sensors
;
291 * Defines which mutex to use for guarding access to the state and the
292 * hardware. Can be either a full path to an AML mutex or the
293 * 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 to
295 * the hardware is not guarded.
297 const char *mutex_path
;
298 enum board_family family
;
301 static 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
|
305 SENSOR_CURR_CPU
| SENSOR_IN_CPU_CORE
,
306 .mutex_path
= ACPI_GLOBAL_LOCK_PSEUDO_PATH
,
307 .family
= family_amd_400_series
,
310 static 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
,
317 static 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
,
325 static 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
,
333 static const struct ec_board_info board_info_pro_art_b550_creator
= {
334 .sensors
= SENSOR_SET_TEMP_CHIPSET_CPU_MB
|
335 SENSOR_TEMP_T_SENSOR
|
337 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
338 .family
= family_amd_500_series
,
341 static 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
,
349 static 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
,
357 static 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
,
365 static 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
,
375 static 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
|
382 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
383 .family
= family_amd_500_series
,
386 static 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
,
395 static 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
|
400 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
401 .family
= family_amd_500_series
,
404 static 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
|
408 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
409 .family
= family_amd_500_series
,
412 static 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
|
417 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
418 .family
= family_amd_500_series
,
421 static 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
|
426 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
427 .family
= family_amd_500_series
,
430 static 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
|
434 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
435 .family
= family_amd_500_series
,
438 static 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
,
445 static 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
,
454 static const struct ec_board_info board_info_strix_z390_f_gaming
= {
455 .sensors
= SENSOR_TEMP_CHIPSET
| SENSOR_TEMP_VRM
|
456 SENSOR_TEMP_T_SENSOR
|
458 .mutex_path
= ASUS_HW_ACCESS_MUTEX_ASMX
,
459 .family
= family_intel_300_series
,
462 static 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
,
468 static 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
,
480 #define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, board_info) \
483 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, \
484 "ASUSTeK COMPUTER INC."), \
485 DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
487 .driver_data = (void *)board_info, \
490 static 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
),
545 unsigned int info_index
;
552 /* global lock handle */
555 bool (*lock
)(struct lock_data
*data
);
556 bool (*unlock
)(struct lock_data
*data
);
560 * The next function pairs implement options for locking access to the
563 static bool lock_via_acpi_mutex(struct lock_data
*data
)
566 * ASUS DSDT does not specify that access to the EC has to be guarded,
567 * but firmware does access it via ACPI
569 return ACPI_SUCCESS(acpi_acquire_mutex(data
->mutex
.aml
,
570 NULL
, ACPI_LOCK_DELAY_MS
));
573 static bool unlock_acpi_mutex(struct lock_data
*data
)
575 return ACPI_SUCCESS(acpi_release_mutex(data
->mutex
.aml
, NULL
));
578 static bool lock_via_global_acpi_lock(struct lock_data
*data
)
580 return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS
,
584 static bool unlock_global_acpi_lock(struct lock_data
*data
)
586 return ACPI_SUCCESS(acpi_release_global_lock(data
->mutex
.glk
));
589 struct 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 */
596 /* sorted list of unique register banks */
597 u8 banks
[ASUS_EC_MAX_BANK
+ 1];
599 unsigned long last_updated
;
600 struct lock_data lock_data
;
601 /* number of board EC sensors */
604 * number of EC registers to read
605 * (sensor might span more than 1 register)
608 /* number of unique register banks */
612 static u8
register_bank(u16 reg
)
617 static u8
register_index(u16 reg
)
622 static bool is_sensor_data_signed(const struct ec_sensor_info
*si
)
625 * guessed from WMI functions in DSDT code for boards
626 * of the X470 generation
628 return si
->type
== hwmon_temp
;
631 static const struct ec_sensor_info
*
632 get_sensor_info(const struct ec_sensors_data
*state
, int index
)
634 return state
->sensors_info
+ state
->sensors
[index
].info_index
;
637 static int find_ec_sensor_index(const struct ec_sensors_data
*ec
,
638 enum hwmon_sensor_types type
, int channel
)
642 for (i
= 0; i
< ec
->nr_sensors
; i
++) {
643 if (get_sensor_info(ec
, i
)->type
== type
) {
652 static int bank_compare(const void *a
, const void *b
)
654 return *((const s8
*)a
) - *((const s8
*)b
);
657 static void setup_sensor_data(struct ec_sensors_data
*ec
)
659 struct ec_sensor
*s
= ec
->sensors
;
665 ec
->nr_registers
= 0;
667 for_each_set_bit(i
, &ec
->board_info
->sensors
,
668 BITS_PER_TYPE(ec
->board_info
->sensors
)) {
672 ec
->sensors_info
[s
->info_index
].addr
.components
.size
;
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
) {
682 ec
->banks
[ec
->nr_banks
++] = bank
;
686 sort(ec
->banks
, ec
->nr_banks
, 1, bank_compare
, NULL
);
689 static void fill_ec_registers(struct ec_sensors_data
*ec
)
691 const struct ec_sensor_info
*si
;
692 unsigned int i
, j
, register_idx
= 0;
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
;
704 static int setup_lock_data(struct device
*dev
)
706 const char *mutex_path
;
708 struct ec_sensors_data
*state
= dev_get_drvdata(dev
);
710 mutex_path
= mutex_path_override
?
711 mutex_path_override
: state
->board_info
->mutex_path
;
713 if (!mutex_path
|| !strlen(mutex_path
)) {
714 dev_err(dev
, "Hardware access guard mutex name is empty");
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
;
722 status
= acpi_get_handle(NULL
, (acpi_string
)mutex_path
,
723 &state
->lock_data
.mutex
.aml
);
724 if (ACPI_FAILURE(status
)) {
726 "Failed to get hardware access guard AML mutex '%s': error %d",
730 state
->lock_data
.lock
= lock_via_acpi_mutex
;
731 state
->lock_data
.unlock
= unlock_acpi_mutex
;
736 static int asus_ec_bank_switch(u8 bank
, u8
*old
)
741 status
= ec_read(ASUS_EC_BANK_REGISTER
, old
);
743 if (status
|| (old
&& (*old
== bank
)))
745 return ec_write(ASUS_EC_BANK_REGISTER
, bank
);
748 static int asus_ec_block_read(const struct device
*dev
,
749 struct ec_sensors_data
*ec
)
751 int ireg
, ibank
, status
;
752 u8 bank
, reg_bank
, prev_bank
;
755 status
= asus_ec_bank_switch(bank
, &prev_bank
);
757 dev_warn(dev
, "EC bank switch failed");
762 /* oops... somebody else is working with the EC too */
764 "Concurrent access to the ACPI EC detected.\nRace condition possible.");
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",
777 for (ireg
= 0; ireg
< ec
->nr_registers
; ireg
++) {
778 reg_bank
= register_bank(ec
->registers
[ireg
]);
779 if (reg_bank
< bank
) {
782 ec_read(register_index(ec
->registers
[ireg
]),
783 ec
->read_buffer
+ ireg
);
787 status
= asus_ec_bank_switch(prev_bank
, NULL
);
791 static inline s32
get_sensor_value(const struct ec_sensor_info
*si
, u8
*data
)
793 if (is_sensor_data_signed(si
)) {
794 switch (si
->addr
.components
.size
) {
798 return (s16
)get_unaligned_be16(data
);
800 return (s32
)get_unaligned_be32(data
);
805 switch (si
->addr
.components
.size
) {
809 return get_unaligned_be16(data
);
811 return get_unaligned_be32(data
);
818 static void update_sensor_values(struct ec_sensors_data
*ec
, u8
*data
)
820 const struct ec_sensor_info
*si
;
821 struct ec_sensor
*s
, *sensor_end
;
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
;
831 static int update_ec_sensors(const struct device
*dev
,
832 struct ec_sensors_data
*ec
)
836 if (!ec
->lock_data
.lock(&ec
->lock_data
)) {
837 dev_warn(dev
, "Failed to acquire mutex");
841 status
= asus_ec_block_read(dev
, ec
);
844 update_sensor_values(ec
, ec
->read_buffer
);
847 if (!ec
->lock_data
.unlock(&ec
->lock_data
))
848 dev_err(dev
, "Failed to release mutex");
853 static long scale_sensor_value(s32 value
, int data_type
)
858 return value
* MILLI
;
864 static int get_cached_value_or_update(const struct device
*dev
,
866 struct ec_sensors_data
*state
, s32
*value
)
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");
874 state
->last_updated
= jiffies
;
877 *value
= state
->sensors
[sensor_index
].cached_value
;
882 * Now follow the functions that implement the hwmon interface
885 static int asus_ec_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
886 u32 attr
, int channel
, long *val
)
891 struct ec_sensors_data
*state
= dev_get_drvdata(dev
);
892 int sidx
= find_ec_sensor_index(state
, type
, channel
);
898 ret
= get_cached_value_or_update(dev
, sidx
, state
, &value
);
900 *val
= scale_sensor_value(value
,
901 get_sensor_info(state
, sidx
)->type
);
907 static int asus_ec_hwmon_read_string(struct device
*dev
,
908 enum hwmon_sensor_types type
, u32 attr
,
909 int channel
, const char **str
)
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
;
918 static umode_t
asus_ec_hwmon_is_visible(const void *drvdata
,
919 enum hwmon_sensor_types type
, u32 attr
,
922 const struct ec_sensors_data
*state
= drvdata
;
924 return find_ec_sensor_index(state
, type
, channel
) >= 0 ? S_IRUGO
: 0;
928 asus_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
)
933 u32
*cfg
= devm_kcalloc(dev
, num
+ 1, sizeof(*cfg
), GFP_KERNEL
);
938 asus_ec_hwmon_chan
->type
= type
;
939 asus_ec_hwmon_chan
->config
= cfg
;
940 for (i
= 0; i
< num
; i
++, cfg
++)
946 static 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
,
952 static struct hwmon_chip_info asus_ec_chip_info
= {
953 .ops
= &asus_ec_hwmon_ops
,
956 static const struct ec_board_info
*get_board_info(void)
958 const struct dmi_system_id
*dmi_entry
;
960 dmi_entry
= dmi_first_match(dmi_table
);
961 return dmi_entry
? dmi_entry
->driver_data
: NULL
;
964 static int asus_ec_probe(struct platform_device
*pdev
)
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
;
979 pboard_info
= get_board_info();
983 ec_data
= devm_kzalloc(dev
, sizeof(struct ec_sensors_data
),
988 dev_set_drvdata(dev
, ec_data
);
989 ec_data
->board_info
= pboard_info
;
991 switch (ec_data
->board_info
->family
) {
992 case family_amd_400_series
:
993 ec_data
->sensors_info
= sensors_family_amd_400
;
995 case family_amd_500_series
:
996 ec_data
->sensors_info
= sensors_family_amd_500
;
998 case family_amd_600_series
:
999 ec_data
->sensors_info
= sensors_family_amd_600
;
1001 case family_intel_300_series
:
1002 ec_data
->sensors_info
= sensors_family_intel_300
;
1004 case family_intel_600_series
:
1005 ec_data
->sensors_info
= sensors_family_intel_600
;
1008 dev_err(dev
, "Unknown board family: %d",
1009 ec_data
->board_info
->family
);
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
)
1019 status
= setup_lock_data(dev
);
1021 dev_err(dev
, "Failed to setup state/EC locking: %d", status
);
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
);
1031 if (!ec_data
->registers
|| !ec_data
->read_buffer
)
1034 fill_ec_registers(ec_data
);
1036 for (i
= 0; i
< ec_data
->nr_sensors
; ++i
) {
1037 si
= get_sensor_info(ec_data
, i
);
1038 if (!nr_count
[si
->type
])
1040 ++nr_count
[si
->type
];
1043 if (nr_count
[hwmon_temp
])
1044 nr_count
[hwmon_chip
]++, nr_types
++;
1046 asus_ec_hwmon_chan
= devm_kcalloc(
1047 dev
, nr_types
, sizeof(*asus_ec_hwmon_chan
), GFP_KERNEL
);
1048 if (!asus_ec_hwmon_chan
)
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
)
1056 asus_ec_chip_info
.info
= ptr_asus_ec_ci
;
1057 chip_info
= &asus_ec_chip_info
;
1059 for (type
= 0; type
< hwmon_max
; ++type
) {
1060 if (!nr_count
[type
])
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
++;
1069 dev_info(dev
, "board has %d EC sensors that span %d registers",
1070 ec_data
->nr_sensors
, ec_data
->nr_registers
);
1072 hwdev
= devm_hwmon_device_register_with_info(dev
, "asusec",
1073 ec_data
, chip_info
, NULL
);
1075 return PTR_ERR_OR_ZERO(hwdev
);
1078 MODULE_DEVICE_TABLE(dmi
, dmi_table
);
1080 static struct platform_driver asus_ec_sensors_platform_driver
= {
1082 .name
= "asus-ec-sensors",
1084 .probe
= asus_ec_probe
,
1087 static struct platform_device
*asus_ec_sensors_platform_device
;
1089 static int __init
asus_ec_init(void)
1091 asus_ec_sensors_platform_device
=
1092 platform_create_bundle(&asus_ec_sensors_platform_driver
,
1093 asus_ec_probe
, NULL
, 0, NULL
, 0);
1095 if (IS_ERR(asus_ec_sensors_platform_device
))
1096 return PTR_ERR(asus_ec_sensors_platform_device
);
1101 static void __exit
asus_ec_exit(void)
1103 platform_device_unregister(asus_ec_sensors_platform_device
);
1104 platform_driver_unregister(&asus_ec_sensors_platform_driver
);
1107 module_init(asus_ec_init
);
1108 module_exit(asus_ec_exit
);
1110 module_param_named(mutex_path
, mutex_path_override
, charp
, 0);
1111 MODULE_PARM_DESC(mutex_path
,
1112 "Override ACPI mutex path used to guard access to hardware");
1114 MODULE_AUTHOR("Eugene Shalygin <eugene.shalygin@gmail.com>");
1116 "HWMON driver for sensors accessible via ACPI EC in ASUS motherboards");
1117 MODULE_LICENSE("GPL");