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