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