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 G1 i"), 212 }, 213 .driver_data = (void *)oxp_g1_i, 214 }, 215 { 216 .matches = { 217 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 218 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"), 219 }, 220 .driver_data = (void *)oxp_mini_amd_a07, 221 }, 222 { 223 .matches = { 224 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 225 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"), 226 }, 227 .driver_data = (void *)oxp_mini_amd_pro, 228 }, 229 { 230 .matches = { 231 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 232 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1z"), 233 }, 234 .driver_data = (void *)oxp_x1, 235 }, 236 { 237 .matches = { 238 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), 239 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 A"), 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 i"), 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 X1Air"), 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 X1 mini"), 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 X1Mini Pro"), 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 X1Pro"), 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 EVA-02"), 282 }, 283 .driver_data = (void *)oxp_x1, 284 }, 285 {}, 286 }; 287 288 /* Helper functions to handle EC read/write */ 289 static int read_from_ec(u8 reg, int size, long *val) 290 { 291 u8 buffer; 292 int ret; 293 int i; 294 295 if (!lock_global_acpi_lock()) 296 return -EBUSY; 297 298 *val = 0; 299 for (i = 0; i < size; i++) { 300 ret = ec_read(reg + i, &buffer); 301 if (ret) 302 return ret; 303 *val <<= i * 8; 304 *val += buffer; 305 } 306 307 if (!unlock_global_acpi_lock()) 308 return -EBUSY; 309 310 return 0; 311 } 312 313 static int write_to_ec(u8 reg, u8 value) 314 { 315 int ret; 316 317 if (!lock_global_acpi_lock()) 318 return -EBUSY; 319 320 ret = ec_write(reg, value); 321 322 if (!unlock_global_acpi_lock()) 323 return -EBUSY; 324 325 return ret; 326 } 327 328 /* Callbacks for turbo toggle attribute */ 329 static umode_t tt_toggle_is_visible(struct kobject *kobj, 330 struct attribute *attr, int n) 331 { 332 switch (board) { 333 case aok_zoe_a1: 334 case oxp_2: 335 case oxp_fly: 336 case oxp_mini_amd_a07: 337 case oxp_mini_amd_pro: 338 case oxp_x1: 339 case oxp_g1_i: 340 case oxp_g1_a: 341 return attr->mode; 342 default: 343 break; 344 } 345 return 0; 346 } 347 348 static ssize_t tt_toggle_store(struct device *dev, 349 struct device_attribute *attr, const char *buf, 350 size_t count) 351 { 352 u8 reg, mask, val; 353 long raw_val; 354 bool enable; 355 int ret; 356 357 ret = kstrtobool(buf, &enable); 358 if (ret) 359 return ret; 360 361 switch (board) { 362 case oxp_mini_amd_a07: 363 reg = OXP_MINI_TURBO_SWITCH_REG; 364 mask = OXP_MINI_TURBO_TAKE_VAL; 365 break; 366 case aok_zoe_a1: 367 case oxp_fly: 368 case oxp_mini_amd_pro: 369 case oxp_g1_a: 370 reg = OXP_TURBO_SWITCH_REG; 371 mask = OXP_TURBO_TAKE_VAL; 372 break; 373 case oxp_2: 374 case oxp_x1: 375 case oxp_g1_i: 376 reg = OXP_2_TURBO_SWITCH_REG; 377 mask = OXP_TURBO_TAKE_VAL; 378 break; 379 default: 380 return -EINVAL; 381 } 382 383 ret = read_from_ec(reg, 1, &raw_val); 384 if (ret) 385 return ret; 386 387 val = raw_val; 388 if (enable) 389 val |= mask; 390 else 391 val &= ~mask; 392 393 ret = write_to_ec(reg, val); 394 if (ret) 395 return ret; 396 397 return count; 398 } 399 400 static ssize_t tt_toggle_show(struct device *dev, 401 struct device_attribute *attr, char *buf) 402 { 403 u8 reg, mask; 404 int retval; 405 long val; 406 407 switch (board) { 408 case oxp_mini_amd_a07: 409 reg = OXP_MINI_TURBO_SWITCH_REG; 410 mask = OXP_MINI_TURBO_TAKE_VAL; 411 break; 412 case aok_zoe_a1: 413 case oxp_fly: 414 case oxp_mini_amd_pro: 415 case oxp_g1_a: 416 reg = OXP_TURBO_SWITCH_REG; 417 mask = OXP_TURBO_TAKE_VAL; 418 break; 419 case oxp_2: 420 case oxp_x1: 421 case oxp_g1_i: 422 reg = OXP_2_TURBO_SWITCH_REG; 423 mask = OXP_TURBO_TAKE_VAL; 424 break; 425 default: 426 return -EINVAL; 427 } 428 429 retval = read_from_ec(reg, 1, &val); 430 if (retval) 431 return retval; 432 433 return sysfs_emit(buf, "%d\n", (val & mask) == mask); 434 } 435 436 static DEVICE_ATTR_RW(tt_toggle); 437 438 /* Callbacks for turbo LED attribute */ 439 static umode_t tt_led_is_visible(struct kobject *kobj, 440 struct attribute *attr, int n) 441 { 442 switch (board) { 443 case oxp_x1: 444 return attr->mode; 445 default: 446 break; 447 } 448 return 0; 449 } 450 451 static ssize_t tt_led_store(struct device *dev, 452 struct device_attribute *attr, const char *buf, 453 size_t count) 454 { 455 u8 reg, val; 456 bool value; 457 int ret; 458 459 ret = kstrtobool(buf, &value); 460 if (ret) 461 return ret; 462 463 switch (board) { 464 case oxp_x1: 465 reg = OXP_X1_TURBO_LED_REG; 466 val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF; 467 break; 468 default: 469 return -EINVAL; 470 } 471 472 ret = write_to_ec(reg, val); 473 if (ret) 474 return ret; 475 476 return count; 477 } 478 479 static ssize_t tt_led_show(struct device *dev, 480 struct device_attribute *attr, char *buf) 481 { 482 long enval; 483 long val; 484 int ret; 485 u8 reg; 486 487 switch (board) { 488 case oxp_x1: 489 reg = OXP_X1_TURBO_LED_REG; 490 enval = OXP_X1_TURBO_LED_ON; 491 break; 492 default: 493 return -EINVAL; 494 } 495 496 ret = read_from_ec(reg, 1, &val); 497 if (ret) 498 return ret; 499 500 return sysfs_emit(buf, "%d\n", val == enval); 501 } 502 503 static DEVICE_ATTR_RW(tt_led); 504 505 /* Callbacks for charge behaviour attributes */ 506 static bool oxp_psy_ext_supported(void) 507 { 508 switch (board) { 509 case oxp_x1: 510 case oxp_g1_i: 511 case oxp_g1_a: 512 case oxp_fly: 513 return true; 514 default: 515 break; 516 } 517 return false; 518 } 519 520 static int oxp_psy_ext_get_prop(struct power_supply *psy, 521 const struct power_supply_ext *ext, 522 void *data, 523 enum power_supply_property psp, 524 union power_supply_propval *val) 525 { 526 long raw_val; 527 int ret; 528 529 switch (psp) { 530 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 531 ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val); 532 if (ret) 533 return ret; 534 if (raw_val < 0 || raw_val > 100) 535 return -EINVAL; 536 val->intval = raw_val; 537 return 0; 538 case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: 539 ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val); 540 if (ret) 541 return ret; 542 if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) == 543 OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) 544 val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; 545 else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) == 546 OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) 547 val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE; 548 else 549 val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; 550 return 0; 551 default: 552 return -EINVAL; 553 } 554 } 555 556 static int oxp_psy_ext_set_prop(struct power_supply *psy, 557 const struct power_supply_ext *ext, 558 void *data, 559 enum power_supply_property psp, 560 const union power_supply_propval *val) 561 { 562 long raw_val; 563 564 switch (psp) { 565 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD: 566 if (val->intval < 0 || val->intval > 100) 567 return -EINVAL; 568 return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval); 569 case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: 570 switch (val->intval) { 571 case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: 572 raw_val = 0; 573 break; 574 case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE: 575 raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE; 576 break; 577 case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: 578 raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS; 579 break; 580 default: 581 return -EINVAL; 582 } 583 584 return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val); 585 default: 586 return -EINVAL; 587 } 588 } 589 590 static int oxp_psy_prop_is_writeable(struct power_supply *psy, 591 const struct power_supply_ext *ext, 592 void *data, 593 enum power_supply_property psp) 594 { 595 return true; 596 } 597 598 static const enum power_supply_property oxp_psy_ext_props[] = { 599 POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, 600 POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, 601 }; 602 603 static const struct power_supply_ext oxp_psy_ext = { 604 .name = "oxp-charge-control", 605 .properties = oxp_psy_ext_props, 606 .num_properties = ARRAY_SIZE(oxp_psy_ext_props), 607 .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS, 608 .get_property = oxp_psy_ext_get_prop, 609 .set_property = oxp_psy_ext_set_prop, 610 .property_is_writeable = oxp_psy_prop_is_writeable, 611 }; 612 613 static int oxp_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 614 { 615 return power_supply_register_extension(battery, &oxp_psy_ext, oxp_dev, NULL); 616 } 617 618 static int oxp_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook) 619 { 620 power_supply_unregister_extension(battery, &oxp_psy_ext); 621 return 0; 622 } 623 624 static struct acpi_battery_hook battery_hook = { 625 .add_battery = oxp_add_battery, 626 .remove_battery = oxp_remove_battery, 627 .name = "OneXPlayer Battery", 628 }; 629 630 /* PWM enable/disable functions */ 631 static int oxp_pwm_enable(void) 632 { 633 switch (board) { 634 case orange_pi_neo: 635 return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 636 case aok_zoe_a1: 637 case oxp_2: 638 case oxp_fly: 639 case oxp_mini_amd: 640 case oxp_mini_amd_a07: 641 case oxp_mini_amd_pro: 642 case oxp_x1: 643 case oxp_g1_i: 644 case oxp_g1_a: 645 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); 646 default: 647 return -EINVAL; 648 } 649 } 650 651 static int oxp_pwm_disable(void) 652 { 653 switch (board) { 654 case orange_pi_neo: 655 return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 656 case aok_zoe_a1: 657 case oxp_2: 658 case oxp_fly: 659 case oxp_mini_amd: 660 case oxp_mini_amd_a07: 661 case oxp_mini_amd_pro: 662 case oxp_x1: 663 case oxp_g1_i: 664 case oxp_g1_a: 665 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); 666 default: 667 return -EINVAL; 668 } 669 } 670 671 static int oxp_pwm_read(long *val) 672 { 673 switch (board) { 674 case orange_pi_neo: 675 return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val); 676 case aok_zoe_a1: 677 case oxp_2: 678 case oxp_fly: 679 case oxp_mini_amd: 680 case oxp_mini_amd_a07: 681 case oxp_mini_amd_pro: 682 case oxp_x1: 683 case oxp_g1_i: 684 case oxp_g1_a: 685 return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); 686 default: 687 return -EOPNOTSUPP; 688 } 689 } 690 691 /* Callbacks for hwmon interface */ 692 static umode_t oxp_ec_hwmon_is_visible(const void *drvdata, 693 enum hwmon_sensor_types type, u32 attr, int channel) 694 { 695 switch (type) { 696 case hwmon_fan: 697 return 0444; 698 case hwmon_pwm: 699 return 0644; 700 default: 701 return 0; 702 } 703 } 704 705 /* Fan speed read function */ 706 static int oxp_pwm_fan_speed(long *val) 707 { 708 switch (board) { 709 case orange_pi_neo: 710 return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val); 711 case oxp_2: 712 case oxp_x1: 713 case oxp_g1_i: 714 return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val); 715 case aok_zoe_a1: 716 case oxp_fly: 717 case oxp_mini_amd: 718 case oxp_mini_amd_a07: 719 case oxp_mini_amd_pro: 720 case oxp_g1_a: 721 return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); 722 default: 723 return -EOPNOTSUPP; 724 } 725 } 726 727 /* PWM input read/write functions */ 728 static int oxp_pwm_input_write(long val) 729 { 730 if (val < 0 || val > 255) 731 return -EINVAL; 732 733 switch (board) { 734 case orange_pi_neo: 735 /* scale to range [1-244] */ 736 val = ((val - 1) * 243 / 254) + 1; 737 return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val); 738 case oxp_2: 739 case oxp_x1: 740 case oxp_g1_i: 741 /* scale to range [0-184] */ 742 val = (val * 184) / 255; 743 return write_to_ec(OXP_SENSOR_PWM_REG, val); 744 case oxp_mini_amd: 745 case oxp_mini_amd_a07: 746 /* scale to range [0-100] */ 747 val = (val * 100) / 255; 748 return write_to_ec(OXP_SENSOR_PWM_REG, val); 749 case aok_zoe_a1: 750 case oxp_fly: 751 case oxp_mini_amd_pro: 752 case oxp_g1_a: 753 return write_to_ec(OXP_SENSOR_PWM_REG, val); 754 default: 755 return -EOPNOTSUPP; 756 } 757 } 758 759 static int oxp_pwm_input_read(long *val) 760 { 761 int ret; 762 763 switch (board) { 764 case orange_pi_neo: 765 ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val); 766 if (ret) 767 return ret; 768 /* scale from range [1-244] */ 769 *val = ((*val - 1) * 254 / 243) + 1; 770 break; 771 case oxp_2: 772 case oxp_x1: 773 case oxp_g1_i: 774 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 775 if (ret) 776 return ret; 777 /* scale from range [0-184] */ 778 *val = (*val * 255) / 184; 779 break; 780 case oxp_mini_amd: 781 case oxp_mini_amd_a07: 782 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 783 if (ret) 784 return ret; 785 /* scale from range [0-100] */ 786 *val = (*val * 255) / 100; 787 break; 788 case aok_zoe_a1: 789 case oxp_fly: 790 case oxp_mini_amd_pro: 791 case oxp_g1_a: 792 default: 793 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); 794 if (ret) 795 return ret; 796 break; 797 } 798 return 0; 799 } 800 801 static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type, 802 u32 attr, int channel, long *val) 803 { 804 int ret; 805 806 switch (type) { 807 case hwmon_fan: 808 switch (attr) { 809 case hwmon_fan_input: 810 return oxp_pwm_fan_speed(val); 811 default: 812 break; 813 } 814 break; 815 case hwmon_pwm: 816 switch (attr) { 817 case hwmon_pwm_input: 818 return oxp_pwm_input_read(val); 819 case hwmon_pwm_enable: 820 ret = oxp_pwm_read(val); 821 if (ret) 822 return ret; 823 824 /* Check for auto and return 2 */ 825 if (!*val) { 826 *val = 2; 827 return 0; 828 } 829 830 /* Return 0 if at full fan speed, 1 otherwise */ 831 ret = oxp_pwm_fan_speed(val); 832 if (ret) 833 return ret; 834 835 if (*val == 255) 836 *val = 0; 837 else 838 *val = 1; 839 840 return 0; 841 default: 842 break; 843 } 844 break; 845 default: 846 break; 847 } 848 return -EOPNOTSUPP; 849 } 850 851 static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type, 852 u32 attr, int channel, long val) 853 { 854 int ret; 855 856 switch (type) { 857 case hwmon_pwm: 858 switch (attr) { 859 case hwmon_pwm_enable: 860 if (val == 1) 861 return oxp_pwm_enable(); 862 else if (val == 2) 863 return oxp_pwm_disable(); 864 else if (val != 0) 865 return -EINVAL; 866 867 /* Enable PWM and set to max speed */ 868 ret = oxp_pwm_enable(); 869 if (ret) 870 return ret; 871 return oxp_pwm_input_write(255); 872 case hwmon_pwm_input: 873 return oxp_pwm_input_write(val); 874 default: 875 break; 876 } 877 break; 878 default: 879 break; 880 } 881 return -EOPNOTSUPP; 882 } 883 884 /* Known sensors in the OXP EC controllers */ 885 static const struct hwmon_channel_info * const oxp_platform_sensors[] = { 886 HWMON_CHANNEL_INFO(fan, 887 HWMON_F_INPUT), 888 HWMON_CHANNEL_INFO(pwm, 889 HWMON_PWM_INPUT | HWMON_PWM_ENABLE), 890 NULL, 891 }; 892 893 static struct attribute *oxp_tt_toggle_attrs[] = { 894 &dev_attr_tt_toggle.attr, 895 NULL 896 }; 897 898 static const struct attribute_group oxp_tt_toggle_attribute_group = { 899 .is_visible = tt_toggle_is_visible, 900 .attrs = oxp_tt_toggle_attrs, 901 }; 902 903 static struct attribute *oxp_tt_led_attrs[] = { 904 &dev_attr_tt_led.attr, 905 NULL 906 }; 907 908 static const struct attribute_group oxp_tt_led_attribute_group = { 909 .is_visible = tt_led_is_visible, 910 .attrs = oxp_tt_led_attrs, 911 }; 912 913 static const struct attribute_group *oxp_ec_groups[] = { 914 &oxp_tt_toggle_attribute_group, 915 &oxp_tt_led_attribute_group, 916 NULL 917 }; 918 919 static const struct hwmon_ops oxp_ec_hwmon_ops = { 920 .is_visible = oxp_ec_hwmon_is_visible, 921 .read = oxp_platform_read, 922 .write = oxp_platform_write, 923 }; 924 925 static const struct hwmon_chip_info oxp_ec_chip_info = { 926 .ops = &oxp_ec_hwmon_ops, 927 .info = oxp_platform_sensors, 928 }; 929 930 /* Initialization logic */ 931 static int oxp_platform_probe(struct platform_device *pdev) 932 { 933 struct device *dev = &pdev->dev; 934 struct device *hwdev; 935 int ret; 936 937 oxp_dev = dev; 938 hwdev = devm_hwmon_device_register_with_info(dev, "oxp_ec", NULL, 939 &oxp_ec_chip_info, NULL); 940 941 if (IS_ERR(hwdev)) 942 return PTR_ERR(hwdev); 943 944 if (oxp_psy_ext_supported()) { 945 ret = devm_battery_hook_register(dev, &battery_hook); 946 if (ret) 947 return ret; 948 } 949 950 return 0; 951 } 952 953 static struct platform_driver oxp_platform_driver = { 954 .driver = { 955 .name = "oxp-platform", 956 .dev_groups = oxp_ec_groups, 957 }, 958 .probe = oxp_platform_probe, 959 }; 960 961 static struct platform_device *oxp_platform_device; 962 963 static int __init oxp_platform_init(void) 964 { 965 const struct dmi_system_id *dmi_entry; 966 967 dmi_entry = dmi_first_match(dmi_table); 968 if (!dmi_entry) 969 return -ENODEV; 970 971 board = (enum oxp_board)(unsigned long)dmi_entry->driver_data; 972 973 /* 974 * Have to check for AMD processor here because DMI strings are the same 975 * between Intel and AMD boards on older OneXPlayer devices, the only way 976 * to tell them apart is the CPU. Old Intel boards have an unsupported EC. 977 */ 978 if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD) 979 return -ENODEV; 980 981 oxp_platform_device = 982 platform_create_bundle(&oxp_platform_driver, 983 oxp_platform_probe, NULL, 0, NULL, 0); 984 985 return PTR_ERR_OR_ZERO(oxp_platform_device); 986 } 987 988 static void __exit oxp_platform_exit(void) 989 { 990 platform_device_unregister(oxp_platform_device); 991 platform_driver_unregister(&oxp_platform_driver); 992 } 993 994 MODULE_DEVICE_TABLE(dmi, dmi_table); 995 996 module_init(oxp_platform_init); 997 module_exit(oxp_platform_exit); 998 999 MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>"); 1000 MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices"); 1001 MODULE_LICENSE("GPL"); 1002