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