msi-ec.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * msi-ec: MSI laptops' embedded controller driver.
  4. *
  5. * This driver allows various MSI laptops' functionalities to be
  6. * controlled from userspace.
  7. *
  8. * It contains EC memory configurations for different firmware versions
  9. * and exports battery charge thresholds to userspace.
  10. *
  11. * Copyright (C) 2023 Jose Angel Pastrana <japp0005@red.ujaen.es>
  12. * Copyright (C) 2023 Aakash Singh <mail@singhaakash.dev>
  13. * Copyright (C) 2023 Nikita Kravets <teackot@gmail.com>
  14. */
  15. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  16. #include "msi-ec.h"
  17. #include <acpi/battery.h>
  18. #include <linux/acpi.h>
  19. #include <linux/init.h>
  20. #include <linux/kernel.h>
  21. #include <linux/module.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/seq_file.h>
  24. #include <linux/string.h>
  25. #define SM_ECO_NAME "eco"
  26. #define SM_COMFORT_NAME "comfort"
  27. #define SM_SPORT_NAME "sport"
  28. #define SM_TURBO_NAME "turbo"
  29. #define FM_AUTO_NAME "auto"
  30. #define FM_SILENT_NAME "silent"
  31. #define FM_BASIC_NAME "basic"
  32. #define FM_ADVANCED_NAME "advanced"
  33. static const char * const ALLOWED_FW_0[] __initconst = {
  34. "14C1EMS1.012",
  35. "14C1EMS1.101",
  36. "14C1EMS1.102",
  37. NULL
  38. };
  39. static struct msi_ec_conf CONF0 __initdata = {
  40. .allowed_fw = ALLOWED_FW_0,
  41. .charge_control = {
  42. .address = 0xef,
  43. .offset_start = 0x8a,
  44. .offset_end = 0x80,
  45. .range_min = 0x8a,
  46. .range_max = 0xe4,
  47. },
  48. .webcam = {
  49. .address = 0x2e,
  50. .block_address = 0x2f,
  51. .bit = 1,
  52. },
  53. .fn_win_swap = {
  54. .address = 0xbf,
  55. .bit = 4,
  56. },
  57. .cooler_boost = {
  58. .address = 0x98,
  59. .bit = 7,
  60. },
  61. .shift_mode = {
  62. .address = 0xf2,
  63. .modes = {
  64. { SM_ECO_NAME, 0xc2 },
  65. { SM_COMFORT_NAME, 0xc1 },
  66. { SM_SPORT_NAME, 0xc0 },
  67. MSI_EC_MODE_NULL
  68. },
  69. },
  70. .super_battery = {
  71. .address = MSI_EC_ADDR_UNKNOWN, // 0xd5 needs testing
  72. },
  73. .fan_mode = {
  74. .address = 0xf4,
  75. .modes = {
  76. { FM_AUTO_NAME, 0x0d },
  77. { FM_SILENT_NAME, 0x1d },
  78. { FM_BASIC_NAME, 0x4d },
  79. { FM_ADVANCED_NAME, 0x8d },
  80. MSI_EC_MODE_NULL
  81. },
  82. },
  83. .cpu = {
  84. .rt_temp_address = 0x68,
  85. .rt_fan_speed_address = 0x71,
  86. .rt_fan_speed_base_min = 0x19,
  87. .rt_fan_speed_base_max = 0x37,
  88. .bs_fan_speed_address = 0x89,
  89. .bs_fan_speed_base_min = 0x00,
  90. .bs_fan_speed_base_max = 0x0f,
  91. },
  92. .gpu = {
  93. .rt_temp_address = 0x80,
  94. .rt_fan_speed_address = 0x89,
  95. },
  96. .leds = {
  97. .micmute_led_address = 0x2b,
  98. .mute_led_address = 0x2c,
  99. .bit = 2,
  100. },
  101. .kbd_bl = {
  102. .bl_mode_address = 0x2c, // ?
  103. .bl_modes = { 0x00, 0x08 }, // ?
  104. .max_mode = 1, // ?
  105. .bl_state_address = 0xf3,
  106. .state_base_value = 0x80,
  107. .max_state = 3,
  108. },
  109. };
  110. static const char * const ALLOWED_FW_1[] __initconst = {
  111. "17F2EMS1.103",
  112. "17F2EMS1.104",
  113. "17F2EMS1.106",
  114. "17F2EMS1.107",
  115. NULL
  116. };
  117. static struct msi_ec_conf CONF1 __initdata = {
  118. .allowed_fw = ALLOWED_FW_1,
  119. .charge_control = {
  120. .address = 0xef,
  121. .offset_start = 0x8a,
  122. .offset_end = 0x80,
  123. .range_min = 0x8a,
  124. .range_max = 0xe4,
  125. },
  126. .webcam = {
  127. .address = 0x2e,
  128. .block_address = 0x2f,
  129. .bit = 1,
  130. },
  131. .fn_win_swap = {
  132. .address = 0xbf,
  133. .bit = 4,
  134. },
  135. .cooler_boost = {
  136. .address = 0x98,
  137. .bit = 7,
  138. },
  139. .shift_mode = {
  140. .address = 0xf2,
  141. .modes = {
  142. { SM_ECO_NAME, 0xc2 },
  143. { SM_COMFORT_NAME, 0xc1 },
  144. { SM_SPORT_NAME, 0xc0 },
  145. { SM_TURBO_NAME, 0xc4 },
  146. MSI_EC_MODE_NULL
  147. },
  148. },
  149. .super_battery = {
  150. .address = MSI_EC_ADDR_UNKNOWN,
  151. },
  152. .fan_mode = {
  153. .address = 0xf4,
  154. .modes = {
  155. { FM_AUTO_NAME, 0x0d },
  156. { FM_BASIC_NAME, 0x4d },
  157. { FM_ADVANCED_NAME, 0x8d },
  158. MSI_EC_MODE_NULL
  159. },
  160. },
  161. .cpu = {
  162. .rt_temp_address = 0x68,
  163. .rt_fan_speed_address = 0x71,
  164. .rt_fan_speed_base_min = 0x19,
  165. .rt_fan_speed_base_max = 0x37,
  166. .bs_fan_speed_address = 0x89,
  167. .bs_fan_speed_base_min = 0x00,
  168. .bs_fan_speed_base_max = 0x0f,
  169. },
  170. .gpu = {
  171. .rt_temp_address = 0x80,
  172. .rt_fan_speed_address = 0x89,
  173. },
  174. .leds = {
  175. .micmute_led_address = 0x2b,
  176. .mute_led_address = 0x2c,
  177. .bit = 2,
  178. },
  179. .kbd_bl = {
  180. .bl_mode_address = 0x2c, // ?
  181. .bl_modes = { 0x00, 0x08 }, // ?
  182. .max_mode = 1, // ?
  183. .bl_state_address = 0xf3,
  184. .state_base_value = 0x80,
  185. .max_state = 3,
  186. },
  187. };
  188. static const char * const ALLOWED_FW_2[] __initconst = {
  189. "1552EMS1.118",
  190. NULL
  191. };
  192. static struct msi_ec_conf CONF2 __initdata = {
  193. .allowed_fw = ALLOWED_FW_2,
  194. .charge_control = {
  195. .address = 0xd7,
  196. .offset_start = 0x8a,
  197. .offset_end = 0x80,
  198. .range_min = 0x8a,
  199. .range_max = 0xe4,
  200. },
  201. .webcam = {
  202. .address = 0x2e,
  203. .block_address = 0x2f,
  204. .bit = 1,
  205. },
  206. .fn_win_swap = {
  207. .address = 0xe8,
  208. .bit = 4,
  209. },
  210. .cooler_boost = {
  211. .address = 0x98,
  212. .bit = 7,
  213. },
  214. .shift_mode = {
  215. .address = 0xf2,
  216. .modes = {
  217. { SM_ECO_NAME, 0xc2 },
  218. { SM_COMFORT_NAME, 0xc1 },
  219. { SM_SPORT_NAME, 0xc0 },
  220. MSI_EC_MODE_NULL
  221. },
  222. },
  223. .super_battery = {
  224. .address = 0xeb,
  225. .mask = 0x0f,
  226. },
  227. .fan_mode = {
  228. .address = 0xd4,
  229. .modes = {
  230. { FM_AUTO_NAME, 0x0d },
  231. { FM_SILENT_NAME, 0x1d },
  232. { FM_BASIC_NAME, 0x4d },
  233. { FM_ADVANCED_NAME, 0x8d },
  234. MSI_EC_MODE_NULL
  235. },
  236. },
  237. .cpu = {
  238. .rt_temp_address = 0x68,
  239. .rt_fan_speed_address = 0x71,
  240. .rt_fan_speed_base_min = 0x19,
  241. .rt_fan_speed_base_max = 0x37,
  242. .bs_fan_speed_address = 0x89,
  243. .bs_fan_speed_base_min = 0x00,
  244. .bs_fan_speed_base_max = 0x0f,
  245. },
  246. .gpu = {
  247. .rt_temp_address = 0x80,
  248. .rt_fan_speed_address = 0x89,
  249. },
  250. .leds = {
  251. .micmute_led_address = 0x2c,
  252. .mute_led_address = 0x2d,
  253. .bit = 1,
  254. },
  255. .kbd_bl = {
  256. .bl_mode_address = 0x2c, // ?
  257. .bl_modes = { 0x00, 0x08 }, // ?
  258. .max_mode = 1, // ?
  259. .bl_state_address = 0xd3,
  260. .state_base_value = 0x80,
  261. .max_state = 3,
  262. },
  263. };
  264. static const char * const ALLOWED_FW_3[] __initconst = {
  265. "1592EMS1.111",
  266. NULL
  267. };
  268. static struct msi_ec_conf CONF3 __initdata = {
  269. .allowed_fw = ALLOWED_FW_3,
  270. .charge_control = {
  271. .address = 0xd7,
  272. .offset_start = 0x8a,
  273. .offset_end = 0x80,
  274. .range_min = 0x8a,
  275. .range_max = 0xe4,
  276. },
  277. .webcam = {
  278. .address = 0x2e,
  279. .block_address = 0x2f,
  280. .bit = 1,
  281. },
  282. .fn_win_swap = {
  283. .address = 0xe8,
  284. .bit = 4,
  285. },
  286. .cooler_boost = {
  287. .address = 0x98,
  288. .bit = 7,
  289. },
  290. .shift_mode = {
  291. .address = 0xd2,
  292. .modes = {
  293. { SM_ECO_NAME, 0xc2 },
  294. { SM_COMFORT_NAME, 0xc1 },
  295. { SM_SPORT_NAME, 0xc0 },
  296. MSI_EC_MODE_NULL
  297. },
  298. },
  299. .super_battery = {
  300. .address = 0xeb,
  301. .mask = 0x0f,
  302. },
  303. .fan_mode = {
  304. .address = 0xd4,
  305. .modes = {
  306. { FM_AUTO_NAME, 0x0d },
  307. { FM_SILENT_NAME, 0x1d },
  308. { FM_BASIC_NAME, 0x4d },
  309. { FM_ADVANCED_NAME, 0x8d },
  310. MSI_EC_MODE_NULL
  311. },
  312. },
  313. .cpu = {
  314. .rt_temp_address = 0x68,
  315. .rt_fan_speed_address = 0xc9,
  316. .rt_fan_speed_base_min = 0x19,
  317. .rt_fan_speed_base_max = 0x37,
  318. .bs_fan_speed_address = 0x89, // ?
  319. .bs_fan_speed_base_min = 0x00,
  320. .bs_fan_speed_base_max = 0x0f,
  321. },
  322. .gpu = {
  323. .rt_temp_address = 0x80,
  324. .rt_fan_speed_address = 0x89,
  325. },
  326. .leds = {
  327. .micmute_led_address = 0x2b,
  328. .mute_led_address = 0x2c,
  329. .bit = 1,
  330. },
  331. .kbd_bl = {
  332. .bl_mode_address = 0x2c, // ?
  333. .bl_modes = { 0x00, 0x08 }, // ?
  334. .max_mode = 1, // ?
  335. .bl_state_address = 0xd3,
  336. .state_base_value = 0x80,
  337. .max_state = 3,
  338. },
  339. };
  340. static const char * const ALLOWED_FW_4[] __initconst = {
  341. "16V4EMS1.114",
  342. NULL
  343. };
  344. static struct msi_ec_conf CONF4 __initdata = {
  345. .allowed_fw = ALLOWED_FW_4,
  346. .charge_control = {
  347. .address = 0xd7,
  348. .offset_start = 0x8a,
  349. .offset_end = 0x80,
  350. .range_min = 0x8a,
  351. .range_max = 0xe4,
  352. },
  353. .webcam = {
  354. .address = 0x2e,
  355. .block_address = 0x2f,
  356. .bit = 1,
  357. },
  358. .fn_win_swap = {
  359. .address = MSI_EC_ADDR_UNKNOWN, // supported, but unknown
  360. .bit = 4,
  361. },
  362. .cooler_boost = {
  363. .address = 0x98,
  364. .bit = 7,
  365. },
  366. .shift_mode = {
  367. .address = 0xd2,
  368. .modes = {
  369. { SM_ECO_NAME, 0xc2 },
  370. { SM_COMFORT_NAME, 0xc1 },
  371. { SM_SPORT_NAME, 0xc0 },
  372. MSI_EC_MODE_NULL
  373. },
  374. },
  375. .super_battery = { // may be supported, but address is unknown
  376. .address = MSI_EC_ADDR_UNKNOWN,
  377. .mask = 0x0f,
  378. },
  379. .fan_mode = {
  380. .address = 0xd4,
  381. .modes = {
  382. { FM_AUTO_NAME, 0x0d },
  383. { FM_SILENT_NAME, 0x1d },
  384. { FM_ADVANCED_NAME, 0x8d },
  385. MSI_EC_MODE_NULL
  386. },
  387. },
  388. .cpu = {
  389. .rt_temp_address = 0x68, // needs testing
  390. .rt_fan_speed_address = 0x71, // needs testing
  391. .rt_fan_speed_base_min = 0x19,
  392. .rt_fan_speed_base_max = 0x37,
  393. .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
  394. .bs_fan_speed_base_min = 0x00,
  395. .bs_fan_speed_base_max = 0x0f,
  396. },
  397. .gpu = {
  398. .rt_temp_address = 0x80,
  399. .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
  400. },
  401. .leds = {
  402. .micmute_led_address = MSI_EC_ADDR_UNKNOWN,
  403. .mute_led_address = MSI_EC_ADDR_UNKNOWN,
  404. .bit = 1,
  405. },
  406. .kbd_bl = {
  407. .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
  408. .bl_modes = { 0x00, 0x08 }, // ?
  409. .max_mode = 1, // ?
  410. .bl_state_address = MSI_EC_ADDR_UNSUPP, // 0xd3, not functional
  411. .state_base_value = 0x80,
  412. .max_state = 3,
  413. },
  414. };
  415. static const char * const ALLOWED_FW_5[] __initconst = {
  416. "158LEMS1.103",
  417. "158LEMS1.105",
  418. "158LEMS1.106",
  419. NULL
  420. };
  421. static struct msi_ec_conf CONF5 __initdata = {
  422. .allowed_fw = ALLOWED_FW_5,
  423. .charge_control = {
  424. .address = 0xef,
  425. .offset_start = 0x8a,
  426. .offset_end = 0x80,
  427. .range_min = 0x8a,
  428. .range_max = 0xe4,
  429. },
  430. .webcam = {
  431. .address = 0x2e,
  432. .block_address = 0x2f,
  433. .bit = 1,
  434. },
  435. .fn_win_swap = { // todo: reverse
  436. .address = 0xbf,
  437. .bit = 4,
  438. },
  439. .cooler_boost = {
  440. .address = 0x98,
  441. .bit = 7,
  442. },
  443. .shift_mode = {
  444. .address = 0xf2,
  445. .modes = {
  446. { SM_ECO_NAME, 0xc2 },
  447. { SM_COMFORT_NAME, 0xc1 },
  448. { SM_TURBO_NAME, 0xc4 },
  449. MSI_EC_MODE_NULL
  450. },
  451. },
  452. .super_battery = { // unsupported?
  453. .address = MSI_EC_ADDR_UNKNOWN,
  454. .mask = 0x0f,
  455. },
  456. .fan_mode = {
  457. .address = 0xf4,
  458. .modes = {
  459. { FM_AUTO_NAME, 0x0d },
  460. { FM_SILENT_NAME, 0x1d },
  461. { FM_ADVANCED_NAME, 0x8d },
  462. MSI_EC_MODE_NULL
  463. },
  464. },
  465. .cpu = {
  466. .rt_temp_address = 0x68, // needs testing
  467. .rt_fan_speed_address = 0x71, // needs testing
  468. .rt_fan_speed_base_min = 0x19,
  469. .rt_fan_speed_base_max = 0x37,
  470. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  471. .bs_fan_speed_base_min = 0x00,
  472. .bs_fan_speed_base_max = 0x0f,
  473. },
  474. .gpu = {
  475. .rt_temp_address = MSI_EC_ADDR_UNKNOWN,
  476. .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
  477. },
  478. .leds = {
  479. .micmute_led_address = 0x2b,
  480. .mute_led_address = 0x2c,
  481. .bit = 2,
  482. },
  483. .kbd_bl = {
  484. .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
  485. .bl_modes = { 0x00, 0x08 }, // ?
  486. .max_mode = 1, // ?
  487. .bl_state_address = MSI_EC_ADDR_UNSUPP, // 0xf3, not functional
  488. .state_base_value = 0x80,
  489. .max_state = 3,
  490. },
  491. };
  492. static const char * const ALLOWED_FW_6[] __initconst = {
  493. "1542EMS1.102",
  494. "1542EMS1.104",
  495. NULL
  496. };
  497. static struct msi_ec_conf CONF6 __initdata = {
  498. .allowed_fw = ALLOWED_FW_6,
  499. .charge_control = {
  500. .address = 0xef,
  501. .offset_start = 0x8a,
  502. .offset_end = 0x80,
  503. .range_min = 0x8a,
  504. .range_max = 0xe4,
  505. },
  506. .webcam = {
  507. .address = 0x2e,
  508. .block_address = MSI_EC_ADDR_UNSUPP,
  509. .bit = 1,
  510. },
  511. .fn_win_swap = {
  512. .address = 0xbf, // todo: reverse
  513. .bit = 4,
  514. },
  515. .cooler_boost = {
  516. .address = 0x98,
  517. .bit = 7,
  518. },
  519. .shift_mode = {
  520. .address = 0xf2,
  521. .modes = {
  522. { SM_ECO_NAME, 0xc2 },
  523. { SM_COMFORT_NAME, 0xc1 },
  524. { SM_SPORT_NAME, 0xc0 },
  525. { SM_TURBO_NAME, 0xc4 },
  526. MSI_EC_MODE_NULL
  527. },
  528. },
  529. .super_battery = {
  530. .address = 0xd5,
  531. .mask = 0x0f,
  532. },
  533. .fan_mode = {
  534. .address = 0xf4,
  535. .modes = {
  536. { FM_AUTO_NAME, 0x0d },
  537. { FM_SILENT_NAME, 0x1d },
  538. { FM_ADVANCED_NAME, 0x8d },
  539. MSI_EC_MODE_NULL
  540. },
  541. },
  542. .cpu = {
  543. .rt_temp_address = 0x68,
  544. .rt_fan_speed_address = 0xc9,
  545. .rt_fan_speed_base_min = 0x19,
  546. .rt_fan_speed_base_max = 0x37,
  547. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  548. .bs_fan_speed_base_min = 0x00,
  549. .bs_fan_speed_base_max = 0x0f,
  550. },
  551. .gpu = {
  552. .rt_temp_address = 0x80,
  553. .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
  554. },
  555. .leds = {
  556. .micmute_led_address = MSI_EC_ADDR_UNSUPP,
  557. .mute_led_address = MSI_EC_ADDR_UNSUPP,
  558. .bit = 2,
  559. },
  560. .kbd_bl = {
  561. .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
  562. .bl_modes = { 0x00, 0x08 }, // ?
  563. .max_mode = 1, // ?
  564. .bl_state_address = MSI_EC_ADDR_UNSUPP, // 0xf3, not functional
  565. .state_base_value = 0x80,
  566. .max_state = 3,
  567. },
  568. };
  569. static const char * const ALLOWED_FW_7[] __initconst = {
  570. "17FKEMS1.108",
  571. "17FKEMS1.109",
  572. "17FKEMS1.10A",
  573. NULL
  574. };
  575. static struct msi_ec_conf CONF7 __initdata = {
  576. .allowed_fw = ALLOWED_FW_7,
  577. .charge_control = {
  578. .address = 0xef,
  579. .offset_start = 0x8a,
  580. .offset_end = 0x80,
  581. .range_min = 0x8a,
  582. .range_max = 0xe4,
  583. },
  584. .webcam = {
  585. .address = 0x2e,
  586. .block_address = MSI_EC_ADDR_UNSUPP,
  587. .bit = 1,
  588. },
  589. .fn_win_swap = {
  590. .address = 0xbf, // needs testing
  591. .bit = 4,
  592. },
  593. .cooler_boost = {
  594. .address = 0x98,
  595. .bit = 7,
  596. },
  597. .shift_mode = {
  598. .address = 0xf2,
  599. .modes = {
  600. { SM_ECO_NAME, 0xc2 },
  601. { SM_COMFORT_NAME, 0xc1 },
  602. { SM_SPORT_NAME, 0xc0 },
  603. { SM_TURBO_NAME, 0xc4 },
  604. MSI_EC_MODE_NULL
  605. },
  606. },
  607. .super_battery = {
  608. .address = MSI_EC_ADDR_UNKNOWN, // 0xd5 but has its own wet of modes
  609. .mask = 0x0f,
  610. },
  611. .fan_mode = {
  612. .address = 0xf4,
  613. .modes = {
  614. { FM_AUTO_NAME, 0x0d }, // d may not be relevant
  615. { FM_SILENT_NAME, 0x1d },
  616. { FM_ADVANCED_NAME, 0x8d },
  617. MSI_EC_MODE_NULL
  618. },
  619. },
  620. .cpu = {
  621. .rt_temp_address = 0x68,
  622. .rt_fan_speed_address = 0xc9, // needs testing
  623. .rt_fan_speed_base_min = 0x19,
  624. .rt_fan_speed_base_max = 0x37,
  625. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  626. .bs_fan_speed_base_min = 0x00,
  627. .bs_fan_speed_base_max = 0x0f,
  628. },
  629. .gpu = {
  630. .rt_temp_address = MSI_EC_ADDR_UNKNOWN,
  631. .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
  632. },
  633. .leds = {
  634. .micmute_led_address = MSI_EC_ADDR_UNSUPP,
  635. .mute_led_address = 0x2c,
  636. .bit = 2,
  637. },
  638. .kbd_bl = {
  639. .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
  640. .bl_modes = { 0x00, 0x08 }, // ?
  641. .max_mode = 1, // ?
  642. .bl_state_address = 0xf3,
  643. .state_base_value = 0x80,
  644. .max_state = 3,
  645. },
  646. };
  647. static const char * const ALLOWED_FW_8[] __initconst = {
  648. "14F1EMS1.115",
  649. NULL
  650. };
  651. static struct msi_ec_conf CONF8 __initdata = {
  652. .allowed_fw = ALLOWED_FW_8,
  653. .charge_control = {
  654. .address = 0xd7,
  655. .offset_start = 0x8a,
  656. .offset_end = 0x80,
  657. .range_min = 0x8a,
  658. .range_max = 0xe4,
  659. },
  660. .webcam = {
  661. .address = 0x2e,
  662. .block_address = MSI_EC_ADDR_UNSUPP,
  663. .bit = 1,
  664. },
  665. .fn_win_swap = {
  666. .address = 0xe8,
  667. .bit = 4,
  668. },
  669. .cooler_boost = {
  670. .address = 0x98,
  671. .bit = 7,
  672. },
  673. .shift_mode = {
  674. .address = 0xd2,
  675. .modes = {
  676. { SM_ECO_NAME, 0xc2 },
  677. { SM_COMFORT_NAME, 0xc1 },
  678. { SM_SPORT_NAME, 0xc0 },
  679. MSI_EC_MODE_NULL
  680. },
  681. },
  682. .super_battery = {
  683. .address = 0xeb,
  684. .mask = 0x0f,
  685. },
  686. .fan_mode = {
  687. .address = 0xd4,
  688. .modes = {
  689. { FM_AUTO_NAME, 0x0d },
  690. { FM_SILENT_NAME, 0x1d },
  691. { FM_BASIC_NAME, 0x4d },
  692. MSI_EC_MODE_NULL
  693. },
  694. },
  695. .cpu = {
  696. .rt_temp_address = 0x68,
  697. .rt_fan_speed_address = 0x71,
  698. .rt_fan_speed_base_min = 0x19,
  699. .rt_fan_speed_base_max = 0x37,
  700. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  701. .bs_fan_speed_base_min = 0x00,
  702. .bs_fan_speed_base_max = 0x0f,
  703. },
  704. .gpu = {
  705. .rt_temp_address = MSI_EC_ADDR_UNKNOWN,
  706. .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
  707. },
  708. .leds = {
  709. .micmute_led_address = MSI_EC_ADDR_UNSUPP,
  710. .mute_led_address = 0x2d,
  711. .bit = 1,
  712. },
  713. .kbd_bl = {
  714. .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
  715. .bl_modes = { 0x00, 0x08 }, // ?
  716. .max_mode = 1, // ?
  717. .bl_state_address = MSI_EC_ADDR_UNSUPP, // not functional
  718. .state_base_value = 0x80,
  719. .max_state = 3,
  720. },
  721. };
  722. static const char * const ALLOWED_FW_9[] __initconst = {
  723. "14JKEMS1.104",
  724. NULL
  725. };
  726. static struct msi_ec_conf CONF9 __initdata = {
  727. .allowed_fw = ALLOWED_FW_9,
  728. .charge_control = {
  729. .address = 0xef,
  730. .offset_start = 0x8a,
  731. .offset_end = 0x80,
  732. .range_min = 0x8a,
  733. .range_max = 0xe4,
  734. },
  735. .webcam = {
  736. .address = 0x2e,
  737. .block_address = 0x2f,
  738. .bit = 1,
  739. },
  740. .fn_win_swap = {
  741. .address = 0xbf,
  742. .bit = 4,
  743. },
  744. .cooler_boost = {
  745. .address = 0x98,
  746. .bit = 7,
  747. },
  748. .shift_mode = {
  749. .address = 0xf2,
  750. .modes = {
  751. { SM_ECO_NAME, 0xc2 },
  752. { SM_COMFORT_NAME, 0xc1 },
  753. { SM_SPORT_NAME, 0xc0 },
  754. MSI_EC_MODE_NULL
  755. },
  756. },
  757. .super_battery = {
  758. .address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift
  759. .mask = 0x0f,
  760. },
  761. .fan_mode = {
  762. .address = 0xf4,
  763. .modes = {
  764. { FM_AUTO_NAME, 0x0d },
  765. { FM_SILENT_NAME, 0x1d },
  766. { FM_ADVANCED_NAME, 0x8d },
  767. MSI_EC_MODE_NULL
  768. },
  769. },
  770. .cpu = {
  771. .rt_temp_address = 0x68,
  772. .rt_fan_speed_address = 0x71,
  773. .rt_fan_speed_base_min = 0x00,
  774. .rt_fan_speed_base_max = 0x96,
  775. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  776. .bs_fan_speed_base_min = 0x00,
  777. .bs_fan_speed_base_max = 0x0f,
  778. },
  779. .gpu = {
  780. .rt_temp_address = MSI_EC_ADDR_UNSUPP,
  781. .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  782. },
  783. .leds = {
  784. .micmute_led_address = 0x2b,
  785. .mute_led_address = 0x2c,
  786. .bit = 2,
  787. },
  788. .kbd_bl = {
  789. .bl_mode_address = MSI_EC_ADDR_UNSUPP, // not presented in MSI app
  790. .bl_modes = { 0x00, 0x08 },
  791. .max_mode = 1,
  792. .bl_state_address = 0xf3,
  793. .state_base_value = 0x80,
  794. .max_state = 3,
  795. },
  796. };
  797. static const char * const ALLOWED_FW_10[] __initconst = {
  798. "1582EMS1.107", // GF66 11UC
  799. NULL
  800. };
  801. static struct msi_ec_conf CONF10 __initdata = {
  802. .allowed_fw = ALLOWED_FW_10,
  803. .charge_control = {
  804. .address = 0xd7,
  805. .offset_start = 0x8a,
  806. .offset_end = 0x80,
  807. .range_min = 0x8a,
  808. .range_max = 0xe4,
  809. },
  810. .webcam = {
  811. .address = 0x2e,
  812. .block_address = 0x2f,
  813. .bit = 1,
  814. },
  815. .fn_win_swap = {
  816. .address = MSI_EC_ADDR_UNSUPP,
  817. .bit = 4,
  818. },
  819. .cooler_boost = {
  820. .address = 0x98,
  821. .bit = 7,
  822. },
  823. .shift_mode = {
  824. .address = 0xd2,
  825. .modes = {
  826. { SM_ECO_NAME, 0xc2 },
  827. { SM_COMFORT_NAME, 0xc1 },
  828. { SM_SPORT_NAME, 0xc0 },
  829. { SM_TURBO_NAME, 0xc4 },
  830. MSI_EC_MODE_NULL
  831. },
  832. },
  833. .super_battery = {
  834. .address = 0xe5,
  835. .mask = 0x0f,
  836. },
  837. .fan_mode = {
  838. .address = 0xd4,
  839. .modes = {
  840. { FM_AUTO_NAME, 0x0d },
  841. { FM_SILENT_NAME, 0x1d },
  842. { FM_ADVANCED_NAME, 0x8d },
  843. MSI_EC_MODE_NULL
  844. },
  845. },
  846. .cpu = {
  847. .rt_temp_address = 0x68,
  848. .rt_fan_speed_address = 0x71, // ?
  849. .rt_fan_speed_base_min = 0x19,
  850. .rt_fan_speed_base_max = 0x37,
  851. .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ?
  852. .bs_fan_speed_base_min = 0x00,
  853. .bs_fan_speed_base_max = 0x0f,
  854. },
  855. .gpu = {
  856. .rt_temp_address = 0x80,
  857. .rt_fan_speed_address = 0x89,
  858. },
  859. .leds = {
  860. .micmute_led_address = 0x2c,
  861. .mute_led_address = 0x2d,
  862. .bit = 1,
  863. },
  864. .kbd_bl = {
  865. .bl_mode_address = 0x2c,
  866. .bl_modes = { 0x00, 0x08 },
  867. .max_mode = 1,
  868. .bl_state_address = 0xd3,
  869. .state_base_value = 0x80,
  870. .max_state = 3,
  871. },
  872. };
  873. static const char * const ALLOWED_FW_11[] __initconst = {
  874. "16S6EMS1.111", // Prestige 15 a11scx
  875. "1552EMS1.115", // Modern 15 a11m
  876. NULL
  877. };
  878. static struct msi_ec_conf CONF11 __initdata = {
  879. .allowed_fw = ALLOWED_FW_11,
  880. .charge_control = {
  881. .address = 0xd7,
  882. .offset_start = 0x8a,
  883. .offset_end = 0x80,
  884. .range_min = 0x8a,
  885. .range_max = 0xe4,
  886. },
  887. .webcam = {
  888. .address = 0x2e,
  889. .block_address = MSI_EC_ADDR_UNKNOWN,
  890. .bit = 1,
  891. },
  892. .fn_win_swap = {
  893. .address = 0xe8,
  894. .bit = 4,
  895. },
  896. .cooler_boost = {
  897. .address = 0x98,
  898. .bit = 7,
  899. },
  900. .shift_mode = {
  901. .address = 0xd2,
  902. .modes = {
  903. { SM_ECO_NAME, 0xc2 },
  904. { SM_COMFORT_NAME, 0xc1 },
  905. { SM_SPORT_NAME, 0xc0 },
  906. MSI_EC_MODE_NULL
  907. },
  908. },
  909. .super_battery = {
  910. .address = 0xeb,
  911. .mask = 0x0f,
  912. },
  913. .fan_mode = {
  914. .address = 0xd4,
  915. .modes = {
  916. { FM_AUTO_NAME, 0x0d },
  917. { FM_SILENT_NAME, 0x1d },
  918. { FM_ADVANCED_NAME, 0x4d },
  919. MSI_EC_MODE_NULL
  920. },
  921. },
  922. .cpu = {
  923. .rt_temp_address = 0x68,
  924. .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  925. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  926. },
  927. .gpu = {
  928. .rt_temp_address = MSI_EC_ADDR_UNSUPP,
  929. .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  930. },
  931. .leds = {
  932. .micmute_led_address = 0x2c,
  933. .mute_led_address = 0x2d,
  934. .bit = 1,
  935. },
  936. .kbd_bl = {
  937. .bl_mode_address = MSI_EC_ADDR_UNKNOWN,
  938. .bl_modes = {}, // ?
  939. .max_mode = 1, // ?
  940. .bl_state_address = 0xd3,
  941. .state_base_value = 0x80,
  942. .max_state = 3,
  943. },
  944. };
  945. static const char * const ALLOWED_FW_12[] __initconst = {
  946. "16R6EMS1.104", // GF63 Thin 11UC
  947. NULL
  948. };
  949. static struct msi_ec_conf CONF12 __initdata = {
  950. .allowed_fw = ALLOWED_FW_12,
  951. .charge_control = {
  952. .address = 0xd7,
  953. .offset_start = 0x8a,
  954. .offset_end = 0x80,
  955. .range_min = 0x8a,
  956. .range_max = 0xe4,
  957. },
  958. .webcam = {
  959. .address = 0x2e,
  960. .block_address = 0x2f,
  961. .bit = 1,
  962. },
  963. .fn_win_swap = {
  964. .address = 0xe8,
  965. .bit = 4,
  966. },
  967. .cooler_boost = {
  968. .address = 0x98,
  969. .bit = 7,
  970. },
  971. .shift_mode = {
  972. .address = 0xd2,
  973. .modes = {
  974. { SM_ECO_NAME, 0xc2 },
  975. { SM_COMFORT_NAME, 0xc1 },
  976. { SM_SPORT_NAME, 0xc0 },
  977. { SM_TURBO_NAME, 0xc4 },
  978. MSI_EC_MODE_NULL
  979. },
  980. },
  981. .super_battery = {
  982. .address = MSI_EC_ADDR_UNSUPP, // 0xeb
  983. .mask = 0x0f, // 00, 0f
  984. },
  985. .fan_mode = {
  986. .address = 0xd4,
  987. .modes = {
  988. { FM_AUTO_NAME, 0x0d },
  989. { FM_SILENT_NAME, 0x1d },
  990. { FM_ADVANCED_NAME, 0x8d },
  991. MSI_EC_MODE_NULL
  992. },
  993. },
  994. .cpu = {
  995. .rt_temp_address = 0x68,
  996. .rt_fan_speed_address = 0x71,
  997. .rt_fan_speed_base_min = 0x19,
  998. .rt_fan_speed_base_max = 0x37,
  999. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  1000. .bs_fan_speed_base_min = 0x00,
  1001. .bs_fan_speed_base_max = 0x0f,
  1002. },
  1003. .gpu = {
  1004. .rt_temp_address = MSI_EC_ADDR_UNSUPP,
  1005. .rt_fan_speed_address = 0x89,
  1006. },
  1007. .leds = {
  1008. .micmute_led_address = MSI_EC_ADDR_UNSUPP,
  1009. .mute_led_address = 0x2d,
  1010. .bit = 1,
  1011. },
  1012. .kbd_bl = {
  1013. .bl_mode_address = MSI_EC_ADDR_UNKNOWN,
  1014. .bl_modes = { 0x00, 0x08 },
  1015. .max_mode = 1,
  1016. .bl_state_address = 0xd3,
  1017. .state_base_value = 0x80,
  1018. .max_state = 3,
  1019. },
  1020. };
  1021. static const char * const ALLOWED_FW_13[] __initconst = {
  1022. "1594EMS1.109", // MSI Prestige 16 Studio A13VE
  1023. NULL
  1024. };
  1025. static struct msi_ec_conf CONF13 __initdata = {
  1026. .allowed_fw = ALLOWED_FW_13,
  1027. .charge_control = {
  1028. .address = 0xd7,
  1029. .offset_start = 0x8a,
  1030. .offset_end = 0x80,
  1031. .range_min = 0x8a,
  1032. .range_max = 0xe4,
  1033. },
  1034. .webcam = {
  1035. .address = 0x2e,
  1036. .block_address = 0x2f,
  1037. .bit = 1,
  1038. },
  1039. .fn_win_swap = {
  1040. .address = 0xe8,
  1041. .bit = 4, // 0x00-0x10
  1042. },
  1043. .cooler_boost = {
  1044. .address = 0x98,
  1045. .bit = 7,
  1046. },
  1047. .shift_mode = {
  1048. .address = 0xd2,
  1049. .modes = {
  1050. { SM_ECO_NAME, 0xc2 }, // super battery
  1051. { SM_COMFORT_NAME, 0xc1 }, // balanced
  1052. { SM_TURBO_NAME, 0xc4 }, // extreme
  1053. MSI_EC_MODE_NULL
  1054. },
  1055. },
  1056. .super_battery = {
  1057. .address = MSI_EC_ADDR_UNSUPP,
  1058. .mask = 0x0f, // 00, 0f
  1059. },
  1060. .fan_mode = {
  1061. .address = 0xd4,
  1062. .modes = {
  1063. { FM_AUTO_NAME, 0x0d },
  1064. { FM_SILENT_NAME, 0x1d },
  1065. { FM_ADVANCED_NAME, 0x8d },
  1066. MSI_EC_MODE_NULL
  1067. },
  1068. },
  1069. .cpu = {
  1070. .rt_temp_address = 0x68,
  1071. .rt_fan_speed_address = 0x71, // 0x0-0x96
  1072. .rt_fan_speed_base_min = 0x00,
  1073. .rt_fan_speed_base_max = 0x96,
  1074. .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
  1075. .bs_fan_speed_base_min = 0x00,
  1076. .bs_fan_speed_base_max = 0x0f,
  1077. },
  1078. .gpu = {
  1079. .rt_temp_address = 0x80,
  1080. .rt_fan_speed_address = 0x89,
  1081. },
  1082. .leds = {
  1083. .micmute_led_address = 0x2c,
  1084. .mute_led_address = 0x2d,
  1085. .bit = 1,
  1086. },
  1087. .kbd_bl = {
  1088. .bl_mode_address = 0x2c, // KB auto turn off
  1089. .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec
  1090. .max_mode = 1,
  1091. .bl_state_address = 0xd3,
  1092. .state_base_value = 0x80,
  1093. .max_state = 3,
  1094. },
  1095. };
  1096. static struct msi_ec_conf *CONFIGS[] __initdata = {
  1097. &CONF0,
  1098. &CONF1,
  1099. &CONF2,
  1100. &CONF3,
  1101. &CONF4,
  1102. &CONF5,
  1103. &CONF6,
  1104. &CONF7,
  1105. &CONF8,
  1106. &CONF9,
  1107. &CONF10,
  1108. &CONF11,
  1109. &CONF12,
  1110. &CONF13,
  1111. NULL
  1112. };
  1113. static struct msi_ec_conf conf; // current configuration
  1114. /*
  1115. * Helper functions
  1116. */
  1117. static int ec_read_seq(u8 addr, u8 *buf, u8 len)
  1118. {
  1119. int result;
  1120. for (u8 i = 0; i < len; i++) {
  1121. result = ec_read(addr + i, buf + i);
  1122. if (result < 0)
  1123. return result;
  1124. }
  1125. return 0;
  1126. }
  1127. static int ec_get_firmware_version(u8 buf[MSI_EC_FW_VERSION_LENGTH + 1])
  1128. {
  1129. int result;
  1130. memset(buf, 0, MSI_EC_FW_VERSION_LENGTH + 1);
  1131. result = ec_read_seq(MSI_EC_FW_VERSION_ADDRESS,
  1132. buf,
  1133. MSI_EC_FW_VERSION_LENGTH);
  1134. if (result < 0)
  1135. return result;
  1136. return MSI_EC_FW_VERSION_LENGTH + 1;
  1137. }
  1138. /*
  1139. * Sysfs power_supply subsystem
  1140. */
  1141. static ssize_t charge_control_threshold_show(u8 offset,
  1142. struct device *device,
  1143. struct device_attribute *attr,
  1144. char *buf)
  1145. {
  1146. u8 rdata;
  1147. int result;
  1148. result = ec_read(conf.charge_control.address, &rdata);
  1149. if (result < 0)
  1150. return result;
  1151. return sysfs_emit(buf, "%i\n", rdata - offset);
  1152. }
  1153. static ssize_t charge_control_threshold_store(u8 offset,
  1154. struct device *dev,
  1155. struct device_attribute *attr,
  1156. const char *buf, size_t count)
  1157. {
  1158. u8 wdata;
  1159. int result;
  1160. result = kstrtou8(buf, 10, &wdata);
  1161. if (result < 0)
  1162. return result;
  1163. wdata += offset;
  1164. if (wdata < conf.charge_control.range_min ||
  1165. wdata > conf.charge_control.range_max)
  1166. return -EINVAL;
  1167. result = ec_write(conf.charge_control.address, wdata);
  1168. if (result < 0)
  1169. return result;
  1170. return count;
  1171. }
  1172. static ssize_t charge_control_start_threshold_show(struct device *device,
  1173. struct device_attribute *attr,
  1174. char *buf)
  1175. {
  1176. return charge_control_threshold_show(conf.charge_control.offset_start,
  1177. device, attr, buf);
  1178. }
  1179. static ssize_t charge_control_start_threshold_store(struct device *dev,
  1180. struct device_attribute *attr,
  1181. const char *buf, size_t count)
  1182. {
  1183. return charge_control_threshold_store(conf.charge_control.offset_start,
  1184. dev, attr, buf, count);
  1185. }
  1186. static ssize_t charge_control_end_threshold_show(struct device *device,
  1187. struct device_attribute *attr,
  1188. char *buf)
  1189. {
  1190. return charge_control_threshold_show(conf.charge_control.offset_end,
  1191. device, attr, buf);
  1192. }
  1193. static ssize_t charge_control_end_threshold_store(struct device *dev,
  1194. struct device_attribute *attr,
  1195. const char *buf, size_t count)
  1196. {
  1197. return charge_control_threshold_store(conf.charge_control.offset_end,
  1198. dev, attr, buf, count);
  1199. }
  1200. static DEVICE_ATTR_RW(charge_control_start_threshold);
  1201. static DEVICE_ATTR_RW(charge_control_end_threshold);
  1202. static struct attribute *msi_battery_attrs[] = {
  1203. &dev_attr_charge_control_start_threshold.attr,
  1204. &dev_attr_charge_control_end_threshold.attr,
  1205. NULL
  1206. };
  1207. ATTRIBUTE_GROUPS(msi_battery);
  1208. static int msi_battery_add(struct power_supply *battery,
  1209. struct acpi_battery_hook *hook)
  1210. {
  1211. return device_add_groups(&battery->dev, msi_battery_groups);
  1212. }
  1213. static int msi_battery_remove(struct power_supply *battery,
  1214. struct acpi_battery_hook *hook)
  1215. {
  1216. device_remove_groups(&battery->dev, msi_battery_groups);
  1217. return 0;
  1218. }
  1219. static struct acpi_battery_hook battery_hook = {
  1220. .add_battery = msi_battery_add,
  1221. .remove_battery = msi_battery_remove,
  1222. .name = MSI_EC_DRIVER_NAME,
  1223. };
  1224. /*
  1225. * Module load/unload
  1226. */
  1227. static const struct dmi_system_id msi_dmi_table[] __initconst __maybe_unused = {
  1228. {
  1229. .matches = {
  1230. DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"),
  1231. },
  1232. },
  1233. {
  1234. .matches = {
  1235. DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
  1236. },
  1237. },
  1238. {}
  1239. };
  1240. MODULE_DEVICE_TABLE(dmi, msi_dmi_table);
  1241. static int __init load_configuration(void)
  1242. {
  1243. int result;
  1244. u8 fw_version[MSI_EC_FW_VERSION_LENGTH + 1];
  1245. /* get firmware version */
  1246. result = ec_get_firmware_version(fw_version);
  1247. if (result < 0)
  1248. return result;
  1249. /* load the suitable configuration, if exists */
  1250. for (int i = 0; CONFIGS[i]; i++) {
  1251. if (match_string(CONFIGS[i]->allowed_fw, -1, fw_version) != -EINVAL) {
  1252. conf = *CONFIGS[i];
  1253. conf.allowed_fw = NULL;
  1254. return 0;
  1255. }
  1256. }
  1257. /* config not found */
  1258. for (int i = 0; i < MSI_EC_FW_VERSION_LENGTH; i++) {
  1259. if (!isgraph(fw_version[i])) {
  1260. pr_warn("Unable to find a valid firmware version!\n");
  1261. return -EOPNOTSUPP;
  1262. }
  1263. }
  1264. pr_warn("Firmware version is not supported: '%s'\n", fw_version);
  1265. return -EOPNOTSUPP;
  1266. }
  1267. static int __init msi_ec_init(void)
  1268. {
  1269. int result;
  1270. result = load_configuration();
  1271. if (result < 0)
  1272. return result;
  1273. battery_hook_register(&battery_hook);
  1274. return 0;
  1275. }
  1276. static void __exit msi_ec_exit(void)
  1277. {
  1278. battery_hook_unregister(&battery_hook);
  1279. }
  1280. MODULE_LICENSE("GPL");
  1281. MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>");
  1282. MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>");
  1283. MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>");
  1284. MODULE_DESCRIPTION("MSI Embedded Controller");
  1285. module_init(msi_ec_init);
  1286. module_exit(msi_ec_exit);