1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * msi-ec: MSI laptops' embedded controller driver.
6 * This driver allows various MSI laptops' functionalities to be
7 * controlled from userspace.
9 * It contains EC memory configurations for different firmware versions
10 * and exports battery charge thresholds to userspace.
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>
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
30 #define SM_ECO_NAME "eco"
31 #define SM_COMFORT_NAME "comfort"
32 #define SM_SPORT_NAME "sport"
33 #define SM_TURBO_NAME "turbo"
35 #define FM_AUTO_NAME "auto"
36 #define FM_SILENT_NAME "silent"
37 #define FM_BASIC_NAME "basic"
38 #define FM_ADVANCED_NAME "advanced"
40 static const char * const ALLOWED_FW_0
[] __initconst
= {
47 static struct msi_ec_conf CONF0 __initdata
= {
48 .allowed_fw
= ALLOWED_FW_0
,
58 .block_address
= 0x2f,
72 { SM_ECO_NAME
, 0xc2 },
73 { SM_COMFORT_NAME
, 0xc1 },
74 { SM_SPORT_NAME
, 0xc0 },
79 .address
= MSI_EC_ADDR_UNKNOWN
, // 0xd5 needs testing
84 { FM_AUTO_NAME
, 0x0d },
85 { FM_SILENT_NAME
, 0x1d },
86 { FM_BASIC_NAME
, 0x4d },
87 { FM_ADVANCED_NAME
, 0x8d },
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,
101 .rt_temp_address
= 0x80,
102 .rt_fan_speed_address
= 0x89,
105 .micmute_led_address
= 0x2b,
106 .mute_led_address
= 0x2c,
110 .bl_mode_address
= 0x2c, // ?
111 .bl_modes
= { 0x00, 0x08 }, // ?
113 .bl_state_address
= 0xf3,
114 .state_base_value
= 0x80,
119 static const char * const ALLOWED_FW_1
[] __initconst
= {
127 static struct msi_ec_conf CONF1 __initdata
= {
128 .allowed_fw
= ALLOWED_FW_1
,
131 .offset_start
= 0x8a,
138 .block_address
= 0x2f,
152 { SM_ECO_NAME
, 0xc2 },
153 { SM_COMFORT_NAME
, 0xc1 },
154 { SM_SPORT_NAME
, 0xc0 },
155 { SM_TURBO_NAME
, 0xc4 },
160 .address
= MSI_EC_ADDR_UNKNOWN
,
165 { FM_AUTO_NAME
, 0x0d },
166 { FM_BASIC_NAME
, 0x4d },
167 { FM_ADVANCED_NAME
, 0x8d },
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,
181 .rt_temp_address
= 0x80,
182 .rt_fan_speed_address
= 0x89,
185 .micmute_led_address
= 0x2b,
186 .mute_led_address
= 0x2c,
190 .bl_mode_address
= 0x2c, // ?
191 .bl_modes
= { 0x00, 0x08 }, // ?
193 .bl_state_address
= 0xf3,
194 .state_base_value
= 0x80,
199 static const char * const ALLOWED_FW_2
[] __initconst
= {
204 static struct msi_ec_conf CONF2 __initdata
= {
205 .allowed_fw
= ALLOWED_FW_2
,
208 .offset_start
= 0x8a,
215 .block_address
= 0x2f,
229 { SM_ECO_NAME
, 0xc2 },
230 { SM_COMFORT_NAME
, 0xc1 },
231 { SM_SPORT_NAME
, 0xc0 },
242 { FM_AUTO_NAME
, 0x0d },
243 { FM_SILENT_NAME
, 0x1d },
244 { FM_BASIC_NAME
, 0x4d },
245 { FM_ADVANCED_NAME
, 0x8d },
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,
259 .rt_temp_address
= 0x80,
260 .rt_fan_speed_address
= 0x89,
263 .micmute_led_address
= 0x2c,
264 .mute_led_address
= 0x2d,
268 .bl_mode_address
= 0x2c, // ?
269 .bl_modes
= { 0x00, 0x08 }, // ?
271 .bl_state_address
= 0xd3,
272 .state_base_value
= 0x80,
277 static const char * const ALLOWED_FW_3
[] __initconst
= {
282 static struct msi_ec_conf CONF3 __initdata
= {
283 .allowed_fw
= ALLOWED_FW_3
,
286 .offset_start
= 0x8a,
293 .block_address
= 0x2f,
307 { SM_ECO_NAME
, 0xc2 },
308 { SM_COMFORT_NAME
, 0xc1 },
309 { SM_SPORT_NAME
, 0xc0 },
320 { FM_AUTO_NAME
, 0x0d },
321 { FM_SILENT_NAME
, 0x1d },
322 { FM_BASIC_NAME
, 0x4d },
323 { FM_ADVANCED_NAME
, 0x8d },
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,
337 .rt_temp_address
= 0x80,
338 .rt_fan_speed_address
= 0x89,
341 .micmute_led_address
= 0x2b,
342 .mute_led_address
= 0x2c,
346 .bl_mode_address
= 0x2c, // ?
347 .bl_modes
= { 0x00, 0x08 }, // ?
349 .bl_state_address
= 0xd3,
350 .state_base_value
= 0x80,
355 static const char * const ALLOWED_FW_4
[] __initconst
= {
360 static struct msi_ec_conf CONF4 __initdata
= {
361 .allowed_fw
= ALLOWED_FW_4
,
364 .offset_start
= 0x8a,
371 .block_address
= 0x2f,
375 .address
= MSI_EC_ADDR_UNKNOWN
, // supported, but unknown
385 { SM_ECO_NAME
, 0xc2 },
386 { SM_COMFORT_NAME
, 0xc1 },
387 { SM_SPORT_NAME
, 0xc0 },
391 .super_battery
= { // may be supported, but address is unknown
392 .address
= MSI_EC_ADDR_UNKNOWN
,
398 { FM_AUTO_NAME
, 0x0d },
399 { FM_SILENT_NAME
, 0x1d },
400 { FM_ADVANCED_NAME
, 0x8d },
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,
414 .rt_temp_address
= 0x80,
415 .rt_fan_speed_address
= MSI_EC_ADDR_UNKNOWN
,
418 .micmute_led_address
= MSI_EC_ADDR_UNKNOWN
,
419 .mute_led_address
= MSI_EC_ADDR_UNKNOWN
,
423 .bl_mode_address
= MSI_EC_ADDR_UNKNOWN
, // ?
424 .bl_modes
= { 0x00, 0x08 }, // ?
426 .bl_state_address
= MSI_EC_ADDR_UNSUPP
, // 0xd3, not functional
427 .state_base_value
= 0x80,
432 static const char * const ALLOWED_FW_5
[] __initconst
= {
439 static struct msi_ec_conf CONF5 __initdata
= {
440 .allowed_fw
= ALLOWED_FW_5
,
443 .offset_start
= 0x8a,
450 .block_address
= 0x2f,
453 .fn_win_swap
= { // todo: reverse
464 { SM_ECO_NAME
, 0xc2 },
465 { SM_COMFORT_NAME
, 0xc1 },
466 { SM_TURBO_NAME
, 0xc4 },
470 .super_battery
= { // unsupported?
471 .address
= MSI_EC_ADDR_UNKNOWN
,
477 { FM_AUTO_NAME
, 0x0d },
478 { FM_SILENT_NAME
, 0x1d },
479 { FM_ADVANCED_NAME
, 0x8d },
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,
493 .rt_temp_address
= MSI_EC_ADDR_UNKNOWN
,
494 .rt_fan_speed_address
= MSI_EC_ADDR_UNKNOWN
,
497 .micmute_led_address
= 0x2b,
498 .mute_led_address
= 0x2c,
502 .bl_mode_address
= MSI_EC_ADDR_UNKNOWN
, // ?
503 .bl_modes
= { 0x00, 0x08 }, // ?
505 .bl_state_address
= MSI_EC_ADDR_UNSUPP
, // 0xf3, not functional
506 .state_base_value
= 0x80,
511 static const char * const ALLOWED_FW_6
[] __initconst
= {
517 static struct msi_ec_conf CONF6 __initdata
= {
518 .allowed_fw
= ALLOWED_FW_6
,
521 .offset_start
= 0x8a,
528 .block_address
= MSI_EC_ADDR_UNSUPP
,
532 .address
= 0xbf, // todo: reverse
542 { SM_ECO_NAME
, 0xc2 },
543 { SM_COMFORT_NAME
, 0xc1 },
544 { SM_SPORT_NAME
, 0xc0 },
545 { SM_TURBO_NAME
, 0xc4 },
556 { FM_AUTO_NAME
, 0x0d },
557 { FM_SILENT_NAME
, 0x1d },
558 { FM_ADVANCED_NAME
, 0x8d },
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,
572 .rt_temp_address
= 0x80,
573 .rt_fan_speed_address
= MSI_EC_ADDR_UNKNOWN
,
576 .micmute_led_address
= MSI_EC_ADDR_UNSUPP
,
577 .mute_led_address
= MSI_EC_ADDR_UNSUPP
,
581 .bl_mode_address
= MSI_EC_ADDR_UNKNOWN
, // ?
582 .bl_modes
= { 0x00, 0x08 }, // ?
584 .bl_state_address
= MSI_EC_ADDR_UNSUPP
, // 0xf3, not functional
585 .state_base_value
= 0x80,
590 static const char * const ALLOWED_FW_7
[] __initconst
= {
597 static struct msi_ec_conf CONF7 __initdata
= {
598 .allowed_fw
= ALLOWED_FW_7
,
601 .offset_start
= 0x8a,
608 .block_address
= MSI_EC_ADDR_UNSUPP
,
612 .address
= 0xbf, // needs testing
622 { SM_ECO_NAME
, 0xc2 },
623 { SM_COMFORT_NAME
, 0xc1 },
624 { SM_SPORT_NAME
, 0xc0 },
625 { SM_TURBO_NAME
, 0xc4 },
630 .address
= MSI_EC_ADDR_UNKNOWN
, // 0xd5 but has its own wet of modes
636 { FM_AUTO_NAME
, 0x0d }, // d may not be relevant
637 { FM_SILENT_NAME
, 0x1d },
638 { FM_ADVANCED_NAME
, 0x8d },
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,
652 .rt_temp_address
= MSI_EC_ADDR_UNKNOWN
,
653 .rt_fan_speed_address
= MSI_EC_ADDR_UNKNOWN
,
656 .micmute_led_address
= MSI_EC_ADDR_UNSUPP
,
657 .mute_led_address
= 0x2c,
661 .bl_mode_address
= MSI_EC_ADDR_UNKNOWN
, // ?
662 .bl_modes
= { 0x00, 0x08 }, // ?
664 .bl_state_address
= 0xf3,
665 .state_base_value
= 0x80,
670 static const char * const ALLOWED_FW_8
[] __initconst
= {
675 static struct msi_ec_conf CONF8 __initdata
= {
676 .allowed_fw
= ALLOWED_FW_8
,
679 .offset_start
= 0x8a,
686 .block_address
= MSI_EC_ADDR_UNSUPP
,
700 { SM_ECO_NAME
, 0xc2 },
701 { SM_COMFORT_NAME
, 0xc1 },
702 { SM_SPORT_NAME
, 0xc0 },
713 { FM_AUTO_NAME
, 0x0d },
714 { FM_SILENT_NAME
, 0x1d },
715 { FM_BASIC_NAME
, 0x4d },
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,
729 .rt_temp_address
= MSI_EC_ADDR_UNKNOWN
,
730 .rt_fan_speed_address
= MSI_EC_ADDR_UNKNOWN
,
733 .micmute_led_address
= MSI_EC_ADDR_UNSUPP
,
734 .mute_led_address
= 0x2d,
738 .bl_mode_address
= MSI_EC_ADDR_UNKNOWN
, // ?
739 .bl_modes
= { 0x00, 0x08 }, // ?
741 .bl_state_address
= MSI_EC_ADDR_UNSUPP
, // not functional
742 .state_base_value
= 0x80,
747 static const char * const ALLOWED_FW_9
[] __initconst
= {
752 static struct msi_ec_conf CONF9 __initdata
= {
753 .allowed_fw
= ALLOWED_FW_9
,
756 .offset_start
= 0x8a,
763 .block_address
= 0x2f,
777 { SM_ECO_NAME
, 0xc2 },
778 { SM_COMFORT_NAME
, 0xc1 },
779 { SM_SPORT_NAME
, 0xc0 },
784 .address
= MSI_EC_ADDR_UNSUPP
, // unsupported or enabled by ECO shift
790 { FM_AUTO_NAME
, 0x0d },
791 { FM_SILENT_NAME
, 0x1d },
792 { FM_ADVANCED_NAME
, 0x8d },
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,
806 .rt_temp_address
= MSI_EC_ADDR_UNSUPP
,
807 .rt_fan_speed_address
= MSI_EC_ADDR_UNSUPP
,
810 .micmute_led_address
= 0x2b,
811 .mute_led_address
= 0x2c,
815 .bl_mode_address
= MSI_EC_ADDR_UNSUPP
, // not presented in MSI app
816 .bl_modes
= { 0x00, 0x08 },
818 .bl_state_address
= 0xf3,
819 .state_base_value
= 0x80,
824 static const char * const ALLOWED_FW_10
[] __initconst
= {
825 "1582EMS1.107", // GF66 11UC
829 static struct msi_ec_conf CONF10 __initdata
= {
830 .allowed_fw
= ALLOWED_FW_10
,
833 .offset_start
= 0x8a,
840 .block_address
= 0x2f,
844 .address
= MSI_EC_ADDR_UNSUPP
,
854 { SM_ECO_NAME
, 0xc2 },
855 { SM_COMFORT_NAME
, 0xc1 },
856 { SM_SPORT_NAME
, 0xc0 },
857 { SM_TURBO_NAME
, 0xc4 },
868 { FM_AUTO_NAME
, 0x0d },
869 { FM_SILENT_NAME
, 0x1d },
870 { FM_ADVANCED_NAME
, 0x8d },
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,
884 .rt_temp_address
= 0x80,
885 .rt_fan_speed_address
= 0x89,
888 .micmute_led_address
= 0x2c,
889 .mute_led_address
= 0x2d,
893 .bl_mode_address
= 0x2c,
894 .bl_modes
= { 0x00, 0x08 },
896 .bl_state_address
= 0xd3,
897 .state_base_value
= 0x80,
902 static const char * const ALLOWED_FW_11
[] __initconst
= {
903 "16S6EMS1.111", // Prestige 15 a11scx
904 "1552EMS1.115", // Modern 15 a11m
908 static struct msi_ec_conf CONF11 __initdata
= {
909 .allowed_fw
= ALLOWED_FW_11
,
912 .offset_start
= 0x8a,
919 .block_address
= MSI_EC_ADDR_UNKNOWN
,
933 { SM_ECO_NAME
, 0xc2 },
934 { SM_COMFORT_NAME
, 0xc1 },
935 { SM_SPORT_NAME
, 0xc0 },
946 { FM_AUTO_NAME
, 0x0d },
947 { FM_SILENT_NAME
, 0x1d },
948 { FM_ADVANCED_NAME
, 0x4d },
953 .rt_temp_address
= 0x68,
954 .rt_fan_speed_address
= MSI_EC_ADDR_UNSUPP
,
955 .bs_fan_speed_address
= MSI_EC_ADDR_UNSUPP
,
958 .rt_temp_address
= MSI_EC_ADDR_UNSUPP
,
959 .rt_fan_speed_address
= MSI_EC_ADDR_UNSUPP
,
962 .micmute_led_address
= 0x2c,
963 .mute_led_address
= 0x2d,
967 .bl_mode_address
= MSI_EC_ADDR_UNKNOWN
,
970 .bl_state_address
= 0xd3,
971 .state_base_value
= 0x80,
976 static const char * const ALLOWED_FW_12
[] __initconst
= {
977 "16R6EMS1.104", // GF63 Thin 11UC
981 static struct msi_ec_conf CONF12 __initdata
= {
982 .allowed_fw
= ALLOWED_FW_12
,
985 .offset_start
= 0x8a,
992 .block_address
= 0x2f,
1006 { SM_ECO_NAME
, 0xc2 },
1007 { SM_COMFORT_NAME
, 0xc1 },
1008 { SM_SPORT_NAME
, 0xc0 },
1009 { SM_TURBO_NAME
, 0xc4 },
1014 .address
= MSI_EC_ADDR_UNSUPP
, // 0xeb
1015 .mask
= 0x0f, // 00, 0f
1020 { FM_AUTO_NAME
, 0x0d },
1021 { FM_SILENT_NAME
, 0x1d },
1022 { FM_ADVANCED_NAME
, 0x8d },
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,
1036 .rt_temp_address
= MSI_EC_ADDR_UNSUPP
,
1037 .rt_fan_speed_address
= 0x89,
1040 .micmute_led_address
= MSI_EC_ADDR_UNSUPP
,
1041 .mute_led_address
= 0x2d,
1045 .bl_mode_address
= MSI_EC_ADDR_UNKNOWN
,
1046 .bl_modes
= { 0x00, 0x08 },
1048 .bl_state_address
= 0xd3,
1049 .state_base_value
= 0x80,
1054 static const char * const ALLOWED_FW_13
[] __initconst
= {
1055 "1594EMS1.109", // MSI Prestige 16 Studio A13VE
1059 static struct msi_ec_conf CONF13 __initdata
= {
1060 .allowed_fw
= ALLOWED_FW_13
,
1063 .offset_start
= 0x8a,
1070 .block_address
= 0x2f,
1075 .bit
= 4, // 0x00-0x10
1084 { SM_ECO_NAME
, 0xc2 }, // super battery
1085 { SM_COMFORT_NAME
, 0xc1 }, // balanced
1086 { SM_TURBO_NAME
, 0xc4 }, // extreme
1091 .address
= MSI_EC_ADDR_UNSUPP
,
1092 .mask
= 0x0f, // 00, 0f
1097 { FM_AUTO_NAME
, 0x0d },
1098 { FM_SILENT_NAME
, 0x1d },
1099 { FM_ADVANCED_NAME
, 0x8d },
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,
1113 .rt_temp_address
= 0x80,
1114 .rt_fan_speed_address
= 0x89,
1117 .micmute_led_address
= 0x2c,
1118 .mute_led_address
= 0x2d,
1122 .bl_mode_address
= 0x2c, // KB auto turn off
1123 .bl_modes
= { 0x00, 0x08 }, // always on; off after 10 sec
1125 .bl_state_address
= 0xd3,
1126 .state_base_value
= 0x80,
1131 static struct msi_ec_conf
*CONFIGS
[] __initdata
= {
1149 static struct msi_ec_conf conf
; // current configuration
1155 static int ec_read_seq(u8 addr
, u8
*buf
, u8 len
)
1159 for (u8 i
= 0; i
< len
; i
++) {
1160 result
= ec_read(addr
+ i
, buf
+ i
);
1168 static int ec_get_firmware_version(u8 buf
[MSI_EC_FW_VERSION_LENGTH
+ 1])
1172 memset(buf
, 0, MSI_EC_FW_VERSION_LENGTH
+ 1);
1173 result
= ec_read_seq(MSI_EC_FW_VERSION_ADDRESS
,
1175 MSI_EC_FW_VERSION_LENGTH
);
1179 return MSI_EC_FW_VERSION_LENGTH
+ 1;
1183 * Sysfs power_supply subsystem
1186 static ssize_t
charge_control_threshold_show(u8 offset
,
1187 struct device
*device
,
1188 struct device_attribute
*attr
,
1194 result
= ec_read(conf
.charge_control
.address
, &rdata
);
1198 return sysfs_emit(buf
, "%i\n", rdata
- offset
);
1201 static ssize_t
charge_control_threshold_store(u8 offset
,
1203 struct device_attribute
*attr
,
1204 const char *buf
, size_t count
)
1209 result
= kstrtou8(buf
, 10, &wdata
);
1214 if (wdata
< conf
.charge_control
.range_min
||
1215 wdata
> conf
.charge_control
.range_max
)
1218 result
= ec_write(conf
.charge_control
.address
, wdata
);
1225 static ssize_t
charge_control_start_threshold_show(struct device
*device
,
1226 struct device_attribute
*attr
,
1229 return charge_control_threshold_show(conf
.charge_control
.offset_start
,
1233 static ssize_t
charge_control_start_threshold_store(struct device
*dev
,
1234 struct device_attribute
*attr
,
1235 const char *buf
, size_t count
)
1237 return charge_control_threshold_store(conf
.charge_control
.offset_start
,
1238 dev
, attr
, buf
, count
);
1241 static ssize_t
charge_control_end_threshold_show(struct device
*device
,
1242 struct device_attribute
*attr
,
1245 return charge_control_threshold_show(conf
.charge_control
.offset_end
,
1249 static ssize_t
charge_control_end_threshold_store(struct device
*dev
,
1250 struct device_attribute
*attr
,
1251 const char *buf
, size_t count
)
1253 return charge_control_threshold_store(conf
.charge_control
.offset_end
,
1254 dev
, attr
, buf
, count
);
1257 static DEVICE_ATTR_RW(charge_control_start_threshold
);
1258 static DEVICE_ATTR_RW(charge_control_end_threshold
);
1260 static struct attribute
*msi_battery_attrs
[] = {
1261 &dev_attr_charge_control_start_threshold
.attr
,
1262 &dev_attr_charge_control_end_threshold
.attr
,
1266 ATTRIBUTE_GROUPS(msi_battery
);
1268 static int msi_battery_add(struct power_supply
*battery
,
1269 struct acpi_battery_hook
*hook
)
1271 return device_add_groups(&battery
->dev
, msi_battery_groups
);
1274 static int msi_battery_remove(struct power_supply
*battery
,
1275 struct acpi_battery_hook
*hook
)
1277 device_remove_groups(&battery
->dev
, msi_battery_groups
);
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
,
1288 * Module load/unload
1291 static const struct dmi_system_id msi_dmi_table
[] __initconst __maybe_unused
= {
1294 DMI_MATCH(DMI_SYS_VENDOR
, "MICRO-STAR INT"),
1299 DMI_MATCH(DMI_SYS_VENDOR
, "Micro-Star International"),
1304 MODULE_DEVICE_TABLE(dmi
, msi_dmi_table
);
1306 static int __init
load_configuration(void)
1310 u8 fw_version
[MSI_EC_FW_VERSION_LENGTH
+ 1];
1312 /* get firmware version */
1313 result
= ec_get_firmware_version(fw_version
);
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
) {
1321 conf
.allowed_fw
= NULL
;
1326 /* config not found */
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");
1335 pr_warn("Firmware version is not supported: '%s'\n", fw_version
);
1339 static int __init
msi_ec_init(void)
1343 result
= load_configuration();
1347 battery_hook_register(&battery_hook
);
1351 static void __exit
msi_ec_exit(void)
1353 battery_hook_unregister(&battery_hook
);
1356 MODULE_LICENSE("GPL");
1357 MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>");
1358 MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>");
1359 MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>");
1360 MODULE_DESCRIPTION("MSI Embedded Controller");
1362 module_init(msi_ec_init
);
1363 module_exit(msi_ec_exit
);