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