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