| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * msi-ec: MSI laptops' embedded controller driver.
- *
- * This driver allows various MSI laptops' functionalities to be
- * controlled from userspace.
- *
- * It contains EC memory configurations for different firmware versions
- * and exports battery charge thresholds to userspace.
- *
- * Copyright (C) 2023 Jose Angel Pastrana <japp0005@red.ujaen.es>
- * Copyright (C) 2023 Aakash Singh <mail@singhaakash.dev>
- * Copyright (C) 2023 Nikita Kravets <teackot@gmail.com>
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #include "msi-ec.h"
- #include <acpi/battery.h>
- #include <linux/acpi.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/seq_file.h>
- #include <linux/string.h>
- #define SM_ECO_NAME "eco"
- #define SM_COMFORT_NAME "comfort"
- #define SM_SPORT_NAME "sport"
- #define SM_TURBO_NAME "turbo"
- #define FM_AUTO_NAME "auto"
- #define FM_SILENT_NAME "silent"
- #define FM_BASIC_NAME "basic"
- #define FM_ADVANCED_NAME "advanced"
- static const char * const ALLOWED_FW_0[] __initconst = {
- "14C1EMS1.012",
- "14C1EMS1.101",
- "14C1EMS1.102",
- NULL
- };
- static struct msi_ec_conf CONF0 __initdata = {
- .allowed_fw = ALLOWED_FW_0,
- .charge_control = {
- .address = 0xef,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xbf,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xf2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = MSI_EC_ADDR_UNKNOWN, // 0xd5 needs testing
- },
- .fan_mode = {
- .address = 0xf4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_BASIC_NAME, 0x4d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71,
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = 0x89,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = 0x89,
- },
- .leds = {
- .micmute_led_address = 0x2b,
- .mute_led_address = 0x2c,
- .bit = 2,
- },
- .kbd_bl = {
- .bl_mode_address = 0x2c, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = 0xf3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_1[] __initconst = {
- "17F2EMS1.103",
- "17F2EMS1.104",
- "17F2EMS1.106",
- "17F2EMS1.107",
- NULL
- };
- static struct msi_ec_conf CONF1 __initdata = {
- .allowed_fw = ALLOWED_FW_1,
- .charge_control = {
- .address = 0xef,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xbf,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xf2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- { SM_TURBO_NAME, 0xc4 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = MSI_EC_ADDR_UNKNOWN,
- },
- .fan_mode = {
- .address = 0xf4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_BASIC_NAME, 0x4d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71,
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = 0x89,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = 0x89,
- },
- .leds = {
- .micmute_led_address = 0x2b,
- .mute_led_address = 0x2c,
- .bit = 2,
- },
- .kbd_bl = {
- .bl_mode_address = 0x2c, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = 0xf3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_2[] __initconst = {
- "1552EMS1.118",
- NULL
- };
- static struct msi_ec_conf CONF2 __initdata = {
- .allowed_fw = ALLOWED_FW_2,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xe8,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xf2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = 0xeb,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_BASIC_NAME, 0x4d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71,
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = 0x89,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = 0x89,
- },
- .leds = {
- .micmute_led_address = 0x2c,
- .mute_led_address = 0x2d,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = 0x2c, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = 0xd3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_3[] __initconst = {
- "1592EMS1.111",
- NULL
- };
- static struct msi_ec_conf CONF3 __initdata = {
- .allowed_fw = ALLOWED_FW_3,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xe8,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xd2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = 0xeb,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_BASIC_NAME, 0x4d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0xc9,
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = 0x89, // ?
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = 0x89,
- },
- .leds = {
- .micmute_led_address = 0x2b,
- .mute_led_address = 0x2c,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = 0x2c, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = 0xd3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_4[] __initconst = {
- "16V4EMS1.114",
- NULL
- };
- static struct msi_ec_conf CONF4 __initdata = {
- .allowed_fw = ALLOWED_FW_4,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = MSI_EC_ADDR_UNKNOWN, // supported, but unknown
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xd2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = { // may be supported, but address is unknown
- .address = MSI_EC_ADDR_UNKNOWN,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68, // needs testing
- .rt_fan_speed_address = 0x71, // needs testing
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
- },
- .leds = {
- .micmute_led_address = MSI_EC_ADDR_UNKNOWN,
- .mute_led_address = MSI_EC_ADDR_UNKNOWN,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = MSI_EC_ADDR_UNSUPP, // 0xd3, not functional
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_5[] __initconst = {
- "158LEMS1.103",
- "158LEMS1.105",
- "158LEMS1.106",
- NULL
- };
- static struct msi_ec_conf CONF5 __initdata = {
- .allowed_fw = ALLOWED_FW_5,
- .charge_control = {
- .address = 0xef,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = { // todo: reverse
- .address = 0xbf,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xf2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_TURBO_NAME, 0xc4 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = { // unsupported?
- .address = MSI_EC_ADDR_UNKNOWN,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xf4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68, // needs testing
- .rt_fan_speed_address = 0x71, // needs testing
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = MSI_EC_ADDR_UNKNOWN,
- .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
- },
- .leds = {
- .micmute_led_address = 0x2b,
- .mute_led_address = 0x2c,
- .bit = 2,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = MSI_EC_ADDR_UNSUPP, // 0xf3, not functional
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_6[] __initconst = {
- "1542EMS1.102",
- "1542EMS1.104",
- NULL
- };
- static struct msi_ec_conf CONF6 __initdata = {
- .allowed_fw = ALLOWED_FW_6,
- .charge_control = {
- .address = 0xef,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = MSI_EC_ADDR_UNSUPP,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xbf, // todo: reverse
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xf2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- { SM_TURBO_NAME, 0xc4 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = 0xd5,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xf4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0xc9,
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
- },
- .leds = {
- .micmute_led_address = MSI_EC_ADDR_UNSUPP,
- .mute_led_address = MSI_EC_ADDR_UNSUPP,
- .bit = 2,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = MSI_EC_ADDR_UNSUPP, // 0xf3, not functional
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_7[] __initconst = {
- "17FKEMS1.108",
- "17FKEMS1.109",
- "17FKEMS1.10A",
- NULL
- };
- static struct msi_ec_conf CONF7 __initdata = {
- .allowed_fw = ALLOWED_FW_7,
- .charge_control = {
- .address = 0xef,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = MSI_EC_ADDR_UNSUPP,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xbf, // needs testing
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xf2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- { SM_TURBO_NAME, 0xc4 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = MSI_EC_ADDR_UNKNOWN, // 0xd5 but has its own wet of modes
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xf4,
- .modes = {
- { FM_AUTO_NAME, 0x0d }, // d may not be relevant
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0xc9, // needs testing
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = MSI_EC_ADDR_UNKNOWN,
- .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
- },
- .leds = {
- .micmute_led_address = MSI_EC_ADDR_UNSUPP,
- .mute_led_address = 0x2c,
- .bit = 2,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = 0xf3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_8[] __initconst = {
- "14F1EMS1.115",
- NULL
- };
- static struct msi_ec_conf CONF8 __initdata = {
- .allowed_fw = ALLOWED_FW_8,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = MSI_EC_ADDR_UNSUPP,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xe8,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xd2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = 0xeb,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_BASIC_NAME, 0x4d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71,
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = MSI_EC_ADDR_UNKNOWN,
- .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN,
- },
- .leds = {
- .micmute_led_address = MSI_EC_ADDR_UNSUPP,
- .mute_led_address = 0x2d,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ?
- .bl_modes = { 0x00, 0x08 }, // ?
- .max_mode = 1, // ?
- .bl_state_address = MSI_EC_ADDR_UNSUPP, // not functional
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_9[] __initconst = {
- "14JKEMS1.104",
- NULL
- };
- static struct msi_ec_conf CONF9 __initdata = {
- .allowed_fw = ALLOWED_FW_9,
- .charge_control = {
- .address = 0xef,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xbf,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xf2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xf4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71,
- .rt_fan_speed_base_min = 0x00,
- .rt_fan_speed_base_max = 0x96,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = MSI_EC_ADDR_UNSUPP,
- .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- },
- .leds = {
- .micmute_led_address = 0x2b,
- .mute_led_address = 0x2c,
- .bit = 2,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNSUPP, // not presented in MSI app
- .bl_modes = { 0x00, 0x08 },
- .max_mode = 1,
- .bl_state_address = 0xf3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_10[] __initconst = {
- "1582EMS1.107", // GF66 11UC
- NULL
- };
- static struct msi_ec_conf CONF10 __initdata = {
- .allowed_fw = ALLOWED_FW_10,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = MSI_EC_ADDR_UNSUPP,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xd2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- { SM_TURBO_NAME, 0xc4 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = 0xe5,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71, // ?
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ?
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = 0x89,
- },
- .leds = {
- .micmute_led_address = 0x2c,
- .mute_led_address = 0x2d,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = 0x2c,
- .bl_modes = { 0x00, 0x08 },
- .max_mode = 1,
- .bl_state_address = 0xd3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_11[] __initconst = {
- "16S6EMS1.111", // Prestige 15 a11scx
- "1552EMS1.115", // Modern 15 a11m
- NULL
- };
- static struct msi_ec_conf CONF11 __initdata = {
- .allowed_fw = ALLOWED_FW_11,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = MSI_EC_ADDR_UNKNOWN,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xe8,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xd2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = 0xeb,
- .mask = 0x0f,
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x4d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- },
- .gpu = {
- .rt_temp_address = MSI_EC_ADDR_UNSUPP,
- .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- },
- .leds = {
- .micmute_led_address = 0x2c,
- .mute_led_address = 0x2d,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNKNOWN,
- .bl_modes = {}, // ?
- .max_mode = 1, // ?
- .bl_state_address = 0xd3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_12[] __initconst = {
- "16R6EMS1.104", // GF63 Thin 11UC
- NULL
- };
- static struct msi_ec_conf CONF12 __initdata = {
- .allowed_fw = ALLOWED_FW_12,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xe8,
- .bit = 4,
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xd2,
- .modes = {
- { SM_ECO_NAME, 0xc2 },
- { SM_COMFORT_NAME, 0xc1 },
- { SM_SPORT_NAME, 0xc0 },
- { SM_TURBO_NAME, 0xc4 },
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = MSI_EC_ADDR_UNSUPP, // 0xeb
- .mask = 0x0f, // 00, 0f
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71,
- .rt_fan_speed_base_min = 0x19,
- .rt_fan_speed_base_max = 0x37,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = MSI_EC_ADDR_UNSUPP,
- .rt_fan_speed_address = 0x89,
- },
- .leds = {
- .micmute_led_address = MSI_EC_ADDR_UNSUPP,
- .mute_led_address = 0x2d,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = MSI_EC_ADDR_UNKNOWN,
- .bl_modes = { 0x00, 0x08 },
- .max_mode = 1,
- .bl_state_address = 0xd3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static const char * const ALLOWED_FW_13[] __initconst = {
- "1594EMS1.109", // MSI Prestige 16 Studio A13VE
- NULL
- };
- static struct msi_ec_conf CONF13 __initdata = {
- .allowed_fw = ALLOWED_FW_13,
- .charge_control = {
- .address = 0xd7,
- .offset_start = 0x8a,
- .offset_end = 0x80,
- .range_min = 0x8a,
- .range_max = 0xe4,
- },
- .webcam = {
- .address = 0x2e,
- .block_address = 0x2f,
- .bit = 1,
- },
- .fn_win_swap = {
- .address = 0xe8,
- .bit = 4, // 0x00-0x10
- },
- .cooler_boost = {
- .address = 0x98,
- .bit = 7,
- },
- .shift_mode = {
- .address = 0xd2,
- .modes = {
- { SM_ECO_NAME, 0xc2 }, // super battery
- { SM_COMFORT_NAME, 0xc1 }, // balanced
- { SM_TURBO_NAME, 0xc4 }, // extreme
- MSI_EC_MODE_NULL
- },
- },
- .super_battery = {
- .address = MSI_EC_ADDR_UNSUPP,
- .mask = 0x0f, // 00, 0f
- },
- .fan_mode = {
- .address = 0xd4,
- .modes = {
- { FM_AUTO_NAME, 0x0d },
- { FM_SILENT_NAME, 0x1d },
- { FM_ADVANCED_NAME, 0x8d },
- MSI_EC_MODE_NULL
- },
- },
- .cpu = {
- .rt_temp_address = 0x68,
- .rt_fan_speed_address = 0x71, // 0x0-0x96
- .rt_fan_speed_base_min = 0x00,
- .rt_fan_speed_base_max = 0x96,
- .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP,
- .bs_fan_speed_base_min = 0x00,
- .bs_fan_speed_base_max = 0x0f,
- },
- .gpu = {
- .rt_temp_address = 0x80,
- .rt_fan_speed_address = 0x89,
- },
- .leds = {
- .micmute_led_address = 0x2c,
- .mute_led_address = 0x2d,
- .bit = 1,
- },
- .kbd_bl = {
- .bl_mode_address = 0x2c, // KB auto turn off
- .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec
- .max_mode = 1,
- .bl_state_address = 0xd3,
- .state_base_value = 0x80,
- .max_state = 3,
- },
- };
- static struct msi_ec_conf *CONFIGS[] __initdata = {
- &CONF0,
- &CONF1,
- &CONF2,
- &CONF3,
- &CONF4,
- &CONF5,
- &CONF6,
- &CONF7,
- &CONF8,
- &CONF9,
- &CONF10,
- &CONF11,
- &CONF12,
- &CONF13,
- NULL
- };
- static struct msi_ec_conf conf; // current configuration
- /*
- * Helper functions
- */
- static int ec_read_seq(u8 addr, u8 *buf, u8 len)
- {
- int result;
- for (u8 i = 0; i < len; i++) {
- result = ec_read(addr + i, buf + i);
- if (result < 0)
- return result;
- }
- return 0;
- }
- static int ec_get_firmware_version(u8 buf[MSI_EC_FW_VERSION_LENGTH + 1])
- {
- int result;
- memset(buf, 0, MSI_EC_FW_VERSION_LENGTH + 1);
- result = ec_read_seq(MSI_EC_FW_VERSION_ADDRESS,
- buf,
- MSI_EC_FW_VERSION_LENGTH);
- if (result < 0)
- return result;
- return MSI_EC_FW_VERSION_LENGTH + 1;
- }
- /*
- * Sysfs power_supply subsystem
- */
- static ssize_t charge_control_threshold_show(u8 offset,
- struct device *device,
- struct device_attribute *attr,
- char *buf)
- {
- u8 rdata;
- int result;
- result = ec_read(conf.charge_control.address, &rdata);
- if (result < 0)
- return result;
- return sysfs_emit(buf, "%i\n", rdata - offset);
- }
- static ssize_t charge_control_threshold_store(u8 offset,
- struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- u8 wdata;
- int result;
- result = kstrtou8(buf, 10, &wdata);
- if (result < 0)
- return result;
- wdata += offset;
- if (wdata < conf.charge_control.range_min ||
- wdata > conf.charge_control.range_max)
- return -EINVAL;
- result = ec_write(conf.charge_control.address, wdata);
- if (result < 0)
- return result;
- return count;
- }
- static ssize_t charge_control_start_threshold_show(struct device *device,
- struct device_attribute *attr,
- char *buf)
- {
- return charge_control_threshold_show(conf.charge_control.offset_start,
- device, attr, buf);
- }
- static ssize_t charge_control_start_threshold_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- return charge_control_threshold_store(conf.charge_control.offset_start,
- dev, attr, buf, count);
- }
- static ssize_t charge_control_end_threshold_show(struct device *device,
- struct device_attribute *attr,
- char *buf)
- {
- return charge_control_threshold_show(conf.charge_control.offset_end,
- device, attr, buf);
- }
- static ssize_t charge_control_end_threshold_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- return charge_control_threshold_store(conf.charge_control.offset_end,
- dev, attr, buf, count);
- }
- static DEVICE_ATTR_RW(charge_control_start_threshold);
- static DEVICE_ATTR_RW(charge_control_end_threshold);
- static struct attribute *msi_battery_attrs[] = {
- &dev_attr_charge_control_start_threshold.attr,
- &dev_attr_charge_control_end_threshold.attr,
- NULL
- };
- ATTRIBUTE_GROUPS(msi_battery);
- static int msi_battery_add(struct power_supply *battery,
- struct acpi_battery_hook *hook)
- {
- return device_add_groups(&battery->dev, msi_battery_groups);
- }
- static int msi_battery_remove(struct power_supply *battery,
- struct acpi_battery_hook *hook)
- {
- device_remove_groups(&battery->dev, msi_battery_groups);
- return 0;
- }
- static struct acpi_battery_hook battery_hook = {
- .add_battery = msi_battery_add,
- .remove_battery = msi_battery_remove,
- .name = MSI_EC_DRIVER_NAME,
- };
- /*
- * Module load/unload
- */
- static const struct dmi_system_id msi_dmi_table[] __initconst __maybe_unused = {
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
- },
- },
- {}
- };
- MODULE_DEVICE_TABLE(dmi, msi_dmi_table);
- static int __init load_configuration(void)
- {
- int result;
- u8 fw_version[MSI_EC_FW_VERSION_LENGTH + 1];
- /* get firmware version */
- result = ec_get_firmware_version(fw_version);
- if (result < 0)
- return result;
- /* load the suitable configuration, if exists */
- for (int i = 0; CONFIGS[i]; i++) {
- if (match_string(CONFIGS[i]->allowed_fw, -1, fw_version) != -EINVAL) {
- conf = *CONFIGS[i];
- conf.allowed_fw = NULL;
- return 0;
- }
- }
- /* config not found */
- for (int i = 0; i < MSI_EC_FW_VERSION_LENGTH; i++) {
- if (!isgraph(fw_version[i])) {
- pr_warn("Unable to find a valid firmware version!\n");
- return -EOPNOTSUPP;
- }
- }
- pr_warn("Firmware version is not supported: '%s'\n", fw_version);
- return -EOPNOTSUPP;
- }
- static int __init msi_ec_init(void)
- {
- int result;
- result = load_configuration();
- if (result < 0)
- return result;
- battery_hook_register(&battery_hook);
- return 0;
- }
- static void __exit msi_ec_exit(void)
- {
- battery_hook_unregister(&battery_hook);
- }
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>");
- MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>");
- MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>");
- MODULE_DESCRIPTION("MSI Embedded Controller");
- module_init(msi_ec_init);
- module_exit(msi_ec_exit);
|