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