powerpc/mm: Avoid calling arch_enter/leave_lazy_mmu() in set_ptes
[platform/kernel/linux-starfive.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 <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_super_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_super_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_super_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         "E1592IMS.10C",
280         NULL
281 };
282
283 static struct msi_ec_conf CONF3 __initdata = {
284         .allowed_fw = ALLOWED_FW_3,
285         .charge_control = {
286                 .address      = 0xef,
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_super_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_super_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_super_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_super_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_super_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 struct msi_ec_conf *CONFIGS[] __initdata = {
672         &CONF0,
673         &CONF1,
674         &CONF2,
675         &CONF3,
676         &CONF4,
677         &CONF5,
678         &CONF6,
679         &CONF7,
680         NULL
681 };
682
683 static struct msi_ec_conf conf; // current configuration
684
685 /*
686  * Helper functions
687  */
688
689 static int ec_read_seq(u8 addr, u8 *buf, u8 len)
690 {
691         int result;
692
693         for (u8 i = 0; i < len; i++) {
694                 result = ec_read(addr + i, buf + i);
695                 if (result < 0)
696                         return result;
697         }
698
699         return 0;
700 }
701
702 static int ec_get_firmware_version(u8 buf[MSI_EC_FW_VERSION_LENGTH + 1])
703 {
704         int result;
705
706         memset(buf, 0, MSI_EC_FW_VERSION_LENGTH + 1);
707         result = ec_read_seq(MSI_EC_FW_VERSION_ADDRESS,
708                              buf,
709                              MSI_EC_FW_VERSION_LENGTH);
710         if (result < 0)
711                 return result;
712
713         return MSI_EC_FW_VERSION_LENGTH + 1;
714 }
715
716 /*
717  * Sysfs power_supply subsystem
718  */
719
720 static ssize_t charge_control_threshold_show(u8 offset,
721                                              struct device *device,
722                                              struct device_attribute *attr,
723                                              char *buf)
724 {
725         u8 rdata;
726         int result;
727
728         result = ec_read(conf.charge_control.address, &rdata);
729         if (result < 0)
730                 return result;
731
732         return sysfs_emit(buf, "%i\n", rdata - offset);
733 }
734
735 static ssize_t charge_control_threshold_store(u8 offset,
736                                               struct device *dev,
737                                               struct device_attribute *attr,
738                                               const char *buf, size_t count)
739 {
740         u8 wdata;
741         int result;
742
743         result = kstrtou8(buf, 10, &wdata);
744         if (result < 0)
745                 return result;
746
747         wdata += offset;
748         if (wdata < conf.charge_control.range_min ||
749             wdata > conf.charge_control.range_max)
750                 return -EINVAL;
751
752         result = ec_write(conf.charge_control.address, wdata);
753         if (result < 0)
754                 return result;
755
756         return count;
757 }
758
759 static ssize_t charge_control_start_threshold_show(struct device *device,
760                                                    struct device_attribute *attr,
761                                                    char *buf)
762 {
763         return charge_control_threshold_show(conf.charge_control.offset_start,
764                                              device, attr, buf);
765 }
766
767 static ssize_t charge_control_start_threshold_store(struct device *dev,
768                                                     struct device_attribute *attr,
769                                                     const char *buf, size_t count)
770 {
771         return charge_control_threshold_store(conf.charge_control.offset_start,
772                                               dev, attr, buf, count);
773 }
774
775 static ssize_t charge_control_end_threshold_show(struct device *device,
776                                                  struct device_attribute *attr,
777                                                  char *buf)
778 {
779         return charge_control_threshold_show(conf.charge_control.offset_end,
780                                              device, attr, buf);
781 }
782
783 static ssize_t charge_control_end_threshold_store(struct device *dev,
784                                                   struct device_attribute *attr,
785                                                   const char *buf, size_t count)
786 {
787         return charge_control_threshold_store(conf.charge_control.offset_end,
788                                               dev, attr, buf, count);
789 }
790
791 static DEVICE_ATTR_RW(charge_control_start_threshold);
792 static DEVICE_ATTR_RW(charge_control_end_threshold);
793
794 static struct attribute *msi_battery_attrs[] = {
795         &dev_attr_charge_control_start_threshold.attr,
796         &dev_attr_charge_control_end_threshold.attr,
797         NULL
798 };
799
800 ATTRIBUTE_GROUPS(msi_battery);
801
802 static int msi_battery_add(struct power_supply *battery,
803                            struct acpi_battery_hook *hook)
804 {
805         return device_add_groups(&battery->dev, msi_battery_groups);
806 }
807
808 static int msi_battery_remove(struct power_supply *battery,
809                               struct acpi_battery_hook *hook)
810 {
811         device_remove_groups(&battery->dev, msi_battery_groups);
812         return 0;
813 }
814
815 static struct acpi_battery_hook battery_hook = {
816         .add_battery = msi_battery_add,
817         .remove_battery = msi_battery_remove,
818         .name = MSI_EC_DRIVER_NAME,
819 };
820
821 /*
822  * Module load/unload
823  */
824
825 static const struct dmi_system_id msi_dmi_table[] __initconst __maybe_unused = {
826         {
827                 .matches = {
828                         DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"),
829                 },
830         },
831         {
832                 .matches = {
833                         DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
834                 },
835         },
836         {}
837 };
838 MODULE_DEVICE_TABLE(dmi, msi_dmi_table);
839
840 static int __init load_configuration(void)
841 {
842         int result;
843
844         u8 fw_version[MSI_EC_FW_VERSION_LENGTH + 1];
845
846         /* get firmware version */
847         result = ec_get_firmware_version(fw_version);
848         if (result < 0)
849                 return result;
850
851         /* load the suitable configuration, if exists */
852         for (int i = 0; CONFIGS[i]; i++) {
853                 if (match_string(CONFIGS[i]->allowed_fw, -1, fw_version) != -EINVAL) {
854                         conf = *CONFIGS[i];
855                         conf.allowed_fw = NULL;
856                         return 0;
857                 }
858         }
859
860         /* config not found */
861
862         for (int i = 0; i < MSI_EC_FW_VERSION_LENGTH; i++) {
863                 if (!isgraph(fw_version[i])) {
864                         pr_warn("Unable to find a valid firmware version!\n");
865                         return -EOPNOTSUPP;
866                 }
867         }
868
869         pr_warn("Firmware version is not supported: '%s'\n", fw_version);
870         return -EOPNOTSUPP;
871 }
872
873 static int __init msi_ec_init(void)
874 {
875         int result;
876
877         result = load_configuration();
878         if (result < 0)
879                 return result;
880
881         battery_hook_register(&battery_hook);
882         return 0;
883 }
884
885 static void __exit msi_ec_exit(void)
886 {
887         battery_hook_unregister(&battery_hook);
888 }
889
890 MODULE_LICENSE("GPL");
891 MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>");
892 MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>");
893 MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>");
894 MODULE_DESCRIPTION("MSI Embedded Controller");
895
896 module_init(msi_ec_init);
897 module_exit(msi_ec_exit);