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 "1583EMS1.109", // Pulse GL66 12UEK 827 NULL 828 }; 829 830 static struct msi_ec_conf CONF10 __initdata = { 831 .allowed_fw = ALLOWED_FW_10, 832 .charge_control = { 833 .address = 0xd7, 834 .offset_start = 0x8a, 835 .offset_end = 0x80, 836 .range_min = 0x8a, 837 .range_max = 0xe4, 838 }, 839 .webcam = { 840 .address = 0x2e, 841 .block_address = 0x2f, 842 .bit = 1, 843 }, 844 .fn_win_swap = { 845 .address = MSI_EC_ADDR_UNSUPP, 846 .bit = 4, 847 }, 848 .cooler_boost = { 849 .address = 0x98, 850 .bit = 7, 851 }, 852 .shift_mode = { 853 .address = 0xd2, 854 .modes = { 855 { SM_ECO_NAME, 0xc2 }, 856 { SM_COMFORT_NAME, 0xc1 }, 857 { SM_SPORT_NAME, 0xc0 }, 858 { SM_TURBO_NAME, 0xc4 }, 859 MSI_EC_MODE_NULL 860 }, 861 }, 862 .super_battery = { 863 .address = 0xe5, 864 .mask = 0x0f, 865 }, 866 .fan_mode = { 867 .address = 0xd4, 868 .modes = { 869 { FM_AUTO_NAME, 0x0d }, 870 { FM_SILENT_NAME, 0x1d }, 871 { FM_ADVANCED_NAME, 0x8d }, 872 MSI_EC_MODE_NULL 873 }, 874 }, 875 .cpu = { 876 .rt_temp_address = 0x68, 877 .rt_fan_speed_address = 0x71, // ? 878 .rt_fan_speed_base_min = 0x19, 879 .rt_fan_speed_base_max = 0x37, 880 .bs_fan_speed_address = MSI_EC_ADDR_UNKNOWN, // ? 881 .bs_fan_speed_base_min = 0x00, 882 .bs_fan_speed_base_max = 0x0f, 883 }, 884 .gpu = { 885 .rt_temp_address = 0x80, 886 .rt_fan_speed_address = 0x89, 887 }, 888 .leds = { 889 .micmute_led_address = 0x2c, 890 .mute_led_address = 0x2d, 891 .bit = 1, 892 }, 893 .kbd_bl = { 894 .bl_mode_address = 0x2c, 895 .bl_modes = { 0x00, 0x08 }, 896 .max_mode = 1, 897 .bl_state_address = 0xd3, 898 .state_base_value = 0x80, 899 .max_state = 3, 900 }, 901 }; 902 903 static const char * const ALLOWED_FW_11[] __initconst = { 904 "16S6EMS1.111", // Prestige 15 a11scx 905 "1552EMS1.115", // Modern 15 a11m 906 NULL 907 }; 908 909 static struct msi_ec_conf CONF11 __initdata = { 910 .allowed_fw = ALLOWED_FW_11, 911 .charge_control = { 912 .address = 0xd7, 913 .offset_start = 0x8a, 914 .offset_end = 0x80, 915 .range_min = 0x8a, 916 .range_max = 0xe4, 917 }, 918 .webcam = { 919 .address = 0x2e, 920 .block_address = MSI_EC_ADDR_UNKNOWN, 921 .bit = 1, 922 }, 923 .fn_win_swap = { 924 .address = 0xe8, 925 .bit = 4, 926 }, 927 .cooler_boost = { 928 .address = 0x98, 929 .bit = 7, 930 }, 931 .shift_mode = { 932 .address = 0xd2, 933 .modes = { 934 { SM_ECO_NAME, 0xc2 }, 935 { SM_COMFORT_NAME, 0xc1 }, 936 { SM_SPORT_NAME, 0xc0 }, 937 MSI_EC_MODE_NULL 938 }, 939 }, 940 .super_battery = { 941 .address = 0xeb, 942 .mask = 0x0f, 943 }, 944 .fan_mode = { 945 .address = 0xd4, 946 .modes = { 947 { FM_AUTO_NAME, 0x0d }, 948 { FM_SILENT_NAME, 0x1d }, 949 { FM_ADVANCED_NAME, 0x4d }, 950 MSI_EC_MODE_NULL 951 }, 952 }, 953 .cpu = { 954 .rt_temp_address = 0x68, 955 .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, 956 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 957 }, 958 .gpu = { 959 .rt_temp_address = MSI_EC_ADDR_UNSUPP, 960 .rt_fan_speed_address = MSI_EC_ADDR_UNSUPP, 961 }, 962 .leds = { 963 .micmute_led_address = 0x2c, 964 .mute_led_address = 0x2d, 965 .bit = 1, 966 }, 967 .kbd_bl = { 968 .bl_mode_address = MSI_EC_ADDR_UNKNOWN, 969 .bl_modes = {}, // ? 970 .max_mode = 1, // ? 971 .bl_state_address = 0xd3, 972 .state_base_value = 0x80, 973 .max_state = 3, 974 }, 975 }; 976 977 static const char * const ALLOWED_FW_12[] __initconst = { 978 "16R6EMS1.104", // GF63 Thin 11UC 979 NULL 980 }; 981 982 static struct msi_ec_conf CONF12 __initdata = { 983 .allowed_fw = ALLOWED_FW_12, 984 .charge_control = { 985 .address = 0xd7, 986 .offset_start = 0x8a, 987 .offset_end = 0x80, 988 .range_min = 0x8a, 989 .range_max = 0xe4, 990 }, 991 .webcam = { 992 .address = 0x2e, 993 .block_address = 0x2f, 994 .bit = 1, 995 }, 996 .fn_win_swap = { 997 .address = 0xe8, 998 .bit = 4, 999 }, 1000 .cooler_boost = { 1001 .address = 0x98, 1002 .bit = 7, 1003 }, 1004 .shift_mode = { 1005 .address = 0xd2, 1006 .modes = { 1007 { SM_ECO_NAME, 0xc2 }, 1008 { SM_COMFORT_NAME, 0xc1 }, 1009 { SM_SPORT_NAME, 0xc0 }, 1010 { SM_TURBO_NAME, 0xc4 }, 1011 MSI_EC_MODE_NULL 1012 }, 1013 }, 1014 .super_battery = { 1015 .address = MSI_EC_ADDR_UNSUPP, // 0xeb 1016 .mask = 0x0f, // 00, 0f 1017 }, 1018 .fan_mode = { 1019 .address = 0xd4, 1020 .modes = { 1021 { FM_AUTO_NAME, 0x0d }, 1022 { FM_SILENT_NAME, 0x1d }, 1023 { FM_ADVANCED_NAME, 0x8d }, 1024 MSI_EC_MODE_NULL 1025 }, 1026 }, 1027 .cpu = { 1028 .rt_temp_address = 0x68, 1029 .rt_fan_speed_address = 0x71, 1030 .rt_fan_speed_base_min = 0x19, 1031 .rt_fan_speed_base_max = 0x37, 1032 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 1033 .bs_fan_speed_base_min = 0x00, 1034 .bs_fan_speed_base_max = 0x0f, 1035 }, 1036 .gpu = { 1037 .rt_temp_address = MSI_EC_ADDR_UNSUPP, 1038 .rt_fan_speed_address = 0x89, 1039 }, 1040 .leds = { 1041 .micmute_led_address = MSI_EC_ADDR_UNSUPP, 1042 .mute_led_address = 0x2d, 1043 .bit = 1, 1044 }, 1045 .kbd_bl = { 1046 .bl_mode_address = MSI_EC_ADDR_UNKNOWN, 1047 .bl_modes = { 0x00, 0x08 }, 1048 .max_mode = 1, 1049 .bl_state_address = 0xd3, 1050 .state_base_value = 0x80, 1051 .max_state = 3, 1052 }, 1053 }; 1054 1055 static const char * const ALLOWED_FW_13[] __initconst = { 1056 "1594EMS1.109", // MSI Prestige 16 Studio A13VE 1057 NULL 1058 }; 1059 1060 static struct msi_ec_conf CONF13 __initdata = { 1061 .allowed_fw = ALLOWED_FW_13, 1062 .charge_control = { 1063 .address = 0xd7, 1064 .offset_start = 0x8a, 1065 .offset_end = 0x80, 1066 .range_min = 0x8a, 1067 .range_max = 0xe4, 1068 }, 1069 .webcam = { 1070 .address = 0x2e, 1071 .block_address = 0x2f, 1072 .bit = 1, 1073 }, 1074 .fn_win_swap = { 1075 .address = 0xe8, 1076 .bit = 4, // 0x00-0x10 1077 }, 1078 .cooler_boost = { 1079 .address = 0x98, 1080 .bit = 7, 1081 }, 1082 .shift_mode = { 1083 .address = 0xd2, 1084 .modes = { 1085 { SM_ECO_NAME, 0xc2 }, // super battery 1086 { SM_COMFORT_NAME, 0xc1 }, // balanced 1087 { SM_TURBO_NAME, 0xc4 }, // extreme 1088 MSI_EC_MODE_NULL 1089 }, 1090 }, 1091 .super_battery = { 1092 .address = MSI_EC_ADDR_UNSUPP, 1093 .mask = 0x0f, // 00, 0f 1094 }, 1095 .fan_mode = { 1096 .address = 0xd4, 1097 .modes = { 1098 { FM_AUTO_NAME, 0x0d }, 1099 { FM_SILENT_NAME, 0x1d }, 1100 { FM_ADVANCED_NAME, 0x8d }, 1101 MSI_EC_MODE_NULL 1102 }, 1103 }, 1104 .cpu = { 1105 .rt_temp_address = 0x68, 1106 .rt_fan_speed_address = 0x71, // 0x0-0x96 1107 .rt_fan_speed_base_min = 0x00, 1108 .rt_fan_speed_base_max = 0x96, 1109 .bs_fan_speed_address = MSI_EC_ADDR_UNSUPP, 1110 .bs_fan_speed_base_min = 0x00, 1111 .bs_fan_speed_base_max = 0x0f, 1112 }, 1113 .gpu = { 1114 .rt_temp_address = 0x80, 1115 .rt_fan_speed_address = 0x89, 1116 }, 1117 .leds = { 1118 .micmute_led_address = 0x2c, 1119 .mute_led_address = 0x2d, 1120 .bit = 1, 1121 }, 1122 .kbd_bl = { 1123 .bl_mode_address = 0x2c, // KB auto turn off 1124 .bl_modes = { 0x00, 0x08 }, // always on; off after 10 sec 1125 .max_mode = 1, 1126 .bl_state_address = 0xd3, 1127 .state_base_value = 0x80, 1128 .max_state = 3, 1129 }, 1130 }; 1131 1132 static struct msi_ec_conf *CONFIGS[] __initdata = { 1133 &CONF0, 1134 &CONF1, 1135 &CONF2, 1136 &CONF3, 1137 &CONF4, 1138 &CONF5, 1139 &CONF6, 1140 &CONF7, 1141 &CONF8, 1142 &CONF9, 1143 &CONF10, 1144 &CONF11, 1145 &CONF12, 1146 &CONF13, 1147 NULL 1148 }; 1149 1150 static struct msi_ec_conf conf; // current configuration 1151 1152 /* 1153 * Helper functions 1154 */ 1155 1156 static int ec_read_seq(u8 addr, u8 *buf, u8 len) 1157 { 1158 int result; 1159 1160 for (u8 i = 0; i < len; i++) { 1161 result = ec_read(addr + i, buf + i); 1162 if (result < 0) 1163 return result; 1164 } 1165 1166 return 0; 1167 } 1168 1169 static int ec_get_firmware_version(u8 buf[MSI_EC_FW_VERSION_LENGTH + 1]) 1170 { 1171 int result; 1172 1173 memset(buf, 0, MSI_EC_FW_VERSION_LENGTH + 1); 1174 result = ec_read_seq(MSI_EC_FW_VERSION_ADDRESS, 1175 buf, 1176 MSI_EC_FW_VERSION_LENGTH); 1177 if (result < 0) 1178 return result; 1179 1180 return MSI_EC_FW_VERSION_LENGTH + 1; 1181 } 1182 1183 /* 1184 * Sysfs power_supply subsystem 1185 */ 1186 1187 static ssize_t charge_control_threshold_show(u8 offset, 1188 struct device *device, 1189 struct device_attribute *attr, 1190 char *buf) 1191 { 1192 u8 rdata; 1193 int result; 1194 1195 result = ec_read(conf.charge_control.address, &rdata); 1196 if (result < 0) 1197 return result; 1198 1199 return sysfs_emit(buf, "%i\n", rdata - offset); 1200 } 1201 1202 static ssize_t charge_control_threshold_store(u8 offset, 1203 struct device *dev, 1204 struct device_attribute *attr, 1205 const char *buf, size_t count) 1206 { 1207 u8 wdata; 1208 int result; 1209 1210 result = kstrtou8(buf, 10, &wdata); 1211 if (result < 0) 1212 return result; 1213 1214 wdata += offset; 1215 if (wdata < conf.charge_control.range_min || 1216 wdata > conf.charge_control.range_max) 1217 return -EINVAL; 1218 1219 result = ec_write(conf.charge_control.address, wdata); 1220 if (result < 0) 1221 return result; 1222 1223 return count; 1224 } 1225 1226 static ssize_t charge_control_start_threshold_show(struct device *device, 1227 struct device_attribute *attr, 1228 char *buf) 1229 { 1230 return charge_control_threshold_show(conf.charge_control.offset_start, 1231 device, attr, buf); 1232 } 1233 1234 static ssize_t charge_control_start_threshold_store(struct device *dev, 1235 struct device_attribute *attr, 1236 const char *buf, size_t count) 1237 { 1238 return charge_control_threshold_store(conf.charge_control.offset_start, 1239 dev, attr, buf, count); 1240 } 1241 1242 static ssize_t charge_control_end_threshold_show(struct device *device, 1243 struct device_attribute *attr, 1244 char *buf) 1245 { 1246 return charge_control_threshold_show(conf.charge_control.offset_end, 1247 device, attr, buf); 1248 } 1249 1250 static ssize_t charge_control_end_threshold_store(struct device *dev, 1251 struct device_attribute *attr, 1252 const char *buf, size_t count) 1253 { 1254 return charge_control_threshold_store(conf.charge_control.offset_end, 1255 dev, attr, buf, count); 1256 } 1257 1258 static DEVICE_ATTR_RW(charge_control_start_threshold); 1259 static DEVICE_ATTR_RW(charge_control_end_threshold); 1260 1261 static struct attribute *msi_battery_attrs[] = { 1262 &dev_attr_charge_control_start_threshold.attr, 1263 &dev_attr_charge_control_end_threshold.attr, 1264 NULL 1265 }; 1266 1267 ATTRIBUTE_GROUPS(msi_battery); 1268 1269 static int msi_battery_add(struct power_supply *battery, 1270 struct acpi_battery_hook *hook) 1271 { 1272 return device_add_groups(&battery->dev, msi_battery_groups); 1273 } 1274 1275 static int msi_battery_remove(struct power_supply *battery, 1276 struct acpi_battery_hook *hook) 1277 { 1278 device_remove_groups(&battery->dev, msi_battery_groups); 1279 return 0; 1280 } 1281 1282 static struct acpi_battery_hook battery_hook = { 1283 .add_battery = msi_battery_add, 1284 .remove_battery = msi_battery_remove, 1285 .name = MSI_EC_DRIVER_NAME, 1286 }; 1287 1288 /* 1289 * Module load/unload 1290 */ 1291 1292 static const struct dmi_system_id msi_dmi_table[] __initconst __maybe_unused = { 1293 { 1294 .matches = { 1295 DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT"), 1296 }, 1297 }, 1298 { 1299 .matches = { 1300 DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), 1301 }, 1302 }, 1303 {} 1304 }; 1305 MODULE_DEVICE_TABLE(dmi, msi_dmi_table); 1306 1307 static int __init load_configuration(void) 1308 { 1309 int result; 1310 1311 u8 fw_version[MSI_EC_FW_VERSION_LENGTH + 1]; 1312 1313 /* get firmware version */ 1314 result = ec_get_firmware_version(fw_version); 1315 if (result < 0) 1316 return result; 1317 1318 /* load the suitable configuration, if exists */ 1319 for (int i = 0; CONFIGS[i]; i++) { 1320 if (match_string(CONFIGS[i]->allowed_fw, -1, fw_version) != -EINVAL) { 1321 conf = *CONFIGS[i]; 1322 conf.allowed_fw = NULL; 1323 return 0; 1324 } 1325 } 1326 1327 /* config not found */ 1328 1329 for (int i = 0; i < MSI_EC_FW_VERSION_LENGTH; i++) { 1330 if (!isgraph(fw_version[i])) { 1331 pr_warn("Unable to find a valid firmware version!\n"); 1332 return -EOPNOTSUPP; 1333 } 1334 } 1335 1336 pr_warn("Firmware version is not supported: '%s'\n", fw_version); 1337 return -EOPNOTSUPP; 1338 } 1339 1340 static int __init msi_ec_init(void) 1341 { 1342 int result; 1343 1344 result = load_configuration(); 1345 if (result < 0) 1346 return result; 1347 1348 battery_hook_register(&battery_hook); 1349 return 0; 1350 } 1351 1352 static void __exit msi_ec_exit(void) 1353 { 1354 battery_hook_unregister(&battery_hook); 1355 } 1356 1357 MODULE_LICENSE("GPL"); 1358 MODULE_AUTHOR("Jose Angel Pastrana <japp0005@red.ujaen.es>"); 1359 MODULE_AUTHOR("Aakash Singh <mail@singhaakash.dev>"); 1360 MODULE_AUTHOR("Nikita Kravets <teackot@gmail.com>"); 1361 MODULE_DESCRIPTION("MSI Embedded Controller"); 1362 1363 module_init(msi_ec_init); 1364 module_exit(msi_ec_exit); 1365