Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * HWMON driver for ASUS motherboards that publish some sensor values
4 * via the embedded controller registers.
5 *
6 * Copyright (C) 2021 Eugene Shalygin <eugene.shalygin@gmail.com>
7
8 * EC provides:
9 * - Chipset temperature
10 * - CPU temperature
11 * - Motherboard temperature
12 * - T_Sensor temperature
13 * - VRM temperature
14 * - Water In temperature
15 * - Water Out temperature
16 * - CPU Optional fan RPM
17 * - Chipset fan RPM
18 * - VRM Heat Sink fan RPM
19 * - Water Flow fan RPM
20 * - CPU current
21 * - CPU core voltage
22 */
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 0xff
43#define SENSOR_LABEL_LEN 16
44
45/*
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.
49 */
50#define ASUS_EC_MAX_BANK 3
51
52#define ACPI_LOCK_DELAY_MS 500
53
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 3
62
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_series
170};
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 [ec_sensor_fan_cpu_opt] =
254 EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
255};
256
257static const struct ec_sensor_info sensors_family_intel_300[] = {
258 [ec_sensor_temp_chipset] =
259 EC_SENSOR("Chipset", hwmon_temp, 1, 0x00, 0x3a),
260 [ec_sensor_temp_cpu] = EC_SENSOR("CPU", hwmon_temp, 1, 0x00, 0x3b),
261 [ec_sensor_temp_mb] =
262 EC_SENSOR("Motherboard", hwmon_temp, 1, 0x00, 0x3c),
263 [ec_sensor_temp_t_sensor] =
264 EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
265 [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
266 [ec_sensor_fan_cpu_opt] =
267 EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0),
268 [ec_sensor_fan_vrm_hs] = EC_SENSOR("VRM HS", hwmon_fan, 2, 0x00, 0xb2),
269 [ec_sensor_fan_water_flow] =
270 EC_SENSOR("Water_Flow", hwmon_fan, 2, 0x00, 0xbc),
271 [ec_sensor_temp_water_in] =
272 EC_SENSOR("Water_In", hwmon_temp, 1, 0x01, 0x00),
273 [ec_sensor_temp_water_out] =
274 EC_SENSOR("Water_Out", hwmon_temp, 1, 0x01, 0x01),
275};
276
277static const struct ec_sensor_info sensors_family_intel_600[] = {
278 [ec_sensor_temp_t_sensor] =
279 EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x3d),
280 [ec_sensor_temp_vrm] = EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x3e),
281};
282
283/* Shortcuts for common combinations */
284#define SENSOR_SET_TEMP_CHIPSET_CPU_MB \
285 (SENSOR_TEMP_CHIPSET | SENSOR_TEMP_CPU | SENSOR_TEMP_MB)
286#define SENSOR_SET_TEMP_WATER (SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT)
287#define SENSOR_SET_WATER_BLOCK \
288 (SENSOR_TEMP_WATER_BLOCK_IN | SENSOR_TEMP_WATER_BLOCK_OUT)
289
290struct ec_board_info {
291 unsigned long sensors;
292 /*
293 * Defines which mutex to use for guarding access to the state and the
294 * hardware. Can be either a full path to an AML mutex or the
295 * pseudo-path ACPI_GLOBAL_LOCK_PSEUDO_PATH to use the global ACPI lock,
296 * or left empty to use a regular mutex object, in which case access to
297 * the hardware is not guarded.
298 */
299 const char *mutex_path;
300 enum board_family family;
301};
302
303static const struct ec_board_info board_info_prime_x470_pro = {
304 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
305 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
306 SENSOR_FAN_CPU_OPT |
307 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
308 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
309 .family = family_amd_400_series,
310};
311
312static const struct ec_board_info board_info_prime_x570_pro = {
313 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
314 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
315 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
316 .family = family_amd_500_series,
317};
318
319static const struct ec_board_info board_info_prime_x670e_pro_wifi = {
320 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
321 SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
322 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT,
323 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
324 .family = family_amd_600_series,
325};
326
327static const struct ec_board_info board_info_pro_art_x570_creator_wifi = {
328 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
329 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT |
330 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
331 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
332 .family = family_amd_500_series,
333};
334
335static const struct ec_board_info board_info_pro_art_x670E_creator_wifi = {
336 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
337 SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
338 SENSOR_TEMP_T_SENSOR,
339 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
340 .family = family_amd_600_series,
341};
342
343static const struct ec_board_info board_info_pro_art_b550_creator = {
344 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
345 SENSOR_TEMP_T_SENSOR |
346 SENSOR_FAN_CPU_OPT,
347 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
348 .family = family_amd_500_series,
349};
350
351static const struct ec_board_info board_info_pro_ws_x570_ace = {
352 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_VRM |
353 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET |
354 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
355 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
356 .family = family_amd_500_series,
357};
358
359static const struct ec_board_info board_info_crosshair_x670e_hero = {
360 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
361 SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
362 SENSOR_SET_TEMP_WATER,
363 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
364 .family = family_amd_600_series,
365};
366
367static const struct ec_board_info board_info_crosshair_x670e_gene = {
368 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
369 SENSOR_TEMP_T_SENSOR |
370 SENSOR_TEMP_MB | SENSOR_TEMP_VRM,
371 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
372 .family = family_amd_600_series,
373};
374
375static const struct ec_board_info board_info_crosshair_viii_dark_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_WATER_FLOW |
380 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
381 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
382 .family = family_amd_500_series,
383};
384
385static const struct ec_board_info board_info_crosshair_viii_hero = {
386 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
387 SENSOR_TEMP_T_SENSOR |
388 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
389 SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET |
390 SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU |
391 SENSOR_IN_CPU_CORE,
392 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
393 .family = family_amd_500_series,
394};
395
396static const struct ec_board_info board_info_maximus_xi_hero = {
397 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
398 SENSOR_TEMP_T_SENSOR |
399 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
400 SENSOR_FAN_CPU_OPT | SENSOR_FAN_WATER_FLOW,
401 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
402 .family = family_intel_300_series,
403};
404
405static const struct ec_board_info board_info_crosshair_viii_impact = {
406 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
407 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
408 SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
409 SENSOR_IN_CPU_CORE,
410 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
411 .family = family_amd_500_series,
412};
413
414static const struct ec_board_info board_info_strix_b550_e_gaming = {
415 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
416 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
417 SENSOR_FAN_CPU_OPT,
418 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
419 .family = family_amd_500_series,
420};
421
422static const struct ec_board_info board_info_strix_b550_i_gaming = {
423 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
424 SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM |
425 SENSOR_FAN_VRM_HS | SENSOR_CURR_CPU |
426 SENSOR_IN_CPU_CORE,
427 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
428 .family = family_amd_500_series,
429};
430
431static const struct ec_board_info board_info_strix_x570_e_gaming = {
432 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
433 SENSOR_TEMP_T_SENSOR |
434 SENSOR_FAN_CHIPSET | SENSOR_CURR_CPU |
435 SENSOR_IN_CPU_CORE,
436 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
437 .family = family_amd_500_series,
438};
439
440static const struct ec_board_info board_info_strix_x570_e_gaming_wifi_ii = {
441 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
442 SENSOR_TEMP_T_SENSOR | SENSOR_CURR_CPU |
443 SENSOR_IN_CPU_CORE,
444 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
445 .family = family_amd_500_series,
446};
447
448static const struct ec_board_info board_info_strix_x570_f_gaming = {
449 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB |
450 SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CHIPSET,
451 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
452 .family = family_amd_500_series,
453};
454
455static const struct ec_board_info board_info_strix_x570_i_gaming = {
456 .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
457 SENSOR_TEMP_T_SENSOR |
458 SENSOR_FAN_VRM_HS | SENSOR_FAN_CHIPSET |
459 SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE,
460 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
461 .family = family_amd_500_series,
462};
463
464static const struct ec_board_info board_info_strix_z390_f_gaming = {
465 .sensors = SENSOR_TEMP_CHIPSET | SENSOR_TEMP_VRM |
466 SENSOR_TEMP_T_SENSOR |
467 SENSOR_FAN_CPU_OPT,
468 .mutex_path = ASUS_HW_ACCESS_MUTEX_ASMX,
469 .family = family_intel_300_series,
470};
471
472static const struct ec_board_info board_info_strix_z690_a_gaming_wifi_d4 = {
473 .sensors = SENSOR_TEMP_T_SENSOR | SENSOR_TEMP_VRM,
474 .mutex_path = ASUS_HW_ACCESS_MUTEX_RMTW_ASMX,
475 .family = family_intel_600_series,
476};
477
478static const struct ec_board_info board_info_zenith_ii_extreme = {
479 .sensors = SENSOR_SET_TEMP_CHIPSET_CPU_MB | SENSOR_TEMP_T_SENSOR |
480 SENSOR_TEMP_VRM | SENSOR_SET_TEMP_WATER |
481 SENSOR_FAN_CPU_OPT | SENSOR_FAN_CHIPSET | SENSOR_FAN_VRM_HS |
482 SENSOR_FAN_WATER_FLOW | SENSOR_CURR_CPU | SENSOR_IN_CPU_CORE |
483 SENSOR_SET_WATER_BLOCK |
484 SENSOR_TEMP_T_SENSOR_2 | SENSOR_TEMP_SENSOR_EXTRA_1 |
485 SENSOR_TEMP_SENSOR_EXTRA_2 | SENSOR_TEMP_SENSOR_EXTRA_3,
486 .mutex_path = ASUS_HW_ACCESS_MUTEX_SB_PCI0_SBRG_SIO1_MUT0,
487 .family = family_amd_500_series,
488};
489
490static const struct ec_board_info board_info_tuf_gaming_x670e_plus = {
491 .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE |
492 SENSOR_TEMP_MB | SENSOR_TEMP_VRM |
493 SENSOR_TEMP_WATER_IN | SENSOR_TEMP_WATER_OUT |
494 SENSOR_FAN_CPU_OPT,
495 .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH,
496 .family = family_amd_600_series,
497};
498
499#define DMI_EXACT_MATCH_ASUS_BOARD_NAME(name, board_info) \
500 { \
501 .matches = { \
502 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, \
503 "ASUSTeK COMPUTER INC."), \
504 DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
505 }, \
506 .driver_data = (void *)board_info, \
507 }
508
509static const struct dmi_system_id dmi_table[] = {
510 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X470-PRO",
511 &board_info_prime_x470_pro),
512 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X570-PRO",
513 &board_info_prime_x570_pro),
514 DMI_EXACT_MATCH_ASUS_BOARD_NAME("PRIME X670E-PRO WIFI",
515 &board_info_prime_x670e_pro_wifi),
516 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X570-CREATOR WIFI",
517 &board_info_pro_art_x570_creator_wifi),
518 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt X670E-CREATOR WIFI",
519 &board_info_pro_art_x670E_creator_wifi),
520 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ProArt B550-CREATOR",
521 &board_info_pro_art_b550_creator),
522 DMI_EXACT_MATCH_ASUS_BOARD_NAME("Pro WS X570-ACE",
523 &board_info_pro_ws_x570_ace),
524 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII DARK HERO",
525 &board_info_crosshair_viii_dark_hero),
526 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII FORMULA",
527 &board_info_crosshair_viii_hero),
528 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO",
529 &board_info_crosshair_viii_hero),
530 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII HERO (WI-FI)",
531 &board_info_crosshair_viii_hero),
532 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E HERO",
533 &board_info_crosshair_x670e_hero),
534 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR X670E GENE",
535 &board_info_crosshair_x670e_gene),
536 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO",
537 &board_info_maximus_xi_hero),
538 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG MAXIMUS XI HERO (WI-FI)",
539 &board_info_maximus_xi_hero),
540 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG CROSSHAIR VIII IMPACT",
541 &board_info_crosshair_viii_impact),
542 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-E GAMING",
543 &board_info_strix_b550_e_gaming),
544 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX B550-I GAMING",
545 &board_info_strix_b550_i_gaming),
546 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING",
547 &board_info_strix_x570_e_gaming),
548 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-E GAMING WIFI II",
549 &board_info_strix_x570_e_gaming_wifi_ii),
550 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-F GAMING",
551 &board_info_strix_x570_f_gaming),
552 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX X570-I GAMING",
553 &board_info_strix_x570_i_gaming),
554 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z390-F GAMING",
555 &board_info_strix_z390_f_gaming),
556 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG STRIX Z690-A GAMING WIFI D4",
557 &board_info_strix_z690_a_gaming_wifi_d4),
558 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME",
559 &board_info_zenith_ii_extreme),
560 DMI_EXACT_MATCH_ASUS_BOARD_NAME("ROG ZENITH II EXTREME ALPHA",
561 &board_info_zenith_ii_extreme),
562 DMI_EXACT_MATCH_ASUS_BOARD_NAME("TUF GAMING X670E-PLUS",
563 &board_info_tuf_gaming_x670e_plus),
564 {},
565};
566
567struct ec_sensor {
568 unsigned int info_index;
569 s32 cached_value;
570};
571
572struct lock_data {
573 union {
574 acpi_handle aml;
575 /* global lock handle */
576 u32 glk;
577 } mutex;
578 bool (*lock)(struct lock_data *data);
579 bool (*unlock)(struct lock_data *data);
580};
581
582/*
583 * The next function pairs implement options for locking access to the
584 * state and the EC
585 */
586static bool lock_via_acpi_mutex(struct lock_data *data)
587{
588 /*
589 * ASUS DSDT does not specify that access to the EC has to be guarded,
590 * but firmware does access it via ACPI
591 */
592 return ACPI_SUCCESS(acpi_acquire_mutex(data->mutex.aml,
593 NULL, ACPI_LOCK_DELAY_MS));
594}
595
596static bool unlock_acpi_mutex(struct lock_data *data)
597{
598 return ACPI_SUCCESS(acpi_release_mutex(data->mutex.aml, NULL));
599}
600
601static bool lock_via_global_acpi_lock(struct lock_data *data)
602{
603 return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS,
604 &data->mutex.glk));
605}
606
607static bool unlock_global_acpi_lock(struct lock_data *data)
608{
609 return ACPI_SUCCESS(acpi_release_global_lock(data->mutex.glk));
610}
611
612struct ec_sensors_data {
613 const struct ec_board_info *board_info;
614 const struct ec_sensor_info *sensors_info;
615 struct ec_sensor *sensors;
616 /* EC registers to read from */
617 u16 *registers;
618 u8 *read_buffer;
619 /* sorted list of unique register banks */
620 u8 banks[ASUS_EC_MAX_BANK + 1];
621 /* in jiffies */
622 unsigned long last_updated;
623 struct lock_data lock_data;
624 /* number of board EC sensors */
625 u8 nr_sensors;
626 /*
627 * number of EC registers to read
628 * (sensor might span more than 1 register)
629 */
630 u8 nr_registers;
631 /* number of unique register banks */
632 u8 nr_banks;
633};
634
635static u8 register_bank(u16 reg)
636{
637 return reg >> 8;
638}
639
640static u8 register_index(u16 reg)
641{
642 return reg & 0x00ff;
643}
644
645static bool is_sensor_data_signed(const struct ec_sensor_info *si)
646{
647 /*
648 * guessed from WMI functions in DSDT code for boards
649 * of the X470 generation
650 */
651 return si->type == hwmon_temp;
652}
653
654static const struct ec_sensor_info *
655get_sensor_info(const struct ec_sensors_data *state, int index)
656{
657 return state->sensors_info + state->sensors[index].info_index;
658}
659
660static int find_ec_sensor_index(const struct ec_sensors_data *ec,
661 enum hwmon_sensor_types type, int channel)
662{
663 unsigned int i;
664
665 for (i = 0; i < ec->nr_sensors; i++) {
666 if (get_sensor_info(ec, i)->type == type) {
667 if (channel == 0)
668 return i;
669 channel--;
670 }
671 }
672 return -ENOENT;
673}
674
675static int bank_compare(const void *a, const void *b)
676{
677 return *((const s8 *)a) - *((const s8 *)b);
678}
679
680static void setup_sensor_data(struct ec_sensors_data *ec)
681{
682 struct ec_sensor *s = ec->sensors;
683 bool bank_found;
684 int i, j;
685 u8 bank;
686
687 ec->nr_banks = 0;
688 ec->nr_registers = 0;
689
690 for_each_set_bit(i, &ec->board_info->sensors,
691 BITS_PER_TYPE(ec->board_info->sensors)) {
692 s->info_index = i;
693 s->cached_value = 0;
694 ec->nr_registers +=
695 ec->sensors_info[s->info_index].addr.components.size;
696 bank_found = false;
697 bank = ec->sensors_info[s->info_index].addr.components.bank;
698 for (j = 0; j < ec->nr_banks; j++) {
699 if (ec->banks[j] == bank) {
700 bank_found = true;
701 break;
702 }
703 }
704 if (!bank_found) {
705 ec->banks[ec->nr_banks++] = bank;
706 }
707 s++;
708 }
709 sort(ec->banks, ec->nr_banks, 1, bank_compare, NULL);
710}
711
712static void fill_ec_registers(struct ec_sensors_data *ec)
713{
714 const struct ec_sensor_info *si;
715 unsigned int i, j, register_idx = 0;
716
717 for (i = 0; i < ec->nr_sensors; ++i) {
718 si = get_sensor_info(ec, i);
719 for (j = 0; j < si->addr.components.size; ++j, ++register_idx) {
720 ec->registers[register_idx] =
721 (si->addr.components.bank << 8) +
722 si->addr.components.index + j;
723 }
724 }
725}
726
727static int setup_lock_data(struct device *dev)
728{
729 const char *mutex_path;
730 int status;
731 struct ec_sensors_data *state = dev_get_drvdata(dev);
732
733 mutex_path = mutex_path_override ?
734 mutex_path_override : state->board_info->mutex_path;
735
736 if (!mutex_path || !strlen(mutex_path)) {
737 dev_err(dev, "Hardware access guard mutex name is empty");
738 return -EINVAL;
739 }
740 if (!strcmp(mutex_path, ACPI_GLOBAL_LOCK_PSEUDO_PATH)) {
741 state->lock_data.mutex.glk = 0;
742 state->lock_data.lock = lock_via_global_acpi_lock;
743 state->lock_data.unlock = unlock_global_acpi_lock;
744 } else {
745 status = acpi_get_handle(NULL, (acpi_string)mutex_path,
746 &state->lock_data.mutex.aml);
747 if (ACPI_FAILURE(status)) {
748 dev_err(dev,
749 "Failed to get hardware access guard AML mutex '%s': error %d",
750 mutex_path, status);
751 return -ENOENT;
752 }
753 state->lock_data.lock = lock_via_acpi_mutex;
754 state->lock_data.unlock = unlock_acpi_mutex;
755 }
756 return 0;
757}
758
759static int asus_ec_bank_switch(u8 bank, u8 *old)
760{
761 int status = 0;
762
763 if (old) {
764 status = ec_read(ASUS_EC_BANK_REGISTER, old);
765 }
766 if (status || (old && (*old == bank)))
767 return status;
768 return ec_write(ASUS_EC_BANK_REGISTER, bank);
769}
770
771static int asus_ec_block_read(const struct device *dev,
772 struct ec_sensors_data *ec)
773{
774 int ireg, ibank, status;
775 u8 bank, reg_bank, prev_bank;
776
777 bank = 0;
778 status = asus_ec_bank_switch(bank, &prev_bank);
779 if (status) {
780 dev_warn(dev, "EC bank switch failed");
781 return status;
782 }
783
784 if (prev_bank) {
785 /* oops... somebody else is working with the EC too */
786 dev_warn(dev,
787 "Concurrent access to the ACPI EC detected.\nRace condition possible.");
788 }
789
790 /* read registers minimizing bank switches. */
791 for (ibank = 0; ibank < ec->nr_banks; ibank++) {
792 if (bank != ec->banks[ibank]) {
793 bank = ec->banks[ibank];
794 if (asus_ec_bank_switch(bank, NULL)) {
795 dev_warn(dev, "EC bank switch to %d failed",
796 bank);
797 break;
798 }
799 }
800 for (ireg = 0; ireg < ec->nr_registers; ireg++) {
801 reg_bank = register_bank(ec->registers[ireg]);
802 if (reg_bank < bank) {
803 continue;
804 }
805 ec_read(register_index(ec->registers[ireg]),
806 ec->read_buffer + ireg);
807 }
808 }
809
810 status = asus_ec_bank_switch(prev_bank, NULL);
811 return status;
812}
813
814static inline s32 get_sensor_value(const struct ec_sensor_info *si, u8 *data)
815{
816 if (is_sensor_data_signed(si)) {
817 switch (si->addr.components.size) {
818 case 1:
819 return (s8)*data;
820 case 2:
821 return (s16)get_unaligned_be16(data);
822 case 4:
823 return (s32)get_unaligned_be32(data);
824 default:
825 return 0;
826 }
827 } else {
828 switch (si->addr.components.size) {
829 case 1:
830 return *data;
831 case 2:
832 return get_unaligned_be16(data);
833 case 4:
834 return get_unaligned_be32(data);
835 default:
836 return 0;
837 }
838 }
839}
840
841static void update_sensor_values(struct ec_sensors_data *ec, u8 *data)
842{
843 const struct ec_sensor_info *si;
844 struct ec_sensor *s, *sensor_end;
845
846 sensor_end = ec->sensors + ec->nr_sensors;
847 for (s = ec->sensors; s != sensor_end; s++) {
848 si = ec->sensors_info + s->info_index;
849 s->cached_value = get_sensor_value(si, data);
850 data += si->addr.components.size;
851 }
852}
853
854static int update_ec_sensors(const struct device *dev,
855 struct ec_sensors_data *ec)
856{
857 int status;
858
859 if (!ec->lock_data.lock(&ec->lock_data)) {
860 dev_warn(dev, "Failed to acquire mutex");
861 return -EBUSY;
862 }
863
864 status = asus_ec_block_read(dev, ec);
865
866 if (!status) {
867 update_sensor_values(ec, ec->read_buffer);
868 }
869
870 if (!ec->lock_data.unlock(&ec->lock_data))
871 dev_err(dev, "Failed to release mutex");
872
873 return status;
874}
875
876static long scale_sensor_value(s32 value, int data_type)
877{
878 switch (data_type) {
879 case hwmon_curr:
880 case hwmon_temp:
881 return value * MILLI;
882 default:
883 return value;
884 }
885}
886
887static int get_cached_value_or_update(const struct device *dev,
888 int sensor_index,
889 struct ec_sensors_data *state, s32 *value)
890{
891 if (time_after(jiffies, state->last_updated + HZ)) {
892 if (update_ec_sensors(dev, state)) {
893 dev_err(dev, "update_ec_sensors() failure\n");
894 return -EIO;
895 }
896
897 state->last_updated = jiffies;
898 }
899
900 *value = state->sensors[sensor_index].cached_value;
901 return 0;
902}
903
904/*
905 * Now follow the functions that implement the hwmon interface
906 */
907
908static int asus_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
909 u32 attr, int channel, long *val)
910{
911 int ret;
912 s32 value = 0;
913
914 struct ec_sensors_data *state = dev_get_drvdata(dev);
915 int sidx = find_ec_sensor_index(state, type, channel);
916
917 if (sidx < 0) {
918 return sidx;
919 }
920
921 ret = get_cached_value_or_update(dev, sidx, state, &value);
922 if (!ret) {
923 *val = scale_sensor_value(value,
924 get_sensor_info(state, sidx)->type);
925 }
926
927 return ret;
928}
929
930static int asus_ec_hwmon_read_string(struct device *dev,
931 enum hwmon_sensor_types type, u32 attr,
932 int channel, const char **str)
933{
934 struct ec_sensors_data *state = dev_get_drvdata(dev);
935 int sensor_index = find_ec_sensor_index(state, type, channel);
936 *str = get_sensor_info(state, sensor_index)->label;
937
938 return 0;
939}
940
941static umode_t asus_ec_hwmon_is_visible(const void *drvdata,
942 enum hwmon_sensor_types type, u32 attr,
943 int channel)
944{
945 const struct ec_sensors_data *state = drvdata;
946
947 return find_ec_sensor_index(state, type, channel) >= 0 ? S_IRUGO : 0;
948}
949
950static int
951asus_ec_hwmon_add_chan_info(struct hwmon_channel_info *asus_ec_hwmon_chan,
952 struct device *dev, int num,
953 enum hwmon_sensor_types type, u32 config)
954{
955 int i;
956 u32 *cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL);
957
958 if (!cfg)
959 return -ENOMEM;
960
961 asus_ec_hwmon_chan->type = type;
962 asus_ec_hwmon_chan->config = cfg;
963 for (i = 0; i < num; i++, cfg++)
964 *cfg = config;
965
966 return 0;
967}
968
969static const struct hwmon_ops asus_ec_hwmon_ops = {
970 .is_visible = asus_ec_hwmon_is_visible,
971 .read = asus_ec_hwmon_read,
972 .read_string = asus_ec_hwmon_read_string,
973};
974
975static struct hwmon_chip_info asus_ec_chip_info = {
976 .ops = &asus_ec_hwmon_ops,
977};
978
979static const struct ec_board_info *get_board_info(void)
980{
981 const struct dmi_system_id *dmi_entry;
982
983 dmi_entry = dmi_first_match(dmi_table);
984 return dmi_entry ? dmi_entry->driver_data : NULL;
985}
986
987static int asus_ec_probe(struct platform_device *pdev)
988{
989 const struct hwmon_channel_info **ptr_asus_ec_ci;
990 int nr_count[hwmon_max] = { 0 }, nr_types = 0;
991 struct hwmon_channel_info *asus_ec_hwmon_chan;
992 const struct ec_board_info *pboard_info;
993 const struct hwmon_chip_info *chip_info;
994 struct device *dev = &pdev->dev;
995 struct ec_sensors_data *ec_data;
996 const struct ec_sensor_info *si;
997 enum hwmon_sensor_types type;
998 struct device *hwdev;
999 unsigned int i;
1000 int status;
1001
1002 pboard_info = get_board_info();
1003 if (!pboard_info)
1004 return -ENODEV;
1005
1006 ec_data = devm_kzalloc(dev, sizeof(struct ec_sensors_data),
1007 GFP_KERNEL);
1008 if (!ec_data)
1009 return -ENOMEM;
1010
1011 dev_set_drvdata(dev, ec_data);
1012 ec_data->board_info = pboard_info;
1013
1014 switch (ec_data->board_info->family) {
1015 case family_amd_400_series:
1016 ec_data->sensors_info = sensors_family_amd_400;
1017 break;
1018 case family_amd_500_series:
1019 ec_data->sensors_info = sensors_family_amd_500;
1020 break;
1021 case family_amd_600_series:
1022 ec_data->sensors_info = sensors_family_amd_600;
1023 break;
1024 case family_intel_300_series:
1025 ec_data->sensors_info = sensors_family_intel_300;
1026 break;
1027 case family_intel_600_series:
1028 ec_data->sensors_info = sensors_family_intel_600;
1029 break;
1030 default:
1031 dev_err(dev, "Unknown board family: %d",
1032 ec_data->board_info->family);
1033 return -EINVAL;
1034 }
1035
1036 ec_data->nr_sensors = hweight_long(ec_data->board_info->sensors);
1037 ec_data->sensors = devm_kcalloc(dev, ec_data->nr_sensors,
1038 sizeof(struct ec_sensor), GFP_KERNEL);
1039 if (!ec_data->sensors)
1040 return -ENOMEM;
1041
1042 status = setup_lock_data(dev);
1043 if (status) {
1044 dev_err(dev, "Failed to setup state/EC locking: %d", status);
1045 return status;
1046 }
1047
1048 setup_sensor_data(ec_data);
1049 ec_data->registers = devm_kcalloc(dev, ec_data->nr_registers,
1050 sizeof(u16), GFP_KERNEL);
1051 ec_data->read_buffer = devm_kcalloc(dev, ec_data->nr_registers,
1052 sizeof(u8), GFP_KERNEL);
1053
1054 if (!ec_data->registers || !ec_data->read_buffer)
1055 return -ENOMEM;
1056
1057 fill_ec_registers(ec_data);
1058
1059 for (i = 0; i < ec_data->nr_sensors; ++i) {
1060 si = get_sensor_info(ec_data, i);
1061 if (!nr_count[si->type])
1062 ++nr_types;
1063 ++nr_count[si->type];
1064 }
1065
1066 if (nr_count[hwmon_temp])
1067 nr_count[hwmon_chip]++, nr_types++;
1068
1069 asus_ec_hwmon_chan = devm_kcalloc(
1070 dev, nr_types, sizeof(*asus_ec_hwmon_chan), GFP_KERNEL);
1071 if (!asus_ec_hwmon_chan)
1072 return -ENOMEM;
1073
1074 ptr_asus_ec_ci = devm_kcalloc(dev, nr_types + 1,
1075 sizeof(*ptr_asus_ec_ci), GFP_KERNEL);
1076 if (!ptr_asus_ec_ci)
1077 return -ENOMEM;
1078
1079 asus_ec_chip_info.info = ptr_asus_ec_ci;
1080 chip_info = &asus_ec_chip_info;
1081
1082 for (type = 0; type < hwmon_max; ++type) {
1083 if (!nr_count[type])
1084 continue;
1085
1086 asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
1087 nr_count[type], type,
1088 hwmon_attributes[type]);
1089 *ptr_asus_ec_ci++ = asus_ec_hwmon_chan++;
1090 }
1091
1092 dev_info(dev, "board has %d EC sensors that span %d registers",
1093 ec_data->nr_sensors, ec_data->nr_registers);
1094
1095 hwdev = devm_hwmon_device_register_with_info(dev, "asusec",
1096 ec_data, chip_info, NULL);
1097
1098 return PTR_ERR_OR_ZERO(hwdev);
1099}
1100
1101MODULE_DEVICE_TABLE(dmi, dmi_table);
1102
1103static struct platform_driver asus_ec_sensors_platform_driver = {
1104 .driver = {
1105 .name = "asus-ec-sensors",
1106 },
1107 .probe = asus_ec_probe,
1108};
1109
1110static struct platform_device *asus_ec_sensors_platform_device;
1111
1112static int __init asus_ec_init(void)
1113{
1114 asus_ec_sensors_platform_device =
1115 platform_create_bundle(&asus_ec_sensors_platform_driver,
1116 asus_ec_probe, NULL, 0, NULL, 0);
1117
1118 if (IS_ERR(asus_ec_sensors_platform_device))
1119 return PTR_ERR(asus_ec_sensors_platform_device);
1120
1121 return 0;
1122}
1123
1124static void __exit asus_ec_exit(void)
1125{
1126 platform_device_unregister(asus_ec_sensors_platform_device);
1127 platform_driver_unregister(&asus_ec_sensors_platform_driver);
1128}
1129
1130module_init(asus_ec_init);
1131module_exit(asus_ec_exit);
1132
1133module_param_named(mutex_path, mutex_path_override, charp, 0);
1134MODULE_PARM_DESC(mutex_path,
1135 "Override ACPI mutex path used to guard access to hardware");
1136
1137MODULE_AUTHOR("Eugene Shalygin <eugene.shalygin@gmail.com>");
1138MODULE_DESCRIPTION(
1139 "HWMON driver for sensors accessible via ACPI EC in ASUS motherboards");
1140MODULE_LICENSE("GPL");