]> Git Repo - linux.git/blob - drivers/platform/x86/msi-ec.c
Linux 6.14-rc3
[linux.git] / drivers / platform / x86 / msi-ec.c
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 <[email protected]>
13  * Copyright (C) 2023 Aakash Singh <[email protected]>
14  * Copyright (C) 2023 Nikita Kravets <[email protected]>
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 <[email protected]>");
1358 MODULE_AUTHOR("Aakash Singh <[email protected]>");
1359 MODULE_AUTHOR("Nikita Kravets <[email protected]>");
1360 MODULE_DESCRIPTION("MSI Embedded Controller");
1361
1362 module_init(msi_ec_init);
1363 module_exit(msi_ec_exit);
This page took 0.105323 seconds and 4 git commands to generate.