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