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