1 // SPDX-License-Identifier: GPL-2.0+ 2 3 /* Platform driver for GPD devices that expose fan control via hwmon sysfs. 4 * 5 * Fan control is provided via pwm interface in the range [0-255]. 6 * Each model has a different range in the EC, the written value is scaled to 7 * accommodate for that. 8 * 9 * Based on this repo: 10 * https://github.com/Cryolitia/gpd-fan-driver 11 * 12 * Copyright (c) 2024 Cryolitia PukNgae 13 */ 14 15 #include <linux/dmi.h> 16 #include <linux/hwmon.h> 17 #include <linux/io.h> 18 #include <linux/ioport.h> 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/platform_device.h> 22 23 #define DRIVER_NAME "gpdfan" 24 #define GPD_PWM_CTR_OFFSET 0x1841 25 26 static char *gpd_fan_board = ""; 27 module_param(gpd_fan_board, charp, 0444); 28 29 enum gpd_board { 30 win_mini, 31 win4_6800u, 32 win_max_2, 33 duo, 34 mpc2, 35 }; 36 37 enum FAN_PWM_ENABLE { 38 DISABLE = 0, 39 MANUAL = 1, 40 AUTOMATIC = 2, 41 }; 42 43 static struct { 44 enum FAN_PWM_ENABLE pwm_enable; 45 u8 pwm_value; 46 47 const struct gpd_fan_drvdata *drvdata; 48 } gpd_driver_priv; 49 50 struct gpd_fan_drvdata { 51 const char *board_name; // Board name for module param comparison 52 const enum gpd_board board; 53 54 const u8 addr_port; 55 const u8 data_port; 56 const u16 manual_control_enable; 57 const u16 rpm_read; 58 const u16 pwm_write; 59 const u16 pwm_max; 60 }; 61 62 static struct gpd_fan_drvdata gpd_win_mini_drvdata = { 63 .board_name = "win_mini", 64 .board = win_mini, 65 66 .addr_port = 0x4E, 67 .data_port = 0x4F, 68 .manual_control_enable = 0x047A, 69 .rpm_read = 0x0478, 70 .pwm_write = 0x047A, 71 .pwm_max = 244, 72 }; 73 74 static struct gpd_fan_drvdata gpd_duo_drvdata = { 75 .board_name = "duo", 76 .board = duo, 77 78 .addr_port = 0x4E, 79 .data_port = 0x4F, 80 .manual_control_enable = 0x047A, 81 .rpm_read = 0x0478, 82 .pwm_write = 0x047A, 83 .pwm_max = 244, 84 }; 85 86 static struct gpd_fan_drvdata gpd_win4_drvdata = { 87 .board_name = "win4", 88 .board = win4_6800u, 89 90 .addr_port = 0x2E, 91 .data_port = 0x2F, 92 .manual_control_enable = 0xC311, 93 .rpm_read = 0xC880, 94 .pwm_write = 0xC311, 95 .pwm_max = 127, 96 }; 97 98 static struct gpd_fan_drvdata gpd_wm2_drvdata = { 99 .board_name = "wm2", 100 .board = win_max_2, 101 102 .addr_port = 0x4E, 103 .data_port = 0x4F, 104 .manual_control_enable = 0x0275, 105 .rpm_read = 0x0218, 106 .pwm_write = 0x1809, 107 .pwm_max = 184, 108 }; 109 110 static struct gpd_fan_drvdata gpd_mpc2_drvdata = { 111 .board_name = "mpc2", 112 .board = mpc2, 113 114 .addr_port = 0x4E, 115 .data_port = 0x4F, 116 .manual_control_enable = 0x047A, 117 .rpm_read = 0x0476, 118 .pwm_write = 0x047A, 119 .pwm_max = 244, 120 }; 121 122 static const struct dmi_system_id dmi_table[] = { 123 { 124 // GPD Win Mini 125 // GPD Win Mini with AMD Ryzen 8840U 126 .matches = { 127 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 128 DMI_MATCH(DMI_PRODUCT_NAME, "G1617-01") 129 }, 130 .driver_data = &gpd_win_mini_drvdata, 131 }, 132 { 133 // GPD Win Mini 134 // GPD Win Mini with AMD Ryzen HX370 135 .matches = { 136 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 137 DMI_MATCH(DMI_PRODUCT_NAME, "G1617-02") 138 }, 139 .driver_data = &gpd_win_mini_drvdata, 140 }, 141 { 142 // GPD Win Mini 143 // GPD Win Mini with AMD Ryzen HX370 144 .matches = { 145 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 146 DMI_MATCH(DMI_PRODUCT_NAME, "G1617-02-L") 147 }, 148 .driver_data = &gpd_win_mini_drvdata, 149 }, 150 { 151 // GPD Win 4 with AMD Ryzen 6800U 152 .matches = { 153 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 154 DMI_MATCH(DMI_PRODUCT_NAME, "G1618-04"), 155 DMI_MATCH(DMI_BOARD_VERSION, "Default string"), 156 }, 157 .driver_data = &gpd_win4_drvdata, 158 }, 159 { 160 // GPD Win 4 with Ryzen 7840U 161 .matches = { 162 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 163 DMI_MATCH(DMI_PRODUCT_NAME, "G1618-04"), 164 DMI_MATCH(DMI_BOARD_VERSION, "Ver. 1.0"), 165 }, 166 // Since 7840U, win4 uses the same drvdata as wm2 167 .driver_data = &gpd_wm2_drvdata, 168 }, 169 { 170 // GPD Win 4 with Ryzen 7840U (another) 171 .matches = { 172 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 173 DMI_MATCH(DMI_PRODUCT_NAME, "G1618-04"), 174 DMI_MATCH(DMI_BOARD_VERSION, "Ver.1.0"), 175 }, 176 .driver_data = &gpd_wm2_drvdata, 177 }, 178 { 179 // GPD Win Max 2 with Ryzen 6800U 180 // GPD Win Max 2 2023 with Ryzen 7840U 181 // GPD Win Max 2 2024 with Ryzen 8840U 182 .matches = { 183 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 184 DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"), 185 }, 186 .driver_data = &gpd_wm2_drvdata, 187 }, 188 { 189 // GPD Win Max 2 with AMD Ryzen HX370 190 .matches = { 191 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 192 DMI_MATCH(DMI_PRODUCT_NAME, "G1619-05"), 193 }, 194 .driver_data = &gpd_wm2_drvdata, 195 }, 196 { 197 // GPD Duo 198 .matches = { 199 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 200 DMI_MATCH(DMI_PRODUCT_NAME, "G1622-01"), 201 }, 202 .driver_data = &gpd_duo_drvdata, 203 }, 204 { 205 // GPD Duo (another) 206 .matches = { 207 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 208 DMI_MATCH(DMI_PRODUCT_NAME, "G1622-01-L"), 209 }, 210 .driver_data = &gpd_duo_drvdata, 211 }, 212 { 213 // GPD Win 5 with AMD AI MAX 395 214 .matches = { 215 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 216 DMI_MATCH(DMI_PRODUCT_NAME, "G1618-05"), 217 }, 218 .driver_data = &gpd_duo_drvdata, 219 }, 220 { 221 // GPD Pocket 4 222 .matches = { 223 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 224 DMI_MATCH(DMI_PRODUCT_NAME, "G1628-04"), 225 }, 226 .driver_data = &gpd_win_mini_drvdata, 227 }, 228 { 229 // GPD Pocket 4 (another) 230 .matches = { 231 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 232 DMI_MATCH(DMI_PRODUCT_NAME, "G1628-04-L"), 233 }, 234 .driver_data = &gpd_win_mini_drvdata, 235 }, 236 { 237 // GPD Micro PC 2 238 .matches = { 239 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 240 DMI_MATCH(DMI_PRODUCT_NAME, "G1688-08"), 241 }, 242 .driver_data = &gpd_mpc2_drvdata, 243 }, 244 {} 245 }; 246 247 static const struct gpd_fan_drvdata *gpd_module_drvdata[] = { 248 &gpd_win_mini_drvdata, &gpd_win4_drvdata, &gpd_wm2_drvdata, &gpd_mpc2_drvdata, NULL 249 }; 250 251 // Helper functions to handle EC read/write 252 static void gpd_ecram_read(u16 offset, u8 *val) 253 { 254 u16 addr_port = gpd_driver_priv.drvdata->addr_port; 255 u16 data_port = gpd_driver_priv.drvdata->data_port; 256 257 outb(0x2E, addr_port); 258 outb(0x11, data_port); 259 outb(0x2F, addr_port); 260 outb((u8)((offset >> 8) & 0xFF), data_port); 261 262 outb(0x2E, addr_port); 263 outb(0x10, data_port); 264 outb(0x2F, addr_port); 265 outb((u8)(offset & 0xFF), data_port); 266 267 outb(0x2E, addr_port); 268 outb(0x12, data_port); 269 outb(0x2F, addr_port); 270 *val = inb(data_port); 271 } 272 273 static void gpd_ecram_write(u16 offset, u8 value) 274 { 275 u16 addr_port = gpd_driver_priv.drvdata->addr_port; 276 u16 data_port = gpd_driver_priv.drvdata->data_port; 277 278 outb(0x2E, addr_port); 279 outb(0x11, data_port); 280 outb(0x2F, addr_port); 281 outb((u8)((offset >> 8) & 0xFF), data_port); 282 283 outb(0x2E, addr_port); 284 outb(0x10, data_port); 285 outb(0x2F, addr_port); 286 outb((u8)(offset & 0xFF), data_port); 287 288 outb(0x2E, addr_port); 289 outb(0x12, data_port); 290 outb(0x2F, addr_port); 291 outb(value, data_port); 292 } 293 294 static int gpd_generic_read_rpm(void) 295 { 296 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 297 u8 high, low; 298 299 gpd_ecram_read(drvdata->rpm_read, &high); 300 gpd_ecram_read(drvdata->rpm_read + 1, &low); 301 302 return (u16)high << 8 | low; 303 } 304 305 static int gpd_wm2_read_rpm(void) 306 { 307 for (u16 pwm_ctr_offset = GPD_PWM_CTR_OFFSET; 308 pwm_ctr_offset <= GPD_PWM_CTR_OFFSET + 2; pwm_ctr_offset++) { 309 u8 PWMCTR; 310 311 gpd_ecram_read(pwm_ctr_offset, &PWMCTR); 312 313 if (PWMCTR != 0xB8) 314 gpd_ecram_write(pwm_ctr_offset, 0xB8); 315 } 316 317 return gpd_generic_read_rpm(); 318 } 319 320 // Read value for fan1_input 321 static int gpd_read_rpm(void) 322 { 323 switch (gpd_driver_priv.drvdata->board) { 324 case win4_6800u: 325 case win_mini: 326 case duo: 327 case mpc2: 328 return gpd_generic_read_rpm(); 329 case win_max_2: 330 return gpd_wm2_read_rpm(); 331 } 332 333 return 0; 334 } 335 336 static int gpd_wm2_read_pwm(void) 337 { 338 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 339 u8 var; 340 341 gpd_ecram_read(drvdata->pwm_write, &var); 342 343 // Match gpd_generic_write_pwm(u8) below 344 return DIV_ROUND_CLOSEST((var - 1) * 255, (drvdata->pwm_max - 1)); 345 } 346 347 // Read value for pwm1 348 static int gpd_read_pwm(void) 349 { 350 switch (gpd_driver_priv.drvdata->board) { 351 case win_mini: 352 case duo: 353 case win4_6800u: 354 case mpc2: 355 switch (gpd_driver_priv.pwm_enable) { 356 case DISABLE: 357 return 255; 358 case MANUAL: 359 return gpd_driver_priv.pwm_value; 360 case AUTOMATIC: 361 return -EOPNOTSUPP; 362 } 363 break; 364 case win_max_2: 365 return gpd_wm2_read_pwm(); 366 } 367 return 0; 368 } 369 370 // PWM value's range in EC is 1 - pwm_max, cast 0 - 255 to it. 371 static inline u8 gpd_cast_pwm_range(u8 val) 372 { 373 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 374 375 return DIV_ROUND_CLOSEST(val * (drvdata->pwm_max - 1), 255) + 1; 376 } 377 378 static void gpd_generic_write_pwm(u8 val) 379 { 380 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 381 u8 pwm_reg; 382 383 pwm_reg = gpd_cast_pwm_range(val); 384 gpd_ecram_write(drvdata->pwm_write, pwm_reg); 385 } 386 387 static void gpd_duo_write_pwm(u8 val) 388 { 389 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 390 u8 pwm_reg; 391 392 pwm_reg = gpd_cast_pwm_range(val); 393 gpd_ecram_write(drvdata->pwm_write, pwm_reg); 394 gpd_ecram_write(drvdata->pwm_write + 1, pwm_reg); 395 } 396 397 // Write value for pwm1 398 static int gpd_write_pwm(u8 val) 399 { 400 if (gpd_driver_priv.pwm_enable != MANUAL) 401 return -EPERM; 402 403 switch (gpd_driver_priv.drvdata->board) { 404 case duo: 405 gpd_duo_write_pwm(val); 406 break; 407 case win_mini: 408 case win4_6800u: 409 case win_max_2: 410 case mpc2: 411 gpd_generic_write_pwm(val); 412 break; 413 } 414 415 return 0; 416 } 417 418 static void gpd_win_mini_set_pwm_enable(enum FAN_PWM_ENABLE pwm_enable) 419 { 420 switch (pwm_enable) { 421 case DISABLE: 422 gpd_generic_write_pwm(255); 423 break; 424 case MANUAL: 425 gpd_generic_write_pwm(gpd_driver_priv.pwm_value); 426 break; 427 case AUTOMATIC: 428 gpd_ecram_write(gpd_driver_priv.drvdata->pwm_write, 0); 429 break; 430 } 431 } 432 433 static void gpd_duo_set_pwm_enable(enum FAN_PWM_ENABLE pwm_enable) 434 { 435 switch (pwm_enable) { 436 case DISABLE: 437 gpd_duo_write_pwm(255); 438 break; 439 case MANUAL: 440 gpd_duo_write_pwm(gpd_driver_priv.pwm_value); 441 break; 442 case AUTOMATIC: 443 gpd_ecram_write(gpd_driver_priv.drvdata->pwm_write, 0); 444 break; 445 } 446 } 447 448 static void gpd_wm2_set_pwm_enable(enum FAN_PWM_ENABLE enable) 449 { 450 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 451 452 switch (enable) { 453 case DISABLE: 454 gpd_generic_write_pwm(255); 455 gpd_ecram_write(drvdata->manual_control_enable, 1); 456 break; 457 case MANUAL: 458 gpd_generic_write_pwm(gpd_driver_priv.pwm_value); 459 gpd_ecram_write(drvdata->manual_control_enable, 1); 460 break; 461 case AUTOMATIC: 462 gpd_ecram_write(drvdata->manual_control_enable, 0); 463 break; 464 } 465 } 466 467 // Write value for pwm1_enable 468 static void gpd_set_pwm_enable(enum FAN_PWM_ENABLE enable) 469 { 470 if (enable == MANUAL) 471 // Set pwm_value to max firstly when switching to manual mode, in 472 // consideration of device safety. 473 gpd_driver_priv.pwm_value = 255; 474 475 switch (gpd_driver_priv.drvdata->board) { 476 case win_mini: 477 case win4_6800u: 478 case mpc2: 479 gpd_win_mini_set_pwm_enable(enable); 480 break; 481 case duo: 482 gpd_duo_set_pwm_enable(enable); 483 break; 484 case win_max_2: 485 gpd_wm2_set_pwm_enable(enable); 486 break; 487 } 488 } 489 490 static umode_t gpd_fan_hwmon_is_visible(__always_unused const void *drvdata, 491 enum hwmon_sensor_types type, u32 attr, 492 __always_unused int channel) 493 { 494 if (type == hwmon_fan && attr == hwmon_fan_input) { 495 return 0444; 496 } else if (type == hwmon_pwm) { 497 switch (attr) { 498 case hwmon_pwm_enable: 499 case hwmon_pwm_input: 500 return 0644; 501 default: 502 return 0; 503 } 504 } 505 return 0; 506 } 507 508 static int gpd_fan_hwmon_read(__always_unused struct device *dev, 509 enum hwmon_sensor_types type, u32 attr, 510 __always_unused int channel, long *val) 511 { 512 int ret; 513 514 if (type == hwmon_fan) { 515 if (attr == hwmon_fan_input) { 516 ret = gpd_read_rpm(); 517 518 if (ret < 0) 519 return ret; 520 521 *val = ret; 522 return 0; 523 } 524 } else if (type == hwmon_pwm) { 525 switch (attr) { 526 case hwmon_pwm_enable: 527 *val = gpd_driver_priv.pwm_enable; 528 return 0; 529 case hwmon_pwm_input: 530 ret = gpd_read_pwm(); 531 532 if (ret < 0) 533 return ret; 534 535 *val = ret; 536 return 0; 537 } 538 } 539 540 return -EOPNOTSUPP; 541 } 542 543 static int gpd_fan_hwmon_write(__always_unused struct device *dev, 544 enum hwmon_sensor_types type, u32 attr, 545 __always_unused int channel, long val) 546 { 547 if (type == hwmon_pwm) { 548 switch (attr) { 549 case hwmon_pwm_enable: 550 if (!in_range(val, 0, 3)) 551 return -EINVAL; 552 553 gpd_driver_priv.pwm_enable = val; 554 555 gpd_set_pwm_enable(gpd_driver_priv.pwm_enable); 556 return 0; 557 case hwmon_pwm_input: 558 if (!in_range(val, 0, 256)) 559 return -EINVAL; 560 561 gpd_driver_priv.pwm_value = val; 562 563 return gpd_write_pwm(val); 564 } 565 } 566 567 return -EOPNOTSUPP; 568 } 569 570 static const struct hwmon_ops gpd_fan_ops = { 571 .is_visible = gpd_fan_hwmon_is_visible, 572 .read = gpd_fan_hwmon_read, 573 .write = gpd_fan_hwmon_write, 574 }; 575 576 static const struct hwmon_channel_info *gpd_fan_hwmon_channel_info[] = { 577 HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), 578 HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 579 NULL 580 }; 581 582 static struct hwmon_chip_info gpd_fan_chip_info = { 583 .ops = &gpd_fan_ops, 584 .info = gpd_fan_hwmon_channel_info 585 }; 586 587 static void gpd_win4_init_ec(void) 588 { 589 u8 chip_id, chip_ver; 590 591 gpd_ecram_read(0x2000, &chip_id); 592 593 if (chip_id == 0x55) { 594 gpd_ecram_read(0x1060, &chip_ver); 595 gpd_ecram_write(0x1060, chip_ver | 0x80); 596 } 597 } 598 599 static void gpd_init_ec(void) 600 { 601 // The buggy firmware won't initialize EC properly on boot. 602 // Before its initialization, reading RPM will always return 0, 603 // and writing PWM will have no effect. 604 // Initialize it manually on driver load. 605 if (gpd_driver_priv.drvdata->board == win4_6800u) 606 gpd_win4_init_ec(); 607 } 608 609 static int gpd_fan_probe(struct platform_device *pdev) 610 { 611 struct device *dev = &pdev->dev; 612 const struct resource *region; 613 const struct resource *res; 614 const struct device *hwdev; 615 616 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 617 if (!res) 618 return dev_err_probe(dev, -EINVAL, 619 "Failed to get platform resource\n"); 620 621 region = devm_request_region(dev, res->start, 622 resource_size(res), DRIVER_NAME); 623 if (!region) 624 return dev_err_probe(dev, -EBUSY, 625 "Failed to request region\n"); 626 627 hwdev = devm_hwmon_device_register_with_info(dev, 628 DRIVER_NAME, 629 NULL, 630 &gpd_fan_chip_info, 631 NULL); 632 if (IS_ERR(hwdev)) 633 return dev_err_probe(dev, PTR_ERR(hwdev), 634 "Failed to register hwmon device\n"); 635 636 gpd_init_ec(); 637 638 return 0; 639 } 640 641 static void gpd_fan_remove(__always_unused struct platform_device *pdev) 642 { 643 gpd_driver_priv.pwm_enable = AUTOMATIC; 644 gpd_set_pwm_enable(AUTOMATIC); 645 } 646 647 static struct platform_driver gpd_fan_driver = { 648 .probe = gpd_fan_probe, 649 .remove = gpd_fan_remove, 650 .driver = { 651 .name = KBUILD_MODNAME, 652 }, 653 }; 654 655 static struct platform_device *gpd_fan_platform_device; 656 657 static int __init gpd_fan_init(void) 658 { 659 const struct gpd_fan_drvdata *match = NULL; 660 661 for (const struct gpd_fan_drvdata **p = gpd_module_drvdata; *p; p++) { 662 if (strcmp(gpd_fan_board, (*p)->board_name) == 0) { 663 match = *p; 664 break; 665 } 666 } 667 668 if (!match) { 669 const struct dmi_system_id *dmi_match = 670 dmi_first_match(dmi_table); 671 if (dmi_match) 672 match = dmi_match->driver_data; 673 } 674 675 if (!match) 676 return -ENODEV; 677 678 gpd_driver_priv.pwm_enable = AUTOMATIC; 679 gpd_driver_priv.pwm_value = 255; 680 gpd_driver_priv.drvdata = match; 681 682 struct resource gpd_fan_resources[] = { 683 { 684 .start = match->addr_port, 685 .end = match->data_port, 686 .flags = IORESOURCE_IO, 687 }, 688 }; 689 690 gpd_fan_platform_device = platform_create_bundle(&gpd_fan_driver, 691 gpd_fan_probe, 692 gpd_fan_resources, 693 1, NULL, 0); 694 695 if (IS_ERR(gpd_fan_platform_device)) { 696 pr_warn("Failed to create platform device\n"); 697 return PTR_ERR(gpd_fan_platform_device); 698 } 699 700 return 0; 701 } 702 703 static void __exit gpd_fan_exit(void) 704 { 705 platform_device_unregister(gpd_fan_platform_device); 706 platform_driver_unregister(&gpd_fan_driver); 707 } 708 709 MODULE_DEVICE_TABLE(dmi, dmi_table); 710 711 module_init(gpd_fan_init); 712 module_exit(gpd_fan_exit); 713 714 MODULE_LICENSE("GPL"); 715 MODULE_AUTHOR("Cryolitia PukNgae <cryolitia@uniontech.com>"); 716 MODULE_DESCRIPTION("GPD Devices fan control driver"); 717