asus-ec-sensors.c 30 KB

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