brintos

brintos / linux-shallow public Read only

0
0
Text · 28.8 KiB · f19504d Raw
1364 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3/*4 * msi-ec: MSI laptops' embedded controller driver.5 *6 * This driver allows various MSI laptops' functionalities to be7 * controlled from userspace.8 *9 * It contains EC memory configurations for different firmware versions10 * 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 ": " fmt18 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 40static const char * const ALLOWED_FW_0[] __initconst = {41	"14C1EMS1.012",42	"14C1EMS1.101",43	"14C1EMS1.102",44	NULL45};46 47static 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_NULL76		},77	},78	.super_battery = {79		.address = MSI_EC_ADDR_UNKNOWN, // 0xd5 needs testing80	},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_NULL89		},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 119static const char * const ALLOWED_FW_1[] __initconst = {120	"17F2EMS1.103",121	"17F2EMS1.104",122	"17F2EMS1.106",123	"17F2EMS1.107",124	NULL125};126 127static 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_NULL157		},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_NULL169		},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 199static const char * const ALLOWED_FW_2[] __initconst = {200	"1552EMS1.118",201	NULL202};203 204static 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_NULL233		},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_NULL247		},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 277static const char * const ALLOWED_FW_3[] __initconst = {278	"1592EMS1.111",279	NULL280};281 282static 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_NULL311		},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_NULL325		},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 355static const char * const ALLOWED_FW_4[] __initconst = {356	"16V4EMS1.114",357	NULL358};359 360static 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 unknown376		.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_NULL389		},390	},391	.super_battery = { // may be supported, but address is unknown392		.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_NULL402		},403	},404	.cpu = {405		.rt_temp_address       = 0x68, // needs testing406		.rt_fan_speed_address  = 0x71, // needs testing407		.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 functional427		.state_base_value = 0x80,428		.max_state        = 3,429	},430};431 432static const char * const ALLOWED_FW_5[] __initconst = {433	"158LEMS1.103",434	"158LEMS1.105",435	"158LEMS1.106",436	NULL437};438 439static 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: reverse454		.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_NULL468		},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_NULL481		},482	},483	.cpu = {484		.rt_temp_address       = 0x68, // needs testing485		.rt_fan_speed_address  = 0x71, // needs testing486		.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 functional506		.state_base_value = 0x80,507		.max_state        = 3,508	},509};510 511static const char * const ALLOWED_FW_6[] __initconst = {512	"1542EMS1.102",513	"1542EMS1.104",514	NULL515};516 517static 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: reverse533		.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_NULL547		},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_NULL560		},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 functional585		.state_base_value = 0x80,586		.max_state        = 3,587	},588};589 590static const char * const ALLOWED_FW_7[] __initconst = {591	"17FKEMS1.108",592	"17FKEMS1.109",593	"17FKEMS1.10A",594	NULL595};596 597static 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 testing613		.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_NULL627		},628	},629	.super_battery = {630		.address = MSI_EC_ADDR_UNKNOWN, // 0xd5 but has its own wet of modes631		.mask    = 0x0f,632	},633	.fan_mode = {634		.address = 0xf4,635		.modes = {636			{ FM_AUTO_NAME,     0x0d }, // d may not be relevant637			{ FM_SILENT_NAME,   0x1d },638			{ FM_ADVANCED_NAME, 0x8d },639			MSI_EC_MODE_NULL640		},641	},642	.cpu = {643		.rt_temp_address       = 0x68,644		.rt_fan_speed_address  = 0xc9, // needs testing645		.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 670static const char * const ALLOWED_FW_8[] __initconst = {671	"14F1EMS1.115",672	NULL673};674 675static 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_NULL704		},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_NULL717		},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 functional742		.state_base_value = 0x80,743		.max_state        = 3,744	},745};746 747static const char * const ALLOWED_FW_9[] __initconst = {748	"14JKEMS1.104",749	NULL750};751 752static 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_NULL781		},782	},783	.super_battery = {784		.address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift785		.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_NULL794		},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 app816		.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 824static const char * const ALLOWED_FW_10[] __initconst = {825	"1582EMS1.107", // GF66 11UC826	NULL827};828 829static 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_NULL859		},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_NULL872		},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 902static const char * const ALLOWED_FW_11[] __initconst = {903	"16S6EMS1.111", // Prestige 15 a11scx904	"1552EMS1.115", // Modern 15 a11m905	NULL906};907 908static 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_NULL937		},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_NULL950		},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 976static const char * const ALLOWED_FW_12[] __initconst = {977	"16R6EMS1.104", // GF63 Thin 11UC978	NULL979};980 981static 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_NULL1011		},1012	},1013	.super_battery = {1014		.address = MSI_EC_ADDR_UNSUPP, // 0xeb1015		.mask    = 0x0f, // 00, 0f1016	},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_NULL1024		},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 1054static const char * const ALLOWED_FW_13[] __initconst = {1055	"1594EMS1.109", // MSI Prestige 16 Studio A13VE1056	NULL1057};1058 1059static 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-0x101076	},1077	.cooler_boost = {1078		.address = 0x98,1079		.bit     = 7,1080	},1081	.shift_mode = {1082		.address = 0xd2,1083		.modes = {1084			{ SM_ECO_NAME,     0xc2 }, // super battery1085			{ SM_COMFORT_NAME, 0xc1 }, // balanced1086			{ SM_TURBO_NAME,   0xc4 }, // extreme1087			MSI_EC_MODE_NULL1088		},1089	},1090	.super_battery = {1091		.address = MSI_EC_ADDR_UNSUPP,1092		.mask    = 0x0f, // 00, 0f1093	},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_NULL1101		},1102	},1103	.cpu = {1104		.rt_temp_address       = 0x68,1105		.rt_fan_speed_address  = 0x71, // 0x0-0x961106		.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 off1123		.bl_modes         = { 0x00, 0x08 }, // always on; off after 10 sec1124		.max_mode         = 1,1125		.bl_state_address = 0xd3,1126		.state_base_value = 0x80,1127		.max_state        = 3,1128	},1129};1130 1131static 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	NULL1147};1148 1149static struct msi_ec_conf conf; // current configuration1150 1151/*1152 * Helper functions1153 */1154 1155static 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 1168static 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 subsystem1184 */1185 1186static 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 1201static 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 1225static 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 1233static 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 1241static 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 1249static 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 1257static DEVICE_ATTR_RW(charge_control_start_threshold);1258static DEVICE_ATTR_RW(charge_control_end_threshold);1259 1260static struct attribute *msi_battery_attrs[] = {1261	&dev_attr_charge_control_start_threshold.attr,1262	&dev_attr_charge_control_end_threshold.attr,1263	NULL1264};1265 1266ATTRIBUTE_GROUPS(msi_battery);1267 1268static 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 1274static 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 1281static 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/unload1289 */1290 1291static 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};1304MODULE_DEVICE_TABLE(dmi, msi_dmi_table);1305 1306static 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 1339static 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 1351static void __exit msi_ec_exit(void)1352{1353	battery_hook_unregister(&battery_hook);1354}1355 1356MODULE_LICENSE("GPL");1357MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>");1358MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>");1359MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>");1360MODULE_DESCRIPTION("MSI Embedded Controller");1361 1362module_init(msi_ec_init);1363module_exit(msi_ec_exit);1364