1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Platform driver for OneXPlayer and AOKZOE devices. For the time being, 4 * it also exposes fan controls for AYANEO, and OrangePi Handhelds via 5 * hwmon sysfs. 6 * 7 * Fan control is provided via pwm interface in the range [0-255]. 8 * Old AMD boards use [0-100] as range in the EC, the written value is 9 * scaled to accommodate for that. Newer boards like the mini PRO and 10 * AOKZOE are not scaled but have the same EC layout. Newer models 11 * like the 2 and X1 are [0-184] and are scaled to 0-255. OrangePi 12 * are [1-244] and scaled to 0-255. 13 * 14 * Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com> 15 * Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com> 16 * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev> 17 */ 18 19 #include <linux/acpi.h> 20 #include <linux/dmi.h> 21 #include <linux/hwmon.h> 22 #include <linux/init.h> 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 #include <linux/platform_device.h> 26 #include <linux/processor.h> 27 #include <acpi/battery.h> 28 29 /* Handle ACPI lock mechanism */ 30 static u32 oxp_mutex; 31 32 #define ACPI_LOCK_DELAY_MS 500 33 34 static bool lock_global_acpi_lock(void) 35 { 36 return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex)); 37 } 38 39 static bool unlock_global_acpi_lock(void) 40 { 41 return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex)); 42 } 43 44 enum oxp_board { 45 aok_zoe_a1 = 1, 46 aya_neo_2, 47 aya_neo_air, 48 aya_neo_air_1s, 49 aya_neo_air_plus_mendo, 50 aya_neo_air_pro, 51 aya_neo_flip, 52 aya_neo_geek, 53 aya_neo_kun, 54 orange_pi_neo, 55 oxp_2, 56 oxp_fly, 57 oxp_mini_amd, 58 oxp_mini_amd_a07, 59 oxp_mini_amd_pro, 60 oxp_x1, 61 }; 62 63 static enum oxp_board board; 64 static struct device *oxp_dev; 65 66 /* Fan reading and PWM */ 67 #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ 68 #define OXP_2_SENSOR_FAN_REG 0x58 /* Fan reading is 2 registers long */ 69 #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */ 70 #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */ 71 #define PWM_MODE_AUTO 0x00 72 #define PWM_MODE_MANUAL 0x01 73 74 /* OrangePi fan reading and PWM */ 75 #define ORANGEPI_SENSOR_FAN_REG 0x78 /* Fan reading is 2 registers long */ 76 #define ORANGEPI_SENSOR_PWM_ENABLE_REG 0x40 /* PWM enable is 1 register long */ 77 #define ORANGEPI_SENSOR_PWM_REG 0x38 /* PWM reading is 1 register long */ 78 79 /* Turbo button takeover function 80 * Different boards have different values and EC registers 81 * for the same function 82 */ 83 #define OXP_TURBO_SWITCH_REG 0xF1 /* Mini Pro, OneXFly, AOKZOE */ 84 #define OXP_2_TURBO_SWITCH_REG 0xEB /* OXP2 and X1 */ 85 #define OXP_MINI_TURBO_SWITCH_REG 0x1E /* Mini AO7 */ 86 87 #define OXP_MINI_TURBO_TAKE_VAL 0x01 /* Mini AO7 */ 88 #define OXP_TURBO_TAKE_VAL 0x40 /* All other models */ 89 90 #define OXP_TURBO_RETURN_VAL 0x00 /* Common return val */ 91 92 /* X1 Turbo LED */ 93 #define OXP_X1_TURBO_LED_REG 0x57 94 95 #define OXP_X1_TURBO_LED_OFF 0x01 96 #define OXP_X1_TURBO_LED_ON 0x02 97 98 /* Battery extension settings */ 99 #define EC_CHARGE_CONTROL_BEHAVIOURS (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \ 100 BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) | \ 101 BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE)) 102 103 #define OXP_X1_CHARGE_LIMIT_REG 0xA3 /* X1 charge limit (%) */ 104 #define OXP_X1_CHARGE_INHIBIT_REG 0xA4 /* X1 bypass charging */ 105 106 #define OXP_X1_CHARGE_INHIBIT_MASK_AWAKE 0x01 107 /* X1 Mask is 0x0A, F1Pro is 0x02 but the extra bit on the X1 does nothing. */ 108 #define OXP_X1_CHARGE_INHIBIT_MASK_OFF 0x02 109 #define OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS (OXP_X1_CHARGE_INHIBIT_MASK_AWAKE | \ 110 OXP_X1_CHARGE_INHIBIT_MASK_OFF) 111 112 static const struct dmi_system_id dmi_table[] = { 113 { 114 .matches = { 115 DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), 116 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"), 117 }, 118 .driver_data = (void *)aok_zoe_a1, 119 }, 120 { 121 .matches = { 122 DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"), 123 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"), 124 }, 125 .driver_data = (void *)aok_zoe_a1, 126 }, 127 { 128 .matches = { 129 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 130 DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"), 131 }, 132 .driver_data = (void *)aya_neo_2, 133 }, 134 { 135 .matches = { 136 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 137 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"), 138 }, 139 .driver_data = (void *)aya_neo_air, 140 }, 141 { 142 .matches = { 143 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 144 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"), 145 }, 146 .driver_data = (void *)aya_neo_air_1s, 147 }, 148 { 149 .matches = { 150 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 151 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"), 152 }, 153 .driver_data = (void *)aya_neo_air_plus_mendo, 154 }, 155 { 156 .matches = { 157 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 158 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"), 159 }, 160 .driver_data = (void *)aya_neo_air_pro, 161 }, 162 { 163 .matches = { 164 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 165 DMI_MATCH(DMI_BOARD_NAME, "FLIP"), 166 }, 167 .driver_data = (void *)aya_neo_flip, 168 }, 169 { 170 .matches = { 171 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 172 DMI_MATCH(DMI_BOARD_NAME, "GEEK"), 173 }, 174 .driver_data = (void *)aya_neo_geek, 175 }, 176 { 177 .matches = { 178 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"), 179 DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"), 180 }, 181 .driver_data = (void *)aya_neo_kun, 182 }, 183 { 184 .matches = { 185 DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"), 186 DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"), 187 }, 188 .driver_data = (void *)orange_pi_neo, 189 }, 190 { 191 .matches = { 192 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 193 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"), 194 }, 195 .driver_data = (void *)oxp_mini_amd, 196 }, 197 { 198 .matches = { 199 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 200 DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 2"), 201 }, 202 .driver_data = (void *)oxp_2, 203 }, 204 { 205 .matches = { 206 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 207 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"), 208 }, 209 .driver_data = (void *)oxp_fly, 210 }, 211 { 212 .matches = { 213 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 214 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-01"), 215 }, 216 .driver_data = (void *)oxp_fly, 217 }, 218 { 219 .matches = { 220 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 221 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 OLED"), 222 }, 223 .driver_data = (void *)oxp_fly, 224 }, 225 { 226 .matches = { 227 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 228 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1L"), 229 }, 230 .driver_data = (void *)oxp_fly, 231 }, 232 { 233 .matches = { 234 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 235 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1Pro"), 236 }, 237 .driver_data = (void *)oxp_fly, 238 }, 239 { 240 .matches = { 241 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 242 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-02"), 243 }, 244 .driver_data = (void *)oxp_fly, 245 }, 246 { 247 .matches = { 248 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 249 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), 250 }, 251 .driver_data = (void *)oxp_mini_amd_a07, 252 }, 253 { 254 .matches = { 255 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 256 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"), 257 }, 258 .driver_data = (void *)oxp_mini_amd_pro, 259 }, 260 { 261 .matches = { 262 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 263 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 A"), 264 }, 265 .driver_data = (void *)oxp_x1, 266 }, 267 { 268 .matches = { 269 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 270 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 i"), 271 }, 272 .driver_data = (void *)oxp_x1, 273 }, 274 { 275 .matches = { 276 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 277 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 mini"), 278 }, 279 .driver_data = (void *)oxp_x1, 280 }, 281 { 282 .matches = { 283 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 284 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro"), 285 }, 286 .driver_data = (void *)oxp_x1, 287 }, 288 {}, 289 }; 290 291 /* Helper functions to handle EC read/write */ 292 static int read_from_ec(u8 reg, int size, long *val) 293 { 294 u8 buffer; 295 int ret; 296 int i; 297 298 if (!lock_global_acpi_lock()) 299 return -EBUSY; 300 301 *val = 0; 302 for (i = 0; i < size; i++) { 303 ret = ec_read(reg + i, &buffer); 304 if (ret) 305 return ret; 306 *val <<= i * 8; 307 *val += buffer; 308 } 309 310 if (!unlock_global_acpi_lock()) 311 return -EBUSY; 312 313 return 0; 314 } 315 316 static int write_to_ec(u8 reg, u8 value) 317 { 318 int ret; 319 320 if (!lock_global_acpi_lock()) 321 return -EBUSY; 322 323 ret = ec_write(reg, value); 324 325 if (!unlock_global_acpi_lock()) 326 return -EBUSY; 327 328 return ret; 329 } 330 331 /* Turbo button toggle functions */ 332 static int tt_toggle_enable(void) 333 { 334 u8 reg; 335 u8 val; 336 337 switch (board) { 338 case oxp_mini_amd_a07: 339 reg = OXP_MINI_TURBO_SWITCH_REG; 340 val = OXP_MINI_TURBO_TAKE_VAL; 341 break; 342 case aok_zoe_a1: 343 case oxp_fly: 344 case oxp_mini_amd_pro: 345 reg = OXP_TURBO_SWITCH_REG; 346 val = OXP_TURBO_TAKE_VAL; 347 break; 348 case oxp_2: 349 case oxp_x1: 350 reg = OXP_2_TURBO_SWITCH_REG; 351 val = OXP_TURBO_TAKE_VAL; 352 break; 353 default: 354 return -EINVAL; 355 } 356 return write_to_ec(reg, val); 357 } 358 359 static int tt_toggle_disable(void) 360 { 361 u8 reg; 362 u8 val; 363 364 switch (board) { 365 case oxp_mini_amd_a07: 366 reg = OXP_MINI_TURBO_SWITCH_REG; 367 val = OXP_TURBO_RETURN_VAL; 368 break; 369 case aok_zoe_a1: 370 case oxp_fly: 371 case oxp_mini_amd_pro: 372 reg = OXP_TURBO_SWITCH_REG; 373 val = OXP_TURBO_RETURN_VAL; 374 break; 375 case oxp_2: 376 case oxp_x1: 377 reg = OXP_2_TURBO_SWITCH_REG; 378 val = OXP_TURBO_RETURN_VAL; 379 break; 380 default: 381 return -EINVAL; 382 } 383 return write_to_ec(reg, val); 384 } 385 386 /* Callbacks for turbo toggle attribute */ 387 static umode_t tt_toggle_is_visible(struct kobject *kobj, 388 struct attribute *attr, int n) 389 { 390 switch (board) { 391 case aok_zoe_a1: 392 case oxp_2: 393 case oxp_fly: 394 case oxp_mini_amd_a07: 395 case oxp_mini_amd_pro: 396 case oxp_x1: 397 return attr->mode; 398 default: 399 break; 400 } 401 return 0; 402 } 403 404 static ssize_t tt_toggle_store(struct device *dev, 405 struct device_attribute *attr, const char *buf, 406 size_t count) 407 { 408 bool value; 409 int ret; 410 411 ret = kstrtobool(buf, &value); 412 if (ret) 413 return ret; 414 415 if (value) { 416 ret = tt_toggle_enable(); 417 } else { 418 ret = tt_toggle_disable(); 419 } 420 if (ret) 421 return ret; 422 423 return count; 424 } 425 426 static ssize_t tt_toggle_show(struct device *dev, 427 struct device_attribute *attr, char *buf) 428 { 429 int retval; 430 long val; 431 u8 reg; 432 433 switch (board) { 434 case oxp_mini_amd_a07: 435 reg = OXP_MINI_TURBO_SWITCH_REG; 436 break; 437 case aok_zoe_a1: 438 case oxp_fly: 439 case oxp_mini_amd_pro: 440 reg = OXP_TURBO_SWITCH_REG; 441 break; 442 case oxp_2: 443 case oxp_x1: 444 reg = OXP_2_TURBO_SWITCH_REG; 445 break; 446 default: 447 return -EINVAL; 448 } 449 450 retval = read_from_ec(reg, 1, &val); 451 if (retval) 452 return retval; 453 454 return sysfs_emit(buf, "%d\n", !!val); 455 } 456 457 static DEVICE_ATTR_RW(tt_toggle); 458 459 /* Callbacks for turbo LED attribute */ 460 static umode_t tt_led_is_visible(struct kobject *kobj, 461 struct attribute *attr, int n) 462 { 463 switch (board) { 464 case oxp_x1: 465 return attr->mode; 466 default: 467 break; 468 } 469 return 0; 470 } 471 472 static ssize_t tt_led_store(struct device *dev, 473 struct device_attribute *attr, const char *buf, 474 size_t count) 475 { 476 u8 reg, val; 477 bool value; 478 int ret; 479 480 ret = kstrtobool(buf, &value); 481 if (ret) 482 return ret; 483 484 switch (board) { 485 case oxp_x1: 486 reg = OXP_X1_TURBO_LED_REG; 487 val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF; 488 break; 489 default: 490 return -EINVAL; 491 } 492 493 ret = write_to_ec(reg, val); 494 if (ret) 495 return ret; 496 497 return count; 498 } 499 500 static ssize_t tt_led_show(struct device *dev, 501 struct device_attribute *attr, char *buf) 502 { 503 long enval; 504 long val; 505 int ret; 506 u8 reg; 507 508 switch (board) { 509 case oxp_x1: 510 reg = OXP_X1_TURBO_LED_REG; 511 enval = OXP_X1_TURBO_LED_ON; 512 break; 513 default: 514 return -EINVAL; 515 } 516 517 ret = read_from_ec(reg, 1, &val); 518 if (ret) 519 return ret; 520 521 return sysfs_emit(buf, "%d\n", val == enval); 522 } 523 524 static DEVICE_ATTR_RW(tt_led); 525 526 /* Callbacks for charge behaviour attributes */ 527 static bool oxp_psy_ext_supported(void) 528 { 529 switch (board) { 530 case oxp_x1: 531 case oxp_fly: 532 return true; 533 default: 534 break; 535 } 536 return false; 537 } 538 539 static int oxp_psy_ext_get_prop(struct power_supply *psy, 540 const struct power_supply_ext *ext, 541 void *data, 542 enum power_supply_property psp, 543 union power_supply_propval *val) 544 { 545 long raw_val; 546 int ret; 547 548 switch (psp) { 549 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 550 ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val); 551 if (ret) 552 return ret; 553 if (raw_val < 0 || raw_val > 100) 554 return -EINVAL; 555 val->intval = raw_val; 556 return 0; 557 case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: 558 ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val); 559 if (ret) 560 return ret; 561 if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) == 562 OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) 563 val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; 564 else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) == 565 OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) 566 val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE; 567 else 568 val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; 569 return 0; 570 default: 571 return -EINVAL; 572 } 573 } 574 575 static int oxp_psy_ext_set_prop(struct power_supply *psy, 576 const struct power_supply_ext *ext, 577 void *data, 578 enum power_supply_property psp, 579 const union power_supply_propval *val) 580 { 581 long raw_val; 582 583 switch (psp) { 584 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 585 if (val->intval > 100) 586 return -EINVAL; 587 return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval); 588 case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: 589 switch (val->intval) { 590 case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: 591 raw_val = 0; 592 break; 593 case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE: 594 raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE; 595 break; 596 case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: 597 raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS; 598 break; 599 default: 600 return -EINVAL; 601 } 602 603 return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val); 604 default: 605 return -EINVAL; 606 } 607 } 608 609 static int oxp_psy_prop_is_writeable(struct power_supply *psy, 610 const struct power_supply_ext *ext, 611 void *data, 612 enum power_supply_property psp) 613 { 614 return true; 615 } 616 617 static const enum power_supply_property oxp_psy_ext_props[] = { 618 POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, 619 POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, 620 }; 621 622 static const struct power_supply_ext oxp_psy_ext = { 623 .name = "oxp-charge-control", 624 .properties = oxp_psy_ext_props, 625 .num_properties = ARRAY_SIZE(oxp_psy_ext_props), 626 .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS, 627 .get_property = oxp_psy_ext_get_prop, 628 .set_property = oxp_psy_ext_set_prop, 629 .property_is_writeable = oxp_psy_prop_is_writeable, 630 }; 631 632 static int oxp_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 633 { 634 return power_supply_register_extension(battery, &oxp_psy_ext, oxp_dev, NULL); 635 } 636 637 static int oxp_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 638 { 639 power_supply_unregister_extension(battery, &oxp_psy_ext); 640 return 0; 641 } 642 643 static struct acpi_battery_hook battery_hook = { 644 .add_battery = oxp_add_battery, 645 .remove_battery = oxp_remove_battery, 646 .name = "OneXPlayer Battery", 647 }; 648 649 /* PWM enable/disable functions */ 650 static int oxp_pwm_enable(void) 651 { 652 switch (board) { 653 case orange_pi_neo: 654 return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 655 case aok_zoe_a1: 656 case aya_neo_2: 657 case aya_neo_air: 658 case aya_neo_air_plus_mendo: 659 case aya_neo_air_pro: 660 case aya_neo_flip: 661 case aya_neo_geek: 662 case aya_neo_kun: 663 case oxp_2: 664 case oxp_fly: 665 case oxp_mini_amd: 666 case oxp_mini_amd_a07: 667 case oxp_mini_amd_pro: 668 case oxp_x1: 669 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 670 default: 671 return -EINVAL; 672 } 673 } 674 675 static int oxp_pwm_disable(void) 676 { 677 switch (board) { 678 case orange_pi_neo: 679 return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 680 case aok_zoe_a1: 681 case aya_neo_2: 682 case aya_neo_air: 683 case aya_neo_air_1s: 684 case aya_neo_air_plus_mendo: 685 case aya_neo_air_pro: 686 case aya_neo_flip: 687 case aya_neo_geek: 688 case aya_neo_kun: 689 case oxp_2: 690 case oxp_fly: 691 case oxp_mini_amd: 692 case oxp_mini_amd_a07: 693 case oxp_mini_amd_pro: 694 case oxp_x1: 695 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 696 default: 697 return -EINVAL; 698 } 699 } 700 701 static int oxp_pwm_read(long *val) 702 { 703 switch (board) { 704 case orange_pi_neo: 705 return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val); 706 case aok_zoe_a1: 707 case aya_neo_2: 708 case aya_neo_air: 709 case aya_neo_air_1s: 710 case aya_neo_air_plus_mendo: 711 case aya_neo_air_pro: 712 case aya_neo_flip: 713 case aya_neo_geek: 714 case aya_neo_kun: 715 case oxp_2: 716 case oxp_fly: 717 case oxp_mini_amd: 718 case oxp_mini_amd_a07: 719 case oxp_mini_amd_pro: 720 case oxp_x1: 721 return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); 722 default: 723 return -EOPNOTSUPP; 724 } 725 } 726 727 /* Callbacks for hwmon interface */ 728 static umode_t oxp_ec_hwmon_is_visible(const void *drvdata, 729 enum hwmon_sensor_types type, u32 attr, int channel) 730 { 731 switch (type) { 732 case hwmon_fan: 733 return 0444; 734 case hwmon_pwm: 735 return 0644; 736 default: 737 return 0; 738 } 739 } 740 741 /* Fan speed read function */ 742 static int oxp_pwm_fan_speed(long *val) 743 { 744 switch (board) { 745 case orange_pi_neo: 746 return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val); 747 case oxp_2: 748 case oxp_x1: 749 return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val); 750 case aok_zoe_a1: 751 case aya_neo_2: 752 case aya_neo_air: 753 case aya_neo_air_1s: 754 case aya_neo_air_plus_mendo: 755 case aya_neo_air_pro: 756 case aya_neo_flip: 757 case aya_neo_geek: 758 case aya_neo_kun: 759 case oxp_fly: 760 case oxp_mini_amd: 761 case oxp_mini_amd_a07: 762 case oxp_mini_amd_pro: 763 return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); 764 default: 765 return -EOPNOTSUPP; 766 } 767 } 768 769 /* PWM input read/write functions */ 770 static int oxp_pwm_input_write(long val) 771 { 772 if (val < 0 || val > 255) 773 return -EINVAL; 774 775 switch (board) { 776 case orange_pi_neo: 777 /* scale to range [1-244] */ 778 val = ((val - 1) * 243 / 254) + 1; 779 return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val); 780 case oxp_2: 781 case oxp_x1: 782 /* scale to range [0-184] */ 783 val = (val * 184) / 255; 784 return write_to_ec(OXP_SENSOR_PWM_REG, val); 785 case aya_neo_2: 786 case aya_neo_air: 787 case aya_neo_air_1s: 788 case aya_neo_air_plus_mendo: 789 case aya_neo_air_pro: 790 case aya_neo_flip: 791 case aya_neo_geek: 792 case aya_neo_kun: 793 case oxp_mini_amd: 794 case oxp_mini_amd_a07: 795 /* scale to range [0-100] */ 796 val = (val * 100) / 255; 797 return write_to_ec(OXP_SENSOR_PWM_REG, val); 798 case aok_zoe_a1: 799 case oxp_fly: 800 case oxp_mini_amd_pro: 801 return write_to_ec(OXP_SENSOR_PWM_REG, val); 802 default: 803 return -EOPNOTSUPP; 804 } 805 } 806 807 static int oxp_pwm_input_read(long *val) 808 { 809 int ret; 810 811 switch (board) { 812 case orange_pi_neo: 813 ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val); 814 if (ret) 815 return ret; 816 /* scale from range [1-244] */ 817 *val = ((*val - 1) * 254 / 243) + 1; 818 break; 819 case oxp_2: 820 case oxp_x1: 821 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 822 if (ret) 823 return ret; 824 /* scale from range [0-184] */ 825 *val = (*val * 255) / 184; 826 break; 827 case aya_neo_2: 828 case aya_neo_air: 829 case aya_neo_air_1s: 830 case aya_neo_air_plus_mendo: 831 case aya_neo_air_pro: 832 case aya_neo_flip: 833 case aya_neo_geek: 834 case aya_neo_kun: 835 case oxp_mini_amd: 836 case oxp_mini_amd_a07: 837 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 838 if (ret) 839 return ret; 840 /* scale from range [0-100] */ 841 *val = (*val * 255) / 100; 842 break; 843 case aok_zoe_a1: 844 case oxp_fly: 845 case oxp_mini_amd_pro: 846 default: 847 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 848 if (ret) 849 return ret; 850 break; 851 } 852 return 0; 853 } 854 855 static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, 856 u32 attr, int channel, long *val) 857 { 858 int ret; 859 860 switch (type) { 861 case hwmon_fan: 862 switch (attr) { 863 case hwmon_fan_input: 864 return oxp_pwm_fan_speed(val); 865 default: 866 break; 867 } 868 break; 869 case hwmon_pwm: 870 switch (attr) { 871 case hwmon_pwm_input: 872 return oxp_pwm_input_read(val); 873 case hwmon_pwm_enable: 874 ret = oxp_pwm_read(val); 875 if (ret) 876 return ret; 877 878 /* Check for auto and return 2 */ 879 if (!*val) { 880 *val = 2; 881 return 0; 882 } 883 884 /* Return 0 if at full fan speed, 1 otherwise */ 885 ret = oxp_pwm_fan_speed(val); 886 if (ret) 887 return ret; 888 889 if (*val == 255) 890 *val = 0; 891 else 892 *val = 1; 893 894 return 0; 895 default: 896 break; 897 } 898 break; 899 default: 900 break; 901 } 902 return -EOPNOTSUPP; 903 } 904 905 static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, 906 u32 attr, int channel, long val) 907 { 908 int ret; 909 910 switch (type) { 911 case hwmon_pwm: 912 switch (attr) { 913 case hwmon_pwm_enable: 914 if (val == 1) 915 return oxp_pwm_enable(); 916 else if (val == 2) 917 return oxp_pwm_disable(); 918 else if (val != 0) 919 return -EINVAL; 920 921 /* Enable PWM and set to max speed */ 922 ret = oxp_pwm_enable(); 923 if (ret) 924 return ret; 925 return oxp_pwm_input_write(255); 926 case hwmon_pwm_input: 927 return oxp_pwm_input_write(val); 928 default: 929 break; 930 } 931 break; 932 default: 933 break; 934 } 935 return -EOPNOTSUPP; 936 } 937 938 /* Known sensors in the OXP EC controllers */ 939 static const struct hwmon_channel_info * const oxp_platform_sensors[] = { 940 HWMON_CHANNEL_INFO(fan, 941 HWMON_F_INPUT), 942 HWMON_CHANNEL_INFO(pwm, 943 HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 944 NULL, 945 }; 946 947 static struct attribute *oxp_tt_toggle_attrs[] = { 948 &dev_attr_tt_toggle.attr, 949 NULL 950 }; 951 952 static const struct attribute_group oxp_tt_toggle_attribute_group = { 953 .is_visible = tt_toggle_is_visible, 954 .attrs = oxp_tt_toggle_attrs, 955 }; 956 957 static struct attribute *oxp_tt_led_attrs[] = { 958 &dev_attr_tt_led.attr, 959 NULL 960 }; 961 962 static const struct attribute_group oxp_tt_led_attribute_group = { 963 .is_visible = tt_led_is_visible, 964 .attrs = oxp_tt_led_attrs, 965 }; 966 967 static const struct attribute_group *oxp_ec_groups[] = { 968 &oxp_tt_toggle_attribute_group, 969 &oxp_tt_led_attribute_group, 970 NULL 971 }; 972 973 static const struct hwmon_ops oxp_ec_hwmon_ops = { 974 .is_visible = oxp_ec_hwmon_is_visible, 975 .read = oxp_platform_read, 976 .write = oxp_platform_write, 977 }; 978 979 static const struct hwmon_chip_info oxp_ec_chip_info = { 980 .ops = &oxp_ec_hwmon_ops, 981 .info = oxp_platform_sensors, 982 }; 983 984 /* Initialization logic */ 985 static int oxp_platform_probe(struct platform_device *pdev) 986 { 987 struct device *dev = &pdev->dev; 988 struct device *hwdev; 989 int ret; 990 991 oxp_dev = dev; 992 hwdev = devm_hwmon_device_register_with_info(dev, "oxp_ec", NULL, 993 &oxp_ec_chip_info, NULL); 994 995 if (IS_ERR(hwdev)) 996 return PTR_ERR(hwdev); 997 998 if (oxp_psy_ext_supported()) { 999 ret = devm_battery_hook_register(dev, &battery_hook); 1000 if (ret) 1001 return ret; 1002 } 1003 1004 return 0; 1005 } 1006 1007 static struct platform_driver oxp_platform_driver = { 1008 .driver = { 1009 .name = "oxp-platform", 1010 .dev_groups = oxp_ec_groups, 1011 }, 1012 .probe = oxp_platform_probe, 1013 }; 1014 1015 static struct platform_device *oxp_platform_device; 1016 1017 static int __init oxp_platform_init(void) 1018 { 1019 const struct dmi_system_id *dmi_entry; 1020 1021 dmi_entry = dmi_first_match(dmi_table); 1022 if (!dmi_entry) 1023 return -ENODEV; 1024 1025 board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; 1026 1027 /* 1028 * Have to check for AMD processor here because DMI strings are the same 1029 * between Intel and AMD boards on older OneXPlayer devices, the only way 1030 * to tell them apart is the CPU. Old Intel boards have an unsupported EC. 1031 */ 1032 if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 1033 return -ENODEV; 1034 1035 oxp_platform_device = 1036 platform_create_bundle(&oxp_platform_driver, 1037 oxp_platform_probe, NULL, 0, NULL, 0); 1038 1039 return PTR_ERR_OR_ZERO(oxp_platform_device); 1040 } 1041 1042 static void __exit oxp_platform_exit(void) 1043 { 1044 platform_device_unregister(oxp_platform_device); 1045 platform_driver_unregister(&oxp_platform_driver); 1046 } 1047 1048 MODULE_DEVICE_TABLE(dmi, dmi_table); 1049 1050 module_init(oxp_platform_init); 1051 module_exit(oxp_platform_exit); 1052 1053 MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>"); 1054 MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices"); 1055 MODULE_LICENSE("GPL"); 1056