xref: /linux/drivers/platform/x86/msi-ec.c (revision eacaf5ae747f7dead6cc268de17a7382d79031fc)
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 	"1583EMS1.109", // Pulse GL66 12UEK
827 	NULL
828 };
829 
830 static struct msi_ec_conf CONF10 __initdata = {
831 	.allowed_fw = ALLOWED_FW_10,
832 	.charge_control = {
833 		.address      = 0xd7,
834 		.offset_start = 0x8a,
835 		.offset_end   = 0x80,
836 		.range_min    = 0x8a,
837 		.range_max    = 0xe4,
838 	},
839 	.webcam = {
840 		.address       = 0x2e,
841 		.block_address = 0x2f,
842 		.bit           = 1,
843 	},
844 	.fn_win_swap = {
845 		.address = MSI_EC_ADDR_UNSUPP,
846 		.bit     = 4,
847 	},
848 	.cooler_boost = {
849 		.address = 0x98,
850 		.bit     = 7,
851 	},
852 	.shift_mode = {
853 		.address = 0xd2,
854 		.modes = {
855 			{ SM_ECO_NAME,     0xc2 },
856 			{ SM_COMFORT_NAME, 0xc1 },
857 			{ SM_SPORT_NAME,   0xc0 },
858 			{ SM_TURBO_NAME,   0xc4 },
859 			MSI_EC_MODE_NULL
860 		},
861 	},
862 	.super_battery = {
863 		.address = 0xe5,
864 		.mask    = 0x0f,
865 	},
866 	.fan_mode = {
867 		.address = 0xd4,
868 		.modes = {
869 			{ FM_AUTO_NAME,     0x0d },
870 			{ FM_SILENT_NAME,   0x1d },
871 			{ FM_ADVANCED_NAME, 0x8d },
872 			MSI_EC_MODE_NULL
873 		},
874 	},
875 	.cpu = {
876 		.rt_temp_address       = 0x68,
877 		.rt_fan_speed_address  = 0x71, // ?
878 		.rt_fan_speed_base_min = 0x19,
879 		.rt_fan_speed_base_max = 0x37,
880 		.bs_fan_speed_address  = MSI_EC_ADDR_UNKNOWN, // ?
881 		.bs_fan_speed_base_min = 0x00,
882 		.bs_fan_speed_base_max = 0x0f,
883 	},
884 	.gpu = {
885 		.rt_temp_address      = 0x80,
886 		.rt_fan_speed_address = 0x89,
887 	},
888 	.leds = {
889 		.micmute_led_address = 0x2c,
890 		.mute_led_address    = 0x2d,
891 		.bit                 = 1,
892 	},
893 	.kbd_bl = {
894 		.bl_mode_address  = 0x2c,
895 		.bl_modes         = { 0x00, 0x08 },
896 		.max_mode         = 1,
897 		.bl_state_address = 0xd3,
898 		.state_base_value = 0x80,
899 		.max_state        = 3,
900 	},
901 };
902 
903 static const char * const ALLOWED_FW_11[] __initconst = {
904 	"16S6EMS1.111", // Prestige 15 a11scx
905 	"1552EMS1.115", // Modern 15 a11m
906 	NULL
907 };
908 
909 static struct msi_ec_conf CONF11 __initdata = {
910 	.allowed_fw = ALLOWED_FW_11,
911 	.charge_control = {
912 		.address      = 0xd7,
913 		.offset_start = 0x8a,
914 		.offset_end   = 0x80,
915 		.range_min    = 0x8a,
916 		.range_max    = 0xe4,
917 	},
918 	.webcam = {
919 		.address       = 0x2e,
920 		.block_address = MSI_EC_ADDR_UNKNOWN,
921 		.bit           = 1,
922 	},
923 	.fn_win_swap = {
924 		.address = 0xe8,
925 		.bit     = 4,
926 	},
927 	.cooler_boost = {
928 		.address = 0x98,
929 		.bit     = 7,
930 	},
931 	.shift_mode = {
932 		.address = 0xd2,
933 		.modes = {
934 			{ SM_ECO_NAME,     0xc2 },
935 			{ SM_COMFORT_NAME, 0xc1 },
936 			{ SM_SPORT_NAME,   0xc0 },
937 			MSI_EC_MODE_NULL
938 		},
939 	},
940 	.super_battery = {
941 		.address = 0xeb,
942 		.mask = 0x0f,
943 	},
944 	.fan_mode = {
945 		.address = 0xd4,
946 		.modes = {
947 			{ FM_AUTO_NAME,     0x0d },
948 			{ FM_SILENT_NAME,   0x1d },
949 			{ FM_ADVANCED_NAME, 0x4d },
950 			MSI_EC_MODE_NULL
951 		},
952 	},
953 	.cpu = {
954 		.rt_temp_address       = 0x68,
955 		.rt_fan_speed_address  = MSI_EC_ADDR_UNSUPP,
956 		.bs_fan_speed_address  = MSI_EC_ADDR_UNSUPP,
957 	},
958 	.gpu = {
959 		.rt_temp_address      = MSI_EC_ADDR_UNSUPP,
960 		.rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
961 	},
962 	.leds = {
963 		.micmute_led_address = 0x2c,
964 		.mute_led_address    = 0x2d,
965 		.bit                 = 1,
966 	},
967 	.kbd_bl = {
968 		.bl_mode_address  = MSI_EC_ADDR_UNKNOWN,
969 		.bl_modes         = {}, // ?
970 		.max_mode         = 1, // ?
971 		.bl_state_address = 0xd3,
972 		.state_base_value = 0x80,
973 		.max_state        = 3,
974 	},
975 };
976 
977 static const char * const ALLOWED_FW_12[] __initconst = {
978 	"16R6EMS1.104", // GF63 Thin 11UC
979 	NULL
980 };
981 
982 static struct msi_ec_conf CONF12 __initdata = {
983 	.allowed_fw = ALLOWED_FW_12,
984 	.charge_control = {
985 		.address      = 0xd7,
986 		.offset_start = 0x8a,
987 		.offset_end   = 0x80,
988 		.range_min    = 0x8a,
989 		.range_max    = 0xe4,
990 	},
991 	.webcam = {
992 		.address       = 0x2e,
993 		.block_address = 0x2f,
994 		.bit           = 1,
995 	},
996 	.fn_win_swap = {
997 		.address = 0xe8,
998 		.bit     = 4,
999 	},
1000 	.cooler_boost = {
1001 		.address = 0x98,
1002 		.bit     = 7,
1003 	},
1004 	.shift_mode = {
1005 		.address = 0xd2,
1006 		.modes = {
1007 			{ SM_ECO_NAME,     0xc2 },
1008 			{ SM_COMFORT_NAME, 0xc1 },
1009 			{ SM_SPORT_NAME,   0xc0 },
1010 			{ SM_TURBO_NAME,   0xc4 },
1011 			MSI_EC_MODE_NULL
1012 		},
1013 	},
1014 	.super_battery = {
1015 		.address = MSI_EC_ADDR_UNSUPP, // 0xeb
1016 		.mask    = 0x0f, // 00, 0f
1017 	},
1018 	.fan_mode = {
1019 		.address = 0xd4,
1020 		.modes = {
1021 			{ FM_AUTO_NAME,     0x0d },
1022 			{ FM_SILENT_NAME,   0x1d },
1023 			{ FM_ADVANCED_NAME, 0x8d },
1024 			MSI_EC_MODE_NULL
1025 		},
1026 	},
1027 	.cpu = {
1028 		.rt_temp_address       = 0x68,
1029 		.rt_fan_speed_address  = 0x71,
1030 		.rt_fan_speed_base_min = 0x19,
1031 		.rt_fan_speed_base_max = 0x37,
1032 		.bs_fan_speed_address  = MSI_EC_ADDR_UNSUPP,
1033 		.bs_fan_speed_base_min = 0x00,
1034 		.bs_fan_speed_base_max = 0x0f,
1035 	},
1036 	.gpu = {
1037 		.rt_temp_address      = MSI_EC_ADDR_UNSUPP,
1038 		.rt_fan_speed_address = 0x89,
1039 	},
1040 	.leds = {
1041 		.micmute_led_address = MSI_EC_ADDR_UNSUPP,
1042 		.mute_led_address    = 0x2d,
1043 		.bit                 = 1,
1044 	},
1045 	.kbd_bl = {
1046 		.bl_mode_address  = MSI_EC_ADDR_UNKNOWN,
1047 		.bl_modes         = { 0x00, 0x08 },
1048 		.max_mode         = 1,
1049 		.bl_state_address = 0xd3,
1050 		.state_base_value = 0x80,
1051 		.max_state        = 3,
1052 	},
1053 };
1054 
1055 static const char * const ALLOWED_FW_13[] __initconst = {
1056 	"1594EMS1.109", // MSI Prestige 16 Studio A13VE
1057 	NULL
1058 };
1059 
1060 static struct msi_ec_conf CONF13 __initdata = {
1061 	.allowed_fw = ALLOWED_FW_13,
1062 	.charge_control = {
1063 		.address      = 0xd7,
1064 		.offset_start = 0x8a,
1065 		.offset_end   = 0x80,
1066 		.range_min    = 0x8a,
1067 		.range_max    = 0xe4,
1068 	},
1069 	.webcam = {
1070 		.address       = 0x2e,
1071 		.block_address = 0x2f,
1072 		.bit           = 1,
1073 	},
1074 	.fn_win_swap = {
1075 		.address = 0xe8,
1076 		.bit     = 4, // 0x00-0x10
1077 	},
1078 	.cooler_boost = {
1079 		.address = 0x98,
1080 		.bit     = 7,
1081 	},
1082 	.shift_mode = {
1083 		.address = 0xd2,
1084 		.modes = {
1085 			{ SM_ECO_NAME,     0xc2 }, // super battery
1086 			{ SM_COMFORT_NAME, 0xc1 }, // balanced
1087 			{ SM_TURBO_NAME,   0xc4 }, // extreme
1088 			MSI_EC_MODE_NULL
1089 		},
1090 	},
1091 	.super_battery = {
1092 		.address = MSI_EC_ADDR_UNSUPP,
1093 		.mask    = 0x0f, // 00, 0f
1094 	},
1095 	.fan_mode = {
1096 		.address = 0xd4,
1097 		.modes = {
1098 			{ FM_AUTO_NAME,     0x0d },
1099 			{ FM_SILENT_NAME,   0x1d },
1100 			{ FM_ADVANCED_NAME, 0x8d },
1101 			MSI_EC_MODE_NULL
1102 		},
1103 	},
1104 	.cpu = {
1105 		.rt_temp_address       = 0x68,
1106 		.rt_fan_speed_address  = 0x71, // 0x0-0x96
1107 		.rt_fan_speed_base_min = 0x00,
1108 		.rt_fan_speed_base_max = 0x96,
1109 		.bs_fan_speed_address  = MSI_EC_ADDR_UNSUPP,
1110 		.bs_fan_speed_base_min = 0x00,
1111 		.bs_fan_speed_base_max = 0x0f,
1112 	},
1113 	.gpu = {
1114 		.rt_temp_address      = 0x80,
1115 		.rt_fan_speed_address = 0x89,
1116 	},
1117 	.leds = {
1118 		.micmute_led_address = 0x2c,
1119 		.mute_led_address    = 0x2d,
1120 		.bit                 = 1,
1121 	},
1122 	.kbd_bl = {
1123 		.bl_mode_address  = 0x2c, // KB auto turn off
1124 		.bl_modes         = { 0x00, 0x08 }, // always on; off after 10 sec
1125 		.max_mode         = 1,
1126 		.bl_state_address = 0xd3,
1127 		.state_base_value = 0x80,
1128 		.max_state        = 3,
1129 	},
1130 };
1131 
1132 static struct msi_ec_conf *CONFIGS[] __initdata = {
1133 	&CONF0,
1134 	&CONF1,
1135 	&CONF2,
1136 	&CONF3,
1137 	&CONF4,
1138 	&CONF5,
1139 	&CONF6,
1140 	&CONF7,
1141 	&CONF8,
1142 	&CONF9,
1143 	&CONF10,
1144 	&CONF11,
1145 	&CONF12,
1146 	&CONF13,
1147 	NULL
1148 };
1149 
1150 static struct msi_ec_conf conf; // current configuration
1151 
1152 /*
1153  * Helper functions
1154  */
1155 
1156 static int ec_read_seq(u8 addr, u8 *buf, u8 len)
1157 {
1158 	int result;
1159 
1160 	for (u8 i = 0; i < len; i++) {
1161 		result = ec_read(addr + i, buf + i);
1162 		if (result < 0)
1163 			return result;
1164 	}
1165 
1166 	return 0;
1167 }
1168 
1169 static int ec_get_firmware_version(u8 buf[MSI_EC_FW_VERSION_LENGTH + 1])
1170 {
1171 	int result;
1172 
1173 	memset(buf, 0, MSI_EC_FW_VERSION_LENGTH + 1);
1174 	result = ec_read_seq(MSI_EC_FW_VERSION_ADDRESS,
1175 			     buf,
1176 			     MSI_EC_FW_VERSION_LENGTH);
1177 	if (result < 0)
1178 		return result;
1179 
1180 	return MSI_EC_FW_VERSION_LENGTH + 1;
1181 }
1182 
1183 /*
1184  * Sysfs power_supply subsystem
1185  */
1186 
1187 static ssize_t charge_control_threshold_show(u8 offset,
1188 					     struct device *device,
1189 					     struct device_attribute *attr,
1190 					     char *buf)
1191 {
1192 	u8 rdata;
1193 	int result;
1194 
1195 	result = ec_read(conf.charge_control.address, &rdata);
1196 	if (result < 0)
1197 		return result;
1198 
1199 	return sysfs_emit(buf, "%i\n", rdata - offset);
1200 }
1201 
1202 static ssize_t charge_control_threshold_store(u8 offset,
1203 					      struct device *dev,
1204 					      struct device_attribute *attr,
1205 					      const char *buf, size_t count)
1206 {
1207 	u8 wdata;
1208 	int result;
1209 
1210 	result = kstrtou8(buf, 10, &wdata);
1211 	if (result < 0)
1212 		return result;
1213 
1214 	wdata += offset;
1215 	if (wdata < conf.charge_control.range_min ||
1216 	    wdata > conf.charge_control.range_max)
1217 		return -EINVAL;
1218 
1219 	result = ec_write(conf.charge_control.address, wdata);
1220 	if (result < 0)
1221 		return result;
1222 
1223 	return count;
1224 }
1225 
1226 static ssize_t charge_control_start_threshold_show(struct device *device,
1227 						   struct device_attribute *attr,
1228 						   char *buf)
1229 {
1230 	return charge_control_threshold_show(conf.charge_control.offset_start,
1231 					     device, attr, buf);
1232 }
1233 
1234 static ssize_t charge_control_start_threshold_store(struct device *dev,
1235 						    struct device_attribute *attr,
1236 						    const char *buf, size_t count)
1237 {
1238 	return charge_control_threshold_store(conf.charge_control.offset_start,
1239 					      dev, attr, buf, count);
1240 }
1241 
1242 static ssize_t charge_control_end_threshold_show(struct device *device,
1243 						 struct device_attribute *attr,
1244 						 char *buf)
1245 {
1246 	return charge_control_threshold_show(conf.charge_control.offset_end,
1247 					     device, attr, buf);
1248 }
1249 
1250 static ssize_t charge_control_end_threshold_store(struct device *dev,
1251 						  struct device_attribute *attr,
1252 						  const char *buf, size_t count)
1253 {
1254 	return charge_control_threshold_store(conf.charge_control.offset_end,
1255 					      dev, attr, buf, count);
1256 }
1257 
1258 static DEVICE_ATTR_RW(charge_control_start_threshold);
1259 static DEVICE_ATTR_RW(charge_control_end_threshold);
1260 
1261 static struct attribute *msi_battery_attrs[] = {
1262 	&dev_attr_charge_control_start_threshold.attr,
1263 	&dev_attr_charge_control_end_threshold.attr,
1264 	NULL
1265 };
1266 
1267 ATTRIBUTE_GROUPS(msi_battery);
1268 
1269 static int msi_battery_add(struct power_supply *battery,
1270 			   struct acpi_battery_hook *hook)
1271 {
1272 	return device_add_groups(&battery->dev, msi_battery_groups);
1273 }
1274 
1275 static int msi_battery_remove(struct power_supply *battery,
1276 			      struct acpi_battery_hook *hook)
1277 {
1278 	device_remove_groups(&battery->dev, msi_battery_groups);
1279 	return 0;
1280 }
1281 
1282 static struct acpi_battery_hook battery_hook = {
1283 	.add_battery = msi_battery_add,
1284 	.remove_battery = msi_battery_remove,
1285 	.name = MSI_EC_DRIVER_NAME,
1286 };
1287 
1288 /*
1289  * Module load/unload
1290  */
1291 
1292 static const struct dmi_system_id msi_dmi_table[] __initconst __maybe_unused = {
1293 	{
1294 		.matches = {
1295 			DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"),
1296 		},
1297 	},
1298 	{
1299 		.matches = {
1300 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
1301 		},
1302 	},
1303 	{}
1304 };
1305 MODULE_DEVICE_TABLE(dmi, msi_dmi_table);
1306 
1307 static int __init load_configuration(void)
1308 {
1309 	int result;
1310 
1311 	u8 fw_version[MSI_EC_FW_VERSION_LENGTH + 1];
1312 
1313 	/* get firmware version */
1314 	result = ec_get_firmware_version(fw_version);
1315 	if (result < 0)
1316 		return result;
1317 
1318 	/* load the suitable configuration, if exists */
1319 	for (int i = 0; CONFIGS[i]; i++) {
1320 		if (match_string(CONFIGS[i]->allowed_fw, -1, fw_version) != -EINVAL) {
1321 			conf = *CONFIGS[i];
1322 			conf.allowed_fw = NULL;
1323 			return 0;
1324 		}
1325 	}
1326 
1327 	/* config not found */
1328 
1329 	for (int i = 0; i < MSI_EC_FW_VERSION_LENGTH; i++) {
1330 		if (!isgraph(fw_version[i])) {
1331 			pr_warn("Unable to find a valid firmware version!\n");
1332 			return -EOPNOTSUPP;
1333 		}
1334 	}
1335 
1336 	pr_warn("Firmware version is not supported: '%s'\n", fw_version);
1337 	return -EOPNOTSUPP;
1338 }
1339 
1340 static int __init msi_ec_init(void)
1341 {
1342 	int result;
1343 
1344 	result = load_configuration();
1345 	if (result < 0)
1346 		return result;
1347 
1348 	battery_hook_register(&battery_hook);
1349 	return 0;
1350 }
1351 
1352 static void __exit msi_ec_exit(void)
1353 {
1354 	battery_hook_unregister(&battery_hook);
1355 }
1356 
1357 MODULE_LICENSE("GPL");
1358 MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>");
1359 MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>");
1360 MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>");
1361 MODULE_DESCRIPTION("MSI Embedded Controller");
1362 
1363 module_init(msi_ec_init);
1364 module_exit(msi_ec_exit);
1365