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/device-id/dmi.h> 27 #include <linux/platform_device.h> 28 #include <linux/seq_file.h> 29 #include <linux/string.h> 30 31 #define SM_ECO_NAME "eco" 32 #define SM_COMFORT_NAME "comfort" 33 #define SM_SPORT_NAME "sport" 34 #define SM_TURBO_NAME "turbo" 35 36 #define FM_AUTO_NAME "auto" 37 #define FM_SILENT_NAME "silent" 38 #define FM_BASIC_NAME "basic" 39 #define FM_ADVANCED_NAME "advanced" 40 41 static const char * const ALLOWED_FW_0[] __initconst = { 42 "14C1EMS1.012", 43 "14C1EMS1.101", 44 "14C1EMS1.102", 45 NULL 46 }; 47 48 static struct msi_ec_conf CONF0 __initdata = { 49 .allowed_fw = ALLOWED_FW_0, 50 .charge_control = { 51 .address = 0xef, 52 .offset_start = 0x8a, 53 .offset_end = 0x80, 54 .range_min = 0x8a, 55 .range_max = 0xe4, 56 }, 57 .webcam = { 58 .address = 0x2e, 59 .block_address = 0x2f, 60 .bit = 1, 61 }, 62 .fn_win_swap = { 63 .address = 0xbf, 64 .bit = 4, 65 }, 66 .cooler_boost = { 67 .address = 0x98, 68 .bit = 7, 69 }, 70 .shift_mode = { 71 .address = 0xf2, 72 .modes = { 73 { SM_ECO_NAME, 0xc2 }, 74 { SM_COMFORT_NAME, 0xc1 }, 75 { SM_SPORT_NAME, 0xc0 }, 76 MSI_EC_MODE_NULL 77 }, 78 }, 79 .super_battery = { 80 .address = MSI_EC_ADDR_UNKNOWN, // 0xd5 needs testing 81 }, 82 .fan_mode = { 83 .address = 0xf4, 84 .modes = { 85 { FM_AUTO_NAME, 0x0d }, 86 { FM_SILENT_NAME, 0x1d }, 87 { FM_BASIC_NAME, 0x4d }, 88 { FM_ADVANCED_NAME, 0x8d }, 89 MSI_EC_MODE_NULL 90 }, 91 }, 92 .cpu = { 93 .rt_temp_address = 0x68, 94 .rt_fan_speed_address = 0x71, 95 .rt_fan_speed_base_min = 0x19, 96 .rt_fan_speed_base_max = 0x37, 97 .bs_fan_speed_address = 0x89, 98 .bs_fan_speed_base_min = 0x00, 99 .bs_fan_speed_base_max = 0x0f, 100 }, 101 .gpu = { 102 .rt_temp_address = 0x80, 103 .rt_fan_speed_address = 0x89, 104 }, 105 .leds = { 106 .micmute_led_address = 0x2b, 107 .mute_led_address = 0x2c, 108 .bit = 2, 109 }, 110 .kbd_bl = { 111 .bl_mode_address = 0x2c, // ? 112 .bl_modes = { 0x00, 0x08 }, // ? 113 .max_mode = 1, // ? 114 .bl_state_address = 0xf3, 115 .state_base_value = 0x80, 116 .max_state = 3, 117 }, 118 }; 119 120 static const char * const ALLOWED_FW_1[] __initconst = { 121 "17F2EMS1.103", 122 "17F2EMS1.104", 123 "17F2EMS1.106", 124 "17F2EMS1.107", 125 NULL 126 }; 127 128 static struct msi_ec_conf CONF1 __initdata = { 129 .allowed_fw = ALLOWED_FW_1, 130 .charge_control = { 131 .address = 0xef, 132 .offset_start = 0x8a, 133 .offset_end = 0x80, 134 .range_min = 0x8a, 135 .range_max = 0xe4, 136 }, 137 .webcam = { 138 .address = 0x2e, 139 .block_address = 0x2f, 140 .bit = 1, 141 }, 142 .fn_win_swap = { 143 .address = 0xbf, 144 .bit = 4, 145 }, 146 .cooler_boost = { 147 .address = 0x98, 148 .bit = 7, 149 }, 150 .shift_mode = { 151 .address = 0xf2, 152 .modes = { 153 { SM_ECO_NAME, 0xc2 }, 154 { SM_COMFORT_NAME, 0xc1 }, 155 { SM_SPORT_NAME, 0xc0 }, 156 { SM_TURBO_NAME, 0xc4 }, 157 MSI_EC_MODE_NULL 158 }, 159 }, 160 .super_battery = { 161 .address = MSI_EC_ADDR_UNKNOWN, 162 }, 163 .fan_mode = { 164 .address = 0xf4, 165 .modes = { 166 { FM_AUTO_NAME, 0x0d }, 167 { FM_BASIC_NAME, 0x4d }, 168 { FM_ADVANCED_NAME, 0x8d }, 169 MSI_EC_MODE_NULL 170 }, 171 }, 172 .cpu = { 173 .rt_temp_address = 0x68, 174 .rt_fan_speed_address = 0x71, 175 .rt_fan_speed_base_min = 0x19, 176 .rt_fan_speed_base_max = 0x37, 177 .bs_fan_speed_address = 0x89, 178 .bs_fan_speed_base_min = 0x00, 179 .bs_fan_speed_base_max = 0x0f, 180 }, 181 .gpu = { 182 .rt_temp_address = 0x80, 183 .rt_fan_speed_address = 0x89, 184 }, 185 .leds = { 186 .micmute_led_address = 0x2b, 187 .mute_led_address = 0x2c, 188 .bit = 2, 189 }, 190 .kbd_bl = { 191 .bl_mode_address = 0x2c, // ? 192 .bl_modes = { 0x00, 0x08 }, // ? 193 .max_mode = 1, // ? 194 .bl_state_address = 0xf3, 195 .state_base_value = 0x80, 196 .max_state = 3, 197 }, 198 }; 199 200 static const char * const ALLOWED_FW_2[] __initconst = { 201 "1552EMS1.118", 202 NULL 203 }; 204 205 static struct msi_ec_conf CONF2 __initdata = { 206 .allowed_fw = ALLOWED_FW_2, 207 .charge_control = { 208 .address = 0xd7, 209 .offset_start = 0x8a, 210 .offset_end = 0x80, 211 .range_min = 0x8a, 212 .range_max = 0xe4, 213 }, 214 .webcam = { 215 .address = 0x2e, 216 .block_address = 0x2f, 217 .bit = 1, 218 }, 219 .fn_win_swap = { 220 .address = 0xe8, 221 .bit = 4, 222 }, 223 .cooler_boost = { 224 .address = 0x98, 225 .bit = 7, 226 }, 227 .shift_mode = { 228 .address = 0xf2, 229 .modes = { 230 { SM_ECO_NAME, 0xc2 }, 231 { SM_COMFORT_NAME, 0xc1 }, 232 { SM_SPORT_NAME, 0xc0 }, 233 MSI_EC_MODE_NULL 234 }, 235 }, 236 .super_battery = { 237 .address = 0xeb, 238 .mask = 0x0f, 239 }, 240 .fan_mode = { 241 .address = 0xd4, 242 .modes = { 243 { FM_AUTO_NAME, 0x0d }, 244 { FM_SILENT_NAME, 0x1d }, 245 { FM_BASIC_NAME, 0x4d }, 246 { FM_ADVANCED_NAME, 0x8d }, 247 MSI_EC_MODE_NULL 248 }, 249 }, 250 .cpu = { 251 .rt_temp_address = 0x68, 252 .rt_fan_speed_address = 0x71, 253 .rt_fan_speed_base_min = 0x19, 254 .rt_fan_speed_base_max = 0x37, 255 .bs_fan_speed_address = 0x89, 256 .bs_fan_speed_base_min = 0x00, 257 .bs_fan_speed_base_max = 0x0f, 258 }, 259 .gpu = { 260 .rt_temp_address = 0x80, 261 .rt_fan_speed_address = 0x89, 262 }, 263 .leds = { 264 .micmute_led_address = 0x2c, 265 .mute_led_address = 0x2d, 266 .bit = 1, 267 }, 268 .kbd_bl = { 269 .bl_mode_address = 0x2c, // ? 270 .bl_modes = { 0x00, 0x08 }, // ? 271 .max_mode = 1, // ? 272 .bl_state_address = 0xd3, 273 .state_base_value = 0x80, 274 .max_state = 3, 275 }, 276 }; 277 278 static const char * const ALLOWED_FW_3[] __initconst = { 279 "1592EMS1.111", 280 NULL 281 }; 282 283 static struct msi_ec_conf CONF3 __initdata = { 284 .allowed_fw = ALLOWED_FW_3, 285 .charge_control = { 286 .address = 0xd7, 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_win_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_win_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_win_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_win_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_win_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 const char * const ALLOWED_FW_8[] __initconst = { 672 "14F1EMS1.115", 673 NULL 674 }; 675 676 static struct msi_ec_conf CONF8 __initdata = { 677 .allowed_fw = ALLOWED_FW_8, 678 .charge_control = { 679 .address = 0xd7, 680 .offset_start = 0x8a, 681 .offset_end = 0x80, 682 .range_min = 0x8a, 683 .range_max = 0xe4, 684 }, 685 .webcam = { 686 .address = 0x2e, 687 .block_address = MSI_EC_ADDR_UNSUPP, 688 .bit = 1, 689 }, 690 .fn_win_swap = { 691 .address = 0xe8, 692 .bit = 4, 693 }, 694 .cooler_boost = { 695 .address = 0x98, 696 .bit = 7, 697 }, 698 .shift_mode = { 699 .address = 0xd2, 700 .modes = { 701 { SM_ECO_NAME, 0xc2 }, 702 { SM_COMFORT_NAME, 0xc1 }, 703 { SM_SPORT_NAME, 0xc0 }, 704 MSI_EC_MODE_NULL 705 }, 706 }, 707 .super_battery = { 708 .address = 0xeb, 709 .mask = 0x0f, 710 }, 711 .fan_mode = { 712 .address = 0xd4, 713 .modes = { 714 { FM_AUTO_NAME, 0x0d }, 715 { FM_SILENT_NAME, 0x1d }, 716 { FM_BASIC_NAME, 0x4d }, 717 MSI_EC_MODE_NULL 718 }, 719 }, 720 .cpu = { 721 .rt_temp_address = 0x68, 722 .rt_fan_speed_address = 0x71, 723 .rt_fan_speed_base_min = 0x19, 724 .rt_fan_speed_base_max = 0x37, 725 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 726 .bs_fan_speed_base_min = 0x00, 727 .bs_fan_speed_base_max = 0x0f, 728 }, 729 .gpu = { 730 .rt_temp_address = MSI_EC_ADDR_UNKNOWN, 731 .rt_fan_speed_address = MSI_EC_ADDR_UNKNOWN, 732 }, 733 .leds = { 734 .micmute_led_address = MSI_EC_ADDR_UNSUPP, 735 .mute_led_address = 0x2d, 736 .bit = 1, 737 }, 738 .kbd_bl = { 739 .bl_mode_address = MSI_EC_ADDR_UNKNOWN, // ? 740 .bl_modes = { 0x00, 0x08 }, // ? 741 .max_mode = 1, // ? 742 .bl_state_address = MSI_EC_ADDR_UNSUPP, // not functional 743 .state_base_value = 0x80, 744 .max_state = 3, 745 }, 746 }; 747 748 static const char * const ALLOWED_FW_9[] __initconst = { 749 "14JKEMS1.104", 750 NULL 751 }; 752 753 static struct msi_ec_conf CONF9 __initdata = { 754 .allowed_fw = ALLOWED_FW_9, 755 .charge_control = { 756 .address = 0xef, 757 .offset_start = 0x8a, 758 .offset_end = 0x80, 759 .range_min = 0x8a, 760 .range_max = 0xe4, 761 }, 762 .webcam = { 763 .address = 0x2e, 764 .block_address = 0x2f, 765 .bit = 1, 766 }, 767 .fn_win_swap = { 768 .address = 0xbf, 769 .bit = 4, 770 }, 771 .cooler_boost = { 772 .address = 0x98, 773 .bit = 7, 774 }, 775 .shift_mode = { 776 .address = 0xf2, 777 .modes = { 778 { SM_ECO_NAME, 0xc2 }, 779 { SM_COMFORT_NAME, 0xc1 }, 780 { SM_SPORT_NAME, 0xc0 }, 781 MSI_EC_MODE_NULL 782 }, 783 }, 784 .super_battery = { 785 .address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift 786 .mask = 0x0f, 787 }, 788 .fan_mode = { 789 .address = 0xf4, 790 .modes = { 791 { FM_AUTO_NAME, 0x0d }, 792 { FM_SILENT_NAME, 0x1d }, 793 { FM_ADVANCED_NAME, 0x8d }, 794 MSI_EC_MODE_NULL 795 }, 796 }, 797 .cpu = { 798 .rt_temp_address = 0x68, 799 .rt_fan_speed_address = 0x71, 800 .rt_fan_speed_base_min = 0x00, 801 .rt_fan_speed_base_max = 0x96, 802 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 803 .bs_fan_speed_base_min = 0x00, 804 .bs_fan_speed_base_max = 0x0f, 805 }, 806 .gpu = { 807 .rt_temp_address = MSI_EC_ADDR_UNSUPP, 808 .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, 809 }, 810 .leds = { 811 .micmute_led_address = 0x2b, 812 .mute_led_address = 0x2c, 813 .bit = 2, 814 }, 815 .kbd_bl = { 816 .bl_mode_address = MSI_EC_ADDR_UNSUPP, // not presented in MSI app 817 .bl_modes = { 0x00, 0x08 }, 818 .max_mode = 1, 819 .bl_state_address = 0xf3, 820 .state_base_value = 0x80, 821 .max_state = 3, 822 }, 823 }; 824 825 static const char * const ALLOWED_FW_10[] __initconst = { 826 "1582EMS1.107", // GF66 11UC 827 "1583EMS1.109", // Pulse GL66 12UEK 828 NULL 829 }; 830 831 static struct msi_ec_conf CONF10 __initdata = { 832 .allowed_fw = ALLOWED_FW_10, 833 .charge_control = { 834 .address = 0xd7, 835 .offset_start = 0x8a, 836 .offset_end = 0x80, 837 .range_min = 0x8a, 838 .range_max = 0xe4, 839 }, 840 .webcam = { 841 .address = 0x2e, 842 .block_address = 0x2f, 843 .bit = 1, 844 }, 845 .fn_win_swap = { 846 .address = MSI_EC_ADDR_UNSUPP, 847 .bit = 4, 848 }, 849 .cooler_boost = { 850 .address = 0x98, 851 .bit = 7, 852 }, 853 .shift_mode = { 854 .address = 0xd2, 855 .modes = { 856 { SM_ECO_NAME, 0xc2 }, 857 { SM_COMFORT_NAME, 0xc1 }, 858 { SM_SPORT_NAME, 0xc0 }, 859 { SM_TURBO_NAME, 0xc4 }, 860 MSI_EC_MODE_NULL 861 }, 862 }, 863 .super_battery = { 864 .address = 0xe5, 865 .mask = 0x0f, 866 }, 867 .fan_mode = { 868 .address = 0xd4, 869 .modes = { 870 { FM_AUTO_NAME, 0x0d }, 871 { FM_SILENT_NAME, 0x1d }, 872 { FM_ADVANCED_NAME, 0x8d }, 873 MSI_EC_MODE_NULL 874 }, 875 }, 876 .cpu = { 877 .rt_temp_address = 0x68, 878 .rt_fan_speed_address = 0x71, // ? 879 .rt_fan_speed_base_min = 0x19, 880 .rt_fan_speed_base_max = 0x37, 881 .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ? 882 .bs_fan_speed_base_min = 0x00, 883 .bs_fan_speed_base_max = 0x0f, 884 }, 885 .gpu = { 886 .rt_temp_address = 0x80, 887 .rt_fan_speed_address = 0x89, 888 }, 889 .leds = { 890 .micmute_led_address = 0x2c, 891 .mute_led_address = 0x2d, 892 .bit = 1, 893 }, 894 .kbd_bl = { 895 .bl_mode_address = 0x2c, 896 .bl_modes = { 0x00, 0x08 }, 897 .max_mode = 1, 898 .bl_state_address = 0xd3, 899 .state_base_value = 0x80, 900 .max_state = 3, 901 }, 902 }; 903 904 static const char * const ALLOWED_FW_11[] __initconst = { 905 "16S6EMS1.111", // Prestige 15 a11scx 906 "1552EMS1.115", // Modern 15 a11m 907 NULL 908 }; 909 910 static struct msi_ec_conf CONF11 __initdata = { 911 .allowed_fw = ALLOWED_FW_11, 912 .charge_control = { 913 .address = 0xd7, 914 .offset_start = 0x8a, 915 .offset_end = 0x80, 916 .range_min = 0x8a, 917 .range_max = 0xe4, 918 }, 919 .webcam = { 920 .address = 0x2e, 921 .block_address = MSI_EC_ADDR_UNKNOWN, 922 .bit = 1, 923 }, 924 .fn_win_swap = { 925 .address = 0xe8, 926 .bit = 4, 927 }, 928 .cooler_boost = { 929 .address = 0x98, 930 .bit = 7, 931 }, 932 .shift_mode = { 933 .address = 0xd2, 934 .modes = { 935 { SM_ECO_NAME, 0xc2 }, 936 { SM_COMFORT_NAME, 0xc1 }, 937 { SM_SPORT_NAME, 0xc0 }, 938 MSI_EC_MODE_NULL 939 }, 940 }, 941 .super_battery = { 942 .address = 0xeb, 943 .mask = 0x0f, 944 }, 945 .fan_mode = { 946 .address = 0xd4, 947 .modes = { 948 { FM_AUTO_NAME, 0x0d }, 949 { FM_SILENT_NAME, 0x1d }, 950 { FM_ADVANCED_NAME, 0x4d }, 951 MSI_EC_MODE_NULL 952 }, 953 }, 954 .cpu = { 955 .rt_temp_address = 0x68, 956 .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, 957 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 958 }, 959 .gpu = { 960 .rt_temp_address = MSI_EC_ADDR_UNSUPP, 961 .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, 962 }, 963 .leds = { 964 .micmute_led_address = 0x2c, 965 .mute_led_address = 0x2d, 966 .bit = 1, 967 }, 968 .kbd_bl = { 969 .bl_mode_address = MSI_EC_ADDR_UNKNOWN, 970 .bl_modes = {}, // ? 971 .max_mode = 1, // ? 972 .bl_state_address = 0xd3, 973 .state_base_value = 0x80, 974 .max_state = 3, 975 }, 976 }; 977 978 static const char * const ALLOWED_FW_12[] __initconst = { 979 "16R6EMS1.104", // GF63 Thin 11UC 980 NULL 981 }; 982 983 static struct msi_ec_conf CONF12 __initdata = { 984 .allowed_fw = ALLOWED_FW_12, 985 .charge_control = { 986 .address = 0xd7, 987 .offset_start = 0x8a, 988 .offset_end = 0x80, 989 .range_min = 0x8a, 990 .range_max = 0xe4, 991 }, 992 .webcam = { 993 .address = 0x2e, 994 .block_address = 0x2f, 995 .bit = 1, 996 }, 997 .fn_win_swap = { 998 .address = 0xe8, 999 .bit = 4, 1000 }, 1001 .cooler_boost = { 1002 .address = 0x98, 1003 .bit = 7, 1004 }, 1005 .shift_mode = { 1006 .address = 0xd2, 1007 .modes = { 1008 { SM_ECO_NAME, 0xc2 }, 1009 { SM_COMFORT_NAME, 0xc1 }, 1010 { SM_SPORT_NAME, 0xc0 }, 1011 { SM_TURBO_NAME, 0xc4 }, 1012 MSI_EC_MODE_NULL 1013 }, 1014 }, 1015 .super_battery = { 1016 .address = MSI_EC_ADDR_UNSUPP, // 0xeb 1017 .mask = 0x0f, // 00, 0f 1018 }, 1019 .fan_mode = { 1020 .address = 0xd4, 1021 .modes = { 1022 { FM_AUTO_NAME, 0x0d }, 1023 { FM_SILENT_NAME, 0x1d }, 1024 { FM_ADVANCED_NAME, 0x8d }, 1025 MSI_EC_MODE_NULL 1026 }, 1027 }, 1028 .cpu = { 1029 .rt_temp_address = 0x68, 1030 .rt_fan_speed_address = 0x71, 1031 .rt_fan_speed_base_min = 0x19, 1032 .rt_fan_speed_base_max = 0x37, 1033 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 1034 .bs_fan_speed_base_min = 0x00, 1035 .bs_fan_speed_base_max = 0x0f, 1036 }, 1037 .gpu = { 1038 .rt_temp_address = MSI_EC_ADDR_UNSUPP, 1039 .rt_fan_speed_address = 0x89, 1040 }, 1041 .leds = { 1042 .micmute_led_address = MSI_EC_ADDR_UNSUPP, 1043 .mute_led_address = 0x2d, 1044 .bit = 1, 1045 }, 1046 .kbd_bl = { 1047 .bl_mode_address = MSI_EC_ADDR_UNKNOWN, 1048 .bl_modes = { 0x00, 0x08 }, 1049 .max_mode = 1, 1050 .bl_state_address = 0xd3, 1051 .state_base_value = 0x80, 1052 .max_state = 3, 1053 }, 1054 }; 1055 1056 static const char * const ALLOWED_FW_13[] __initconst = { 1057 "1594EMS1.109", // MSI Prestige 16 Studio A13VE 1058 NULL 1059 }; 1060 1061 static struct msi_ec_conf CONF13 __initdata = { 1062 .allowed_fw = ALLOWED_FW_13, 1063 .charge_control = { 1064 .address = 0xd7, 1065 .offset_start = 0x8a, 1066 .offset_end = 0x80, 1067 .range_min = 0x8a, 1068 .range_max = 0xe4, 1069 }, 1070 .webcam = { 1071 .address = 0x2e, 1072 .block_address = 0x2f, 1073 .bit = 1, 1074 }, 1075 .fn_win_swap = { 1076 .address = 0xe8, 1077 .bit = 4, // 0x00-0x10 1078 }, 1079 .cooler_boost = { 1080 .address = 0x98, 1081 .bit = 7, 1082 }, 1083 .shift_mode = { 1084 .address = 0xd2, 1085 .modes = { 1086 { SM_ECO_NAME, 0xc2 }, // super battery 1087 { SM_COMFORT_NAME, 0xc1 }, // balanced 1088 { SM_TURBO_NAME, 0xc4 }, // extreme 1089 MSI_EC_MODE_NULL 1090 }, 1091 }, 1092 .super_battery = { 1093 .address = MSI_EC_ADDR_UNSUPP, 1094 .mask = 0x0f, // 00, 0f 1095 }, 1096 .fan_mode = { 1097 .address = 0xd4, 1098 .modes = { 1099 { FM_AUTO_NAME, 0x0d }, 1100 { FM_SILENT_NAME, 0x1d }, 1101 { FM_ADVANCED_NAME, 0x8d }, 1102 MSI_EC_MODE_NULL 1103 }, 1104 }, 1105 .cpu = { 1106 .rt_temp_address = 0x68, 1107 .rt_fan_speed_address = 0x71, // 0x0-0x96 1108 .rt_fan_speed_base_min = 0x00, 1109 .rt_fan_speed_base_max = 0x96, 1110 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 1111 .bs_fan_speed_base_min = 0x00, 1112 .bs_fan_speed_base_max = 0x0f, 1113 }, 1114 .gpu = { 1115 .rt_temp_address = 0x80, 1116 .rt_fan_speed_address = 0x89, 1117 }, 1118 .leds = { 1119 .micmute_led_address = 0x2c, 1120 .mute_led_address = 0x2d, 1121 .bit = 1, 1122 }, 1123 .kbd_bl = { 1124 .bl_mode_address = 0x2c, // KB auto turn off 1125 .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec 1126 .max_mode = 1, 1127 .bl_state_address = 0xd3, 1128 .state_base_value = 0x80, 1129 .max_state = 3, 1130 }, 1131 }; 1132 1133 static struct msi_ec_conf *CONFIGS[] __initdata = { 1134 &CONF0, 1135 &CONF1, 1136 &CONF2, 1137 &CONF3, 1138 &CONF4, 1139 &CONF5, 1140 &CONF6, 1141 &CONF7, 1142 &CONF8, 1143 &CONF9, 1144 &CONF10, 1145 &CONF11, 1146 &CONF12, 1147 &CONF13, 1148 NULL 1149 }; 1150 1151 static struct msi_ec_conf conf; // current configuration 1152 1153 /* 1154 * Helper functions 1155 */ 1156 1157 static int ec_read_seq(u8 addr, u8 *buf, u8 len) 1158 { 1159 int result; 1160 1161 for (u8 i = 0; i < len; i++) { 1162 result = ec_read(addr + i, buf + i); 1163 if (result < 0) 1164 return result; 1165 } 1166 1167 return 0; 1168 } 1169 1170 static int ec_get_firmware_version(u8 buf[MSI_EC_FW_VERSION_LENGTH + 1]) 1171 { 1172 int result; 1173 1174 memset(buf, 0, MSI_EC_FW_VERSION_LENGTH + 1); 1175 result = ec_read_seq(MSI_EC_FW_VERSION_ADDRESS, 1176 buf, 1177 MSI_EC_FW_VERSION_LENGTH); 1178 if (result < 0) 1179 return result; 1180 1181 return MSI_EC_FW_VERSION_LENGTH + 1; 1182 } 1183 1184 /* 1185 * Sysfs power_supply subsystem 1186 */ 1187 1188 static ssize_t charge_control_threshold_show(u8 offset, 1189 struct device *device, 1190 struct device_attribute *attr, 1191 char *buf) 1192 { 1193 u8 rdata; 1194 int result; 1195 1196 result = ec_read(conf.charge_control.address, &rdata); 1197 if (result < 0) 1198 return result; 1199 1200 return sysfs_emit(buf, "%i\n", rdata - offset); 1201 } 1202 1203 static ssize_t charge_control_threshold_store(u8 offset, 1204 struct device *dev, 1205 struct device_attribute *attr, 1206 const char *buf, size_t count) 1207 { 1208 u8 wdata; 1209 int result; 1210 1211 result = kstrtou8(buf, 10, &wdata); 1212 if (result < 0) 1213 return result; 1214 1215 wdata += offset; 1216 if (wdata < conf.charge_control.range_min || 1217 wdata > conf.charge_control.range_max) 1218 return -EINVAL; 1219 1220 result = ec_write(conf.charge_control.address, wdata); 1221 if (result < 0) 1222 return result; 1223 1224 return count; 1225 } 1226 1227 static ssize_t charge_control_start_threshold_show(struct device *device, 1228 struct device_attribute *attr, 1229 char *buf) 1230 { 1231 return charge_control_threshold_show(conf.charge_control.offset_start, 1232 device, attr, buf); 1233 } 1234 1235 static ssize_t charge_control_start_threshold_store(struct device *dev, 1236 struct device_attribute *attr, 1237 const char *buf, size_t count) 1238 { 1239 return charge_control_threshold_store(conf.charge_control.offset_start, 1240 dev, attr, buf, count); 1241 } 1242 1243 static ssize_t charge_control_end_threshold_show(struct device *device, 1244 struct device_attribute *attr, 1245 char *buf) 1246 { 1247 return charge_control_threshold_show(conf.charge_control.offset_end, 1248 device, attr, buf); 1249 } 1250 1251 static ssize_t charge_control_end_threshold_store(struct device *dev, 1252 struct device_attribute *attr, 1253 const char *buf, size_t count) 1254 { 1255 return charge_control_threshold_store(conf.charge_control.offset_end, 1256 dev, attr, buf, count); 1257 } 1258 1259 static DEVICE_ATTR_RW(charge_control_start_threshold); 1260 static DEVICE_ATTR_RW(charge_control_end_threshold); 1261 1262 static struct attribute *msi_battery_attrs[] = { 1263 &dev_attr_charge_control_start_threshold.attr, 1264 &dev_attr_charge_control_end_threshold.attr, 1265 NULL 1266 }; 1267 1268 ATTRIBUTE_GROUPS(msi_battery); 1269 1270 static int msi_battery_add(struct power_supply *battery, 1271 struct acpi_battery_hook *hook) 1272 { 1273 return device_add_groups(&battery->dev, msi_battery_groups); 1274 } 1275 1276 static int msi_battery_remove(struct power_supply *battery, 1277 struct acpi_battery_hook *hook) 1278 { 1279 device_remove_groups(&battery->dev, msi_battery_groups); 1280 return 0; 1281 } 1282 1283 static struct acpi_battery_hook battery_hook = { 1284 .add_battery = msi_battery_add, 1285 .remove_battery = msi_battery_remove, 1286 .name = MSI_EC_DRIVER_NAME, 1287 }; 1288 1289 /* 1290 * Module load/unload 1291 */ 1292 1293 static const struct dmi_system_id msi_dmi_table[] __initconst __maybe_unused = { 1294 { 1295 .matches = { 1296 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"), 1297 }, 1298 }, 1299 { 1300 .matches = { 1301 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 1302 }, 1303 }, 1304 {} 1305 }; 1306 MODULE_DEVICE_TABLE(dmi, msi_dmi_table); 1307 1308 static int __init load_configuration(void) 1309 { 1310 int result; 1311 1312 u8 fw_version[MSI_EC_FW_VERSION_LENGTH + 1]; 1313 1314 /* get firmware version */ 1315 result = ec_get_firmware_version(fw_version); 1316 if (result < 0) 1317 return result; 1318 1319 /* load the suitable configuration, if exists */ 1320 for (int i = 0; CONFIGS[i]; i++) { 1321 if (match_string(CONFIGS[i]->allowed_fw, -1, fw_version) != -EINVAL) { 1322 conf = *CONFIGS[i]; 1323 conf.allowed_fw = NULL; 1324 return 0; 1325 } 1326 } 1327 1328 /* config not found */ 1329 1330 for (int i = 0; i < MSI_EC_FW_VERSION_LENGTH; i++) { 1331 if (!isgraph(fw_version[i])) { 1332 pr_warn("Unable to find a valid firmware version!\n"); 1333 return -EOPNOTSUPP; 1334 } 1335 } 1336 1337 pr_warn("Firmware version is not supported: '%s'\n", fw_version); 1338 return -EOPNOTSUPP; 1339 } 1340 1341 static int __init msi_ec_init(void) 1342 { 1343 int result; 1344 1345 result = load_configuration(); 1346 if (result < 0) 1347 return result; 1348 1349 battery_hook_register(&battery_hook); 1350 return 0; 1351 } 1352 1353 static void __exit msi_ec_exit(void) 1354 { 1355 battery_hook_unregister(&battery_hook); 1356 } 1357 1358 MODULE_LICENSE("GPL"); 1359 MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>"); 1360 MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>"); 1361 MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>"); 1362 MODULE_DESCRIPTION("MSI Embedded Controller"); 1363 1364 module_init(msi_ec_init); 1365 module_exit(msi_ec_exit); 1366