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 Pocket 4 214 .matches = { 215 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 216 DMI_MATCH(DMI_PRODUCT_NAME, "G1628-04"), 217 }, 218 .driver_data = &gpd_win_mini_drvdata, 219 }, 220 { 221 // GPD Pocket 4 (another) 222 .matches = { 223 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 224 DMI_MATCH(DMI_PRODUCT_NAME, "G1628-04-L"), 225 }, 226 .driver_data = &gpd_win_mini_drvdata, 227 }, 228 { 229 // GPD Micro PC 2 230 .matches = { 231 DMI_MATCH(DMI_SYS_VENDOR, "GPD"), 232 DMI_MATCH(DMI_PRODUCT_NAME, "G1688-08"), 233 }, 234 .driver_data = &gpd_mpc2_drvdata, 235 }, 236 {} 237 }; 238 239 static const struct gpd_fan_drvdata *gpd_module_drvdata[] = { 240 &gpd_win_mini_drvdata, &gpd_win4_drvdata, &gpd_wm2_drvdata, &gpd_mpc2_drvdata, NULL 241 }; 242 243 // Helper functions to handle EC read/write 244 static void gpd_ecram_read(u16 offset, u8 *val) 245 { 246 u16 addr_port = gpd_driver_priv.drvdata->addr_port; 247 u16 data_port = gpd_driver_priv.drvdata->data_port; 248 249 outb(0x2E, addr_port); 250 outb(0x11, data_port); 251 outb(0x2F, addr_port); 252 outb((u8)((offset >> 8) & 0xFF), data_port); 253 254 outb(0x2E, addr_port); 255 outb(0x10, data_port); 256 outb(0x2F, addr_port); 257 outb((u8)(offset & 0xFF), data_port); 258 259 outb(0x2E, addr_port); 260 outb(0x12, data_port); 261 outb(0x2F, addr_port); 262 *val = inb(data_port); 263 } 264 265 static void gpd_ecram_write(u16 offset, u8 value) 266 { 267 u16 addr_port = gpd_driver_priv.drvdata->addr_port; 268 u16 data_port = gpd_driver_priv.drvdata->data_port; 269 270 outb(0x2E, addr_port); 271 outb(0x11, data_port); 272 outb(0x2F, addr_port); 273 outb((u8)((offset >> 8) & 0xFF), data_port); 274 275 outb(0x2E, addr_port); 276 outb(0x10, data_port); 277 outb(0x2F, addr_port); 278 outb((u8)(offset & 0xFF), data_port); 279 280 outb(0x2E, addr_port); 281 outb(0x12, data_port); 282 outb(0x2F, addr_port); 283 outb(value, data_port); 284 } 285 286 static int gpd_generic_read_rpm(void) 287 { 288 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 289 u8 high, low; 290 291 gpd_ecram_read(drvdata->rpm_read, &high); 292 gpd_ecram_read(drvdata->rpm_read + 1, &low); 293 294 return (u16)high << 8 | low; 295 } 296 297 static int gpd_wm2_read_rpm(void) 298 { 299 for (u16 pwm_ctr_offset = GPD_PWM_CTR_OFFSET; 300 pwm_ctr_offset <= GPD_PWM_CTR_OFFSET + 2; pwm_ctr_offset++) { 301 u8 PWMCTR; 302 303 gpd_ecram_read(pwm_ctr_offset, &PWMCTR); 304 305 if (PWMCTR != 0xB8) 306 gpd_ecram_write(pwm_ctr_offset, 0xB8); 307 } 308 309 return gpd_generic_read_rpm(); 310 } 311 312 // Read value for fan1_input 313 static int gpd_read_rpm(void) 314 { 315 switch (gpd_driver_priv.drvdata->board) { 316 case win4_6800u: 317 case win_mini: 318 case duo: 319 case mpc2: 320 return gpd_generic_read_rpm(); 321 case win_max_2: 322 return gpd_wm2_read_rpm(); 323 } 324 325 return 0; 326 } 327 328 static int gpd_wm2_read_pwm(void) 329 { 330 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 331 u8 var; 332 333 gpd_ecram_read(drvdata->pwm_write, &var); 334 335 // Match gpd_generic_write_pwm(u8) below 336 return DIV_ROUND_CLOSEST((var - 1) * 255, (drvdata->pwm_max - 1)); 337 } 338 339 // Read value for pwm1 340 static int gpd_read_pwm(void) 341 { 342 switch (gpd_driver_priv.drvdata->board) { 343 case win_mini: 344 case duo: 345 case win4_6800u: 346 case mpc2: 347 switch (gpd_driver_priv.pwm_enable) { 348 case DISABLE: 349 return 255; 350 case MANUAL: 351 return gpd_driver_priv.pwm_value; 352 case AUTOMATIC: 353 return -EOPNOTSUPP; 354 } 355 break; 356 case win_max_2: 357 return gpd_wm2_read_pwm(); 358 } 359 return 0; 360 } 361 362 // PWM value's range in EC is 1 - pwm_max, cast 0 - 255 to it. 363 static inline u8 gpd_cast_pwm_range(u8 val) 364 { 365 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 366 367 return DIV_ROUND_CLOSEST(val * (drvdata->pwm_max - 1), 255) + 1; 368 } 369 370 static void gpd_generic_write_pwm(u8 val) 371 { 372 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 373 u8 pwm_reg; 374 375 pwm_reg = gpd_cast_pwm_range(val); 376 gpd_ecram_write(drvdata->pwm_write, pwm_reg); 377 } 378 379 static void gpd_duo_write_pwm(u8 val) 380 { 381 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 382 u8 pwm_reg; 383 384 pwm_reg = gpd_cast_pwm_range(val); 385 gpd_ecram_write(drvdata->pwm_write, pwm_reg); 386 gpd_ecram_write(drvdata->pwm_write + 1, pwm_reg); 387 } 388 389 // Write value for pwm1 390 static int gpd_write_pwm(u8 val) 391 { 392 if (gpd_driver_priv.pwm_enable != MANUAL) 393 return -EPERM; 394 395 switch (gpd_driver_priv.drvdata->board) { 396 case duo: 397 gpd_duo_write_pwm(val); 398 break; 399 case win_mini: 400 case win4_6800u: 401 case win_max_2: 402 case mpc2: 403 gpd_generic_write_pwm(val); 404 break; 405 } 406 407 return 0; 408 } 409 410 static void gpd_win_mini_set_pwm_enable(enum FAN_PWM_ENABLE pwm_enable) 411 { 412 switch (pwm_enable) { 413 case DISABLE: 414 gpd_generic_write_pwm(255); 415 break; 416 case MANUAL: 417 gpd_generic_write_pwm(gpd_driver_priv.pwm_value); 418 break; 419 case AUTOMATIC: 420 gpd_ecram_write(gpd_driver_priv.drvdata->pwm_write, 0); 421 break; 422 } 423 } 424 425 static void gpd_duo_set_pwm_enable(enum FAN_PWM_ENABLE pwm_enable) 426 { 427 switch (pwm_enable) { 428 case DISABLE: 429 gpd_duo_write_pwm(255); 430 break; 431 case MANUAL: 432 gpd_duo_write_pwm(gpd_driver_priv.pwm_value); 433 break; 434 case AUTOMATIC: 435 gpd_ecram_write(gpd_driver_priv.drvdata->pwm_write, 0); 436 break; 437 } 438 } 439 440 static void gpd_wm2_set_pwm_enable(enum FAN_PWM_ENABLE enable) 441 { 442 const struct gpd_fan_drvdata *const drvdata = gpd_driver_priv.drvdata; 443 444 switch (enable) { 445 case DISABLE: 446 gpd_generic_write_pwm(255); 447 gpd_ecram_write(drvdata->manual_control_enable, 1); 448 break; 449 case MANUAL: 450 gpd_generic_write_pwm(gpd_driver_priv.pwm_value); 451 gpd_ecram_write(drvdata->manual_control_enable, 1); 452 break; 453 case AUTOMATIC: 454 gpd_ecram_write(drvdata->manual_control_enable, 0); 455 break; 456 } 457 } 458 459 // Write value for pwm1_enable 460 static void gpd_set_pwm_enable(enum FAN_PWM_ENABLE enable) 461 { 462 if (enable == MANUAL) 463 // Set pwm_value to max firstly when switching to manual mode, in 464 // consideration of device safety. 465 gpd_driver_priv.pwm_value = 255; 466 467 switch (gpd_driver_priv.drvdata->board) { 468 case win_mini: 469 case win4_6800u: 470 case mpc2: 471 gpd_win_mini_set_pwm_enable(enable); 472 break; 473 case duo: 474 gpd_duo_set_pwm_enable(enable); 475 break; 476 case win_max_2: 477 gpd_wm2_set_pwm_enable(enable); 478 break; 479 } 480 } 481 482 static umode_t gpd_fan_hwmon_is_visible(__always_unused const void *drvdata, 483 enum hwmon_sensor_types type, u32 attr, 484 __always_unused int channel) 485 { 486 if (type == hwmon_fan && attr == hwmon_fan_input) { 487 return 0444; 488 } else if (type == hwmon_pwm) { 489 switch (attr) { 490 case hwmon_pwm_enable: 491 case hwmon_pwm_input: 492 return 0644; 493 default: 494 return 0; 495 } 496 } 497 return 0; 498 } 499 500 static int gpd_fan_hwmon_read(__always_unused struct device *dev, 501 enum hwmon_sensor_types type, u32 attr, 502 __always_unused int channel, long *val) 503 { 504 int ret; 505 506 if (type == hwmon_fan) { 507 if (attr == hwmon_fan_input) { 508 ret = gpd_read_rpm(); 509 510 if (ret < 0) 511 return ret; 512 513 *val = ret; 514 return 0; 515 } 516 } else if (type == hwmon_pwm) { 517 switch (attr) { 518 case hwmon_pwm_enable: 519 *val = gpd_driver_priv.pwm_enable; 520 return 0; 521 case hwmon_pwm_input: 522 ret = gpd_read_pwm(); 523 524 if (ret < 0) 525 return ret; 526 527 *val = ret; 528 return 0; 529 } 530 } 531 532 return -EOPNOTSUPP; 533 } 534 535 static int gpd_fan_hwmon_write(__always_unused struct device *dev, 536 enum hwmon_sensor_types type, u32 attr, 537 __always_unused int channel, long val) 538 { 539 if (type == hwmon_pwm) { 540 switch (attr) { 541 case hwmon_pwm_enable: 542 if (!in_range(val, 0, 3)) 543 return -EINVAL; 544 545 gpd_driver_priv.pwm_enable = val; 546 547 gpd_set_pwm_enable(gpd_driver_priv.pwm_enable); 548 return 0; 549 case hwmon_pwm_input: 550 if (!in_range(val, 0, 256)) 551 return -EINVAL; 552 553 gpd_driver_priv.pwm_value = val; 554 555 return gpd_write_pwm(val); 556 } 557 } 558 559 return -EOPNOTSUPP; 560 } 561 562 static const struct hwmon_ops gpd_fan_ops = { 563 .is_visible = gpd_fan_hwmon_is_visible, 564 .read = gpd_fan_hwmon_read, 565 .write = gpd_fan_hwmon_write, 566 }; 567 568 static const struct hwmon_channel_info *gpd_fan_hwmon_channel_info[] = { 569 HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), 570 HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 571 NULL 572 }; 573 574 static struct hwmon_chip_info gpd_fan_chip_info = { 575 .ops = &gpd_fan_ops, 576 .info = gpd_fan_hwmon_channel_info 577 }; 578 579 static void gpd_win4_init_ec(void) 580 { 581 u8 chip_id, chip_ver; 582 583 gpd_ecram_read(0x2000, &chip_id); 584 585 if (chip_id == 0x55) { 586 gpd_ecram_read(0x1060, &chip_ver); 587 gpd_ecram_write(0x1060, chip_ver | 0x80); 588 } 589 } 590 591 static void gpd_init_ec(void) 592 { 593 // The buggy firmware won't initialize EC properly on boot. 594 // Before its initialization, reading RPM will always return 0, 595 // and writing PWM will have no effect. 596 // Initialize it manually on driver load. 597 if (gpd_driver_priv.drvdata->board == win4_6800u) 598 gpd_win4_init_ec(); 599 } 600 601 static int gpd_fan_probe(struct platform_device *pdev) 602 { 603 struct device *dev = &pdev->dev; 604 const struct resource *region; 605 const struct resource *res; 606 const struct device *hwdev; 607 608 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 609 if (!res) 610 return dev_err_probe(dev, -EINVAL, 611 "Failed to get platform resource\n"); 612 613 region = devm_request_region(dev, res->start, 614 resource_size(res), DRIVER_NAME); 615 if (!region) 616 return dev_err_probe(dev, -EBUSY, 617 "Failed to request region\n"); 618 619 hwdev = devm_hwmon_device_register_with_info(dev, 620 DRIVER_NAME, 621 NULL, 622 &gpd_fan_chip_info, 623 NULL); 624 if (IS_ERR(hwdev)) 625 return dev_err_probe(dev, PTR_ERR(hwdev), 626 "Failed to register hwmon device\n"); 627 628 gpd_init_ec(); 629 630 return 0; 631 } 632 633 static void gpd_fan_remove(__always_unused struct platform_device *pdev) 634 { 635 gpd_driver_priv.pwm_enable = AUTOMATIC; 636 gpd_set_pwm_enable(AUTOMATIC); 637 } 638 639 static struct platform_driver gpd_fan_driver = { 640 .probe = gpd_fan_probe, 641 .remove = gpd_fan_remove, 642 .driver = { 643 .name = KBUILD_MODNAME, 644 }, 645 }; 646 647 static struct platform_device *gpd_fan_platform_device; 648 649 static int __init gpd_fan_init(void) 650 { 651 const struct gpd_fan_drvdata *match = NULL; 652 653 for (const struct gpd_fan_drvdata **p = gpd_module_drvdata; *p; p++) { 654 if (strcmp(gpd_fan_board, (*p)->board_name) == 0) { 655 match = *p; 656 break; 657 } 658 } 659 660 if (!match) { 661 const struct dmi_system_id *dmi_match = 662 dmi_first_match(dmi_table); 663 if (dmi_match) 664 match = dmi_match->driver_data; 665 } 666 667 if (!match) 668 return -ENODEV; 669 670 gpd_driver_priv.pwm_enable = AUTOMATIC; 671 gpd_driver_priv.pwm_value = 255; 672 gpd_driver_priv.drvdata = match; 673 674 struct resource gpd_fan_resources[] = { 675 { 676 .start = match->addr_port, 677 .end = match->data_port, 678 .flags = IORESOURCE_IO, 679 }, 680 }; 681 682 gpd_fan_platform_device = platform_create_bundle(&gpd_fan_driver, 683 gpd_fan_probe, 684 gpd_fan_resources, 685 1, NULL, 0); 686 687 if (IS_ERR(gpd_fan_platform_device)) { 688 pr_warn("Failed to create platform device\n"); 689 return PTR_ERR(gpd_fan_platform_device); 690 } 691 692 return 0; 693 } 694 695 static void __exit gpd_fan_exit(void) 696 { 697 platform_device_unregister(gpd_fan_platform_device); 698 platform_driver_unregister(&gpd_fan_driver); 699 } 700 701 MODULE_DEVICE_TABLE(dmi, dmi_table); 702 703 module_init(gpd_fan_init); 704 module_exit(gpd_fan_exit); 705 706 MODULE_LICENSE("GPL"); 707 MODULE_AUTHOR("Cryolitia PukNgae <cryolitia@uniontech.com>"); 708 MODULE_DESCRIPTION("GPD Devices fan control driver"); 709