1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 /* 4 * msi-ec: MSI laptops' embedded controller driver. 5 * 6 * This driver allows various MSI laptops' functionalities to be 7 * controlled from userspace. 8 * 9 * It contains EC memory configurations for different firmware versions 10 * and exports battery charge thresholds to userspace. 11 * 12 * Copyright (C) 2023 Jose Angel Pastrana <japp0005@red.ujaen.es> 13 * Copyright (C) 2023 Aakash Singh <mail@singhaakash.dev> 14 * Copyright (C) 2023 Nikita Kravets <teackot@gmail.com> 15 */ 16 17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 18 19 #include "msi-ec.h" 20 21 #include <acpi/battery.h> 22 #include <linux/acpi.h> 23 #include <linux/init.h> 24 #include <linux/kernel.h> 25 #include <linux/module.h> 26 #include <linux/platform_device.h> 27 #include <linux/seq_file.h> 28 #include <linux/string.h> 29 30 #define SM_ECO_NAME "eco" 31 #define SM_COMFORT_NAME "comfort" 32 #define SM_SPORT_NAME "sport" 33 #define SM_TURBO_NAME "turbo" 34 35 #define FM_AUTO_NAME "auto" 36 #define FM_SILENT_NAME "silent" 37 #define FM_BASIC_NAME "basic" 38 #define FM_ADVANCED_NAME "advanced" 39 40 static const char * const ALLOWED_FW_0[] __initconst = { 41 "14C1EMS1.012", 42 "14C1EMS1.101", 43 "14C1EMS1.102", 44 NULL 45 }; 46 47 static struct msi_ec_conf CONF0 __initdata = { 48 .allowed_fw = ALLOWED_FW_0, 49 .charge_control = { 50 .address = 0xef, 51 .offset_start = 0x8a, 52 .offset_end = 0x80, 53 .range_min = 0x8a, 54 .range_max = 0xe4, 55 }, 56 .webcam = { 57 .address = 0x2e, 58 .block_address = 0x2f, 59 .bit = 1, 60 }, 61 .fn_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_NULL 76 }, 77 }, 78 .super_battery = { 79 .address = MSI_EC_ADDR_UNKNOWN, // 0xd5 needs testing 80 }, 81 .fan_mode = { 82 .address = 0xf4, 83 .modes = { 84 { FM_AUTO_NAME, 0x0d }, 85 { FM_SILENT_NAME, 0x1d }, 86 { FM_BASIC_NAME, 0x4d }, 87 { FM_ADVANCED_NAME, 0x8d }, 88 MSI_EC_MODE_NULL 89 }, 90 }, 91 .cpu = { 92 .rt_temp_address = 0x68, 93 .rt_fan_speed_address = 0x71, 94 .rt_fan_speed_base_min = 0x19, 95 .rt_fan_speed_base_max = 0x37, 96 .bs_fan_speed_address = 0x89, 97 .bs_fan_speed_base_min = 0x00, 98 .bs_fan_speed_base_max = 0x0f, 99 }, 100 .gpu = { 101 .rt_temp_address = 0x80, 102 .rt_fan_speed_address = 0x89, 103 }, 104 .leds = { 105 .micmute_led_address = 0x2b, 106 .mute_led_address = 0x2c, 107 .bit = 2, 108 }, 109 .kbd_bl = { 110 .bl_mode_address = 0x2c, // ? 111 .bl_modes = { 0x00, 0x08 }, // ? 112 .max_mode = 1, // ? 113 .bl_state_address = 0xf3, 114 .state_base_value = 0x80, 115 .max_state = 3, 116 }, 117 }; 118 119 static const char * const ALLOWED_FW_1[] __initconst = { 120 "17F2EMS1.103", 121 "17F2EMS1.104", 122 "17F2EMS1.106", 123 "17F2EMS1.107", 124 NULL 125 }; 126 127 static struct msi_ec_conf CONF1 __initdata = { 128 .allowed_fw = ALLOWED_FW_1, 129 .charge_control = { 130 .address = 0xef, 131 .offset_start = 0x8a, 132 .offset_end = 0x80, 133 .range_min = 0x8a, 134 .range_max = 0xe4, 135 }, 136 .webcam = { 137 .address = 0x2e, 138 .block_address = 0x2f, 139 .bit = 1, 140 }, 141 .fn_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_NULL 157 }, 158 }, 159 .super_battery = { 160 .address = MSI_EC_ADDR_UNKNOWN, 161 }, 162 .fan_mode = { 163 .address = 0xf4, 164 .modes = { 165 { FM_AUTO_NAME, 0x0d }, 166 { FM_BASIC_NAME, 0x4d }, 167 { FM_ADVANCED_NAME, 0x8d }, 168 MSI_EC_MODE_NULL 169 }, 170 }, 171 .cpu = { 172 .rt_temp_address = 0x68, 173 .rt_fan_speed_address = 0x71, 174 .rt_fan_speed_base_min = 0x19, 175 .rt_fan_speed_base_max = 0x37, 176 .bs_fan_speed_address = 0x89, 177 .bs_fan_speed_base_min = 0x00, 178 .bs_fan_speed_base_max = 0x0f, 179 }, 180 .gpu = { 181 .rt_temp_address = 0x80, 182 .rt_fan_speed_address = 0x89, 183 }, 184 .leds = { 185 .micmute_led_address = 0x2b, 186 .mute_led_address = 0x2c, 187 .bit = 2, 188 }, 189 .kbd_bl = { 190 .bl_mode_address = 0x2c, // ? 191 .bl_modes = { 0x00, 0x08 }, // ? 192 .max_mode = 1, // ? 193 .bl_state_address = 0xf3, 194 .state_base_value = 0x80, 195 .max_state = 3, 196 }, 197 }; 198 199 static const char * const ALLOWED_FW_2[] __initconst = { 200 "1552EMS1.118", 201 NULL 202 }; 203 204 static struct msi_ec_conf CONF2 __initdata = { 205 .allowed_fw = ALLOWED_FW_2, 206 .charge_control = { 207 .address = 0xd7, 208 .offset_start = 0x8a, 209 .offset_end = 0x80, 210 .range_min = 0x8a, 211 .range_max = 0xe4, 212 }, 213 .webcam = { 214 .address = 0x2e, 215 .block_address = 0x2f, 216 .bit = 1, 217 }, 218 .fn_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_NULL 233 }, 234 }, 235 .super_battery = { 236 .address = 0xeb, 237 .mask = 0x0f, 238 }, 239 .fan_mode = { 240 .address = 0xd4, 241 .modes = { 242 { FM_AUTO_NAME, 0x0d }, 243 { FM_SILENT_NAME, 0x1d }, 244 { FM_BASIC_NAME, 0x4d }, 245 { FM_ADVANCED_NAME, 0x8d }, 246 MSI_EC_MODE_NULL 247 }, 248 }, 249 .cpu = { 250 .rt_temp_address = 0x68, 251 .rt_fan_speed_address = 0x71, 252 .rt_fan_speed_base_min = 0x19, 253 .rt_fan_speed_base_max = 0x37, 254 .bs_fan_speed_address = 0x89, 255 .bs_fan_speed_base_min = 0x00, 256 .bs_fan_speed_base_max = 0x0f, 257 }, 258 .gpu = { 259 .rt_temp_address = 0x80, 260 .rt_fan_speed_address = 0x89, 261 }, 262 .leds = { 263 .micmute_led_address = 0x2c, 264 .mute_led_address = 0x2d, 265 .bit = 1, 266 }, 267 .kbd_bl = { 268 .bl_mode_address = 0x2c, // ? 269 .bl_modes = { 0x00, 0x08 }, // ? 270 .max_mode = 1, // ? 271 .bl_state_address = 0xd3, 272 .state_base_value = 0x80, 273 .max_state = 3, 274 }, 275 }; 276 277 static const char * const ALLOWED_FW_3[] __initconst = { 278 "1592EMS1.111", 279 NULL 280 }; 281 282 static 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_NULL 311 }, 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_NULL 325 }, 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 355 static const char * const ALLOWED_FW_4[] __initconst = { 356 "16V4EMS1.114", 357 NULL 358 }; 359 360 static 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 unknown 376 .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_NULL 389 }, 390 }, 391 .super_battery = { // may be supported, but address is unknown 392 .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_NULL 402 }, 403 }, 404 .cpu = { 405 .rt_temp_address = 0x68, // needs testing 406 .rt_fan_speed_address = 0x71, // needs testing 407 .rt_fan_speed_base_min = 0x19, 408 .rt_fan_speed_base_max = 0x37, 409 .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, 410 .bs_fan_speed_base_min = 0x00, 411 .bs_fan_speed_base_max = 0x0f, 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 functional 427 .state_base_value = 0x80, 428 .max_state = 3, 429 }, 430 }; 431 432 static const char * const ALLOWED_FW_5[] __initconst = { 433 "158LEMS1.103", 434 "158LEMS1.105", 435 "158LEMS1.106", 436 NULL 437 }; 438 439 static 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: reverse 454 .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_NULL 468 }, 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_NULL 481 }, 482 }, 483 .cpu = { 484 .rt_temp_address = 0x68, // needs testing 485 .rt_fan_speed_address = 0x71, // needs testing 486 .rt_fan_speed_base_min = 0x19, 487 .rt_fan_speed_base_max = 0x37, 488 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 489 .bs_fan_speed_base_min = 0x00, 490 .bs_fan_speed_base_max = 0x0f, 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 functional 506 .state_base_value = 0x80, 507 .max_state = 3, 508 }, 509 }; 510 511 static const char * const ALLOWED_FW_6[] __initconst = { 512 "1542EMS1.102", 513 "1542EMS1.104", 514 NULL 515 }; 516 517 static 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: reverse 533 .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_NULL 547 }, 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_NULL 560 }, 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 functional 585 .state_base_value = 0x80, 586 .max_state = 3, 587 }, 588 }; 589 590 static const char * const ALLOWED_FW_7[] __initconst = { 591 "17FKEMS1.108", 592 "17FKEMS1.109", 593 "17FKEMS1.10A", 594 NULL 595 }; 596 597 static 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 testing 613 .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_NULL 627 }, 628 }, 629 .super_battery = { 630 .address = MSI_EC_ADDR_UNKNOWN, // 0xd5 but has its own wet of modes 631 .mask = 0x0f, 632 }, 633 .fan_mode = { 634 .address = 0xf4, 635 .modes = { 636 { FM_AUTO_NAME, 0x0d }, // d may not be relevant 637 { FM_SILENT_NAME, 0x1d }, 638 { FM_ADVANCED_NAME, 0x8d }, 639 MSI_EC_MODE_NULL 640 }, 641 }, 642 .cpu = { 643 .rt_temp_address = 0x68, 644 .rt_fan_speed_address = 0xc9, // needs testing 645 .rt_fan_speed_base_min = 0x19, 646 .rt_fan_speed_base_max = 0x37, 647 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 648 .bs_fan_speed_base_min = 0x00, 649 .bs_fan_speed_base_max = 0x0f, 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 670 static const char * const ALLOWED_FW_8[] __initconst = { 671 "14F1EMS1.115", 672 NULL 673 }; 674 675 static 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_NULL 704 }, 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_NULL 717 }, 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 functional 742 .state_base_value = 0x80, 743 .max_state = 3, 744 }, 745 }; 746 747 static const char * const ALLOWED_FW_9[] __initconst = { 748 "14JKEMS1.104", 749 NULL 750 }; 751 752 static 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_NULL 781 }, 782 }, 783 .super_battery = { 784 .address = MSI_EC_ADDR_UNSUPP, // unsupported or enabled by ECO shift 785 .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_NULL 794 }, 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 app 816 .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 824 static const char * const ALLOWED_FW_10[] __initconst = { 825 "1582EMS1.107", // GF66 11UC 826 NULL 827 }; 828 829 static 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_NULL 859 }, 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_NULL 872 }, 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 902 static const char * const ALLOWED_FW_11[] __initconst = { 903 "16S6EMS1.111", // Prestige 15 a11scx 904 "1552EMS1.115", // Modern 15 a11m 905 NULL 906 }; 907 908 static 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_NULL 937 }, 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_NULL 950 }, 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 976 static const char * const ALLOWED_FW_12[] __initconst = { 977 "16R6EMS1.104", // GF63 Thin 11UC 978 NULL 979 }; 980 981 static 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_NULL 1011 }, 1012 }, 1013 .super_battery = { 1014 .address = MSI_EC_ADDR_UNSUPP, // 0xeb 1015 .mask = 0x0f, // 00, 0f 1016 }, 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_NULL 1024 }, 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 1054 static const char * const ALLOWED_FW_13[] __initconst = { 1055 "1594EMS1.109", // MSI Prestige 16 Studio A13VE 1056 NULL 1057 }; 1058 1059 static 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-0x10 1076 }, 1077 .cooler_boost = { 1078 .address = 0x98, 1079 .bit = 7, 1080 }, 1081 .shift_mode = { 1082 .address = 0xd2, 1083 .modes = { 1084 { SM_ECO_NAME, 0xc2 }, // super battery 1085 { SM_COMFORT_NAME, 0xc1 }, // balanced 1086 { SM_TURBO_NAME, 0xc4 }, // extreme 1087 MSI_EC_MODE_NULL 1088 }, 1089 }, 1090 .super_battery = { 1091 .address = MSI_EC_ADDR_UNSUPP, 1092 .mask = 0x0f, // 00, 0f 1093 }, 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_NULL 1101 }, 1102 }, 1103 .cpu = { 1104 .rt_temp_address = 0x68, 1105 .rt_fan_speed_address = 0x71, // 0x0-0x96 1106 .rt_fan_speed_base_min = 0x00, 1107 .rt_fan_speed_base_max = 0x96, 1108 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 1109 .bs_fan_speed_base_min = 0x00, 1110 .bs_fan_speed_base_max = 0x0f, 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 off 1123 .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec 1124 .max_mode = 1, 1125 .bl_state_address = 0xd3, 1126 .state_base_value = 0x80, 1127 .max_state = 3, 1128 }, 1129 }; 1130 1131 static 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 NULL 1147 }; 1148 1149 static struct msi_ec_conf conf; // current configuration 1150 1151 /* 1152 * Helper functions 1153 */ 1154 1155 static 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 1168 static 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 subsystem 1184 */ 1185 1186 static 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 1201 static 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 1225 static 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 1233 static 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 1241 static 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 1249 static 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 1257 static DEVICE_ATTR_RW(charge_control_start_threshold); 1258 static DEVICE_ATTR_RW(charge_control_end_threshold); 1259 1260 static struct attribute *msi_battery_attrs[] = { 1261 &dev_attr_charge_control_start_threshold.attr, 1262 &dev_attr_charge_control_end_threshold.attr, 1263 NULL 1264 }; 1265 1266 ATTRIBUTE_GROUPS(msi_battery); 1267 1268 static 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 1274 static 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 1281 static struct acpi_battery_hook battery_hook = { 1282 .add_battery = msi_battery_add, 1283 .remove_battery = msi_battery_remove, 1284 .name = MSI_EC_DRIVER_NAME, 1285 }; 1286 1287 /* 1288 * Module load/unload 1289 */ 1290 1291 static 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 }; 1304 MODULE_DEVICE_TABLE(dmi, msi_dmi_table); 1305 1306 static 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 1339 static 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 1351 static void __exit msi_ec_exit(void) 1352 { 1353 battery_hook_unregister(&battery_hook); 1354 } 1355 1356 MODULE_LICENSE("GPL"); 1357 MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>"); 1358 MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>"); 1359 MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>"); 1360 MODULE_DESCRIPTION("MSI Embedded Controller"); 1361 1362 module_init(msi_ec_init); 1363 module_exit(msi_ec_exit); 1364