1 // SPDX-License-Identifier: GPL-2.0+
3 * Platform driver for OneXPlayer, AOKZOE, AYANEO, and OrangePi Handhelds
4 * that expose fan reading and control via hwmon sysfs.
6 * Old OXP boards have the same DMI strings and they are told apart by
7 * the boot cpu vendor (Intel/AMD). Of these older models only AMD is
10 * Fan control is provided via pwm interface in the range [0-255].
11 * Old AMD boards use [0-100] as range in the EC, the written value is
12 * scaled to accommodate for that. Newer boards like the mini PRO and
13 * AOKZOE are not scaled but have the same EC layout. Newer models
14 * like the 2 and X1 are [0-184] and are scaled to 0-255. OrangePi
15 * are [1-244] and scaled to 0-255.
21 #include <linux/acpi.h>
22 #include <linux/dmi.h>
23 #include <linux/hwmon.h>
24 #include <linux/init.h>
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/platform_device.h>
28 #include <linux/processor.h>
30 /* Handle ACPI lock mechanism */
33 #define ACPI_LOCK_DELAY_MS 500
35 static bool lock_global_acpi_lock(void)
37 return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex));
40 static bool unlock_global_acpi_lock(void)
42 return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex));
50 aya_neo_air_plus_mendo,
64 static enum oxp_board board;
66 /* Fan reading and PWM */
67 #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
68 #define OXP_2_SENSOR_FAN_REG 0x58 /* Fan reading is 2 registers long */
69 #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */
70 #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */
71 #define PWM_MODE_AUTO 0x00
72 #define PWM_MODE_MANUAL 0x01
74 /* OrangePi fan reading and PWM */
75 #define ORANGEPI_SENSOR_FAN_REG 0x78 /* Fan reading is 2 registers long */
76 #define ORANGEPI_SENSOR_PWM_ENABLE_REG 0x40 /* PWM enable is 1 register long */
77 #define ORANGEPI_SENSOR_PWM_REG 0x38 /* PWM reading is 1 register long */
79 /* Turbo button takeover function
80 * Different boards have different values and EC registers
81 * for the same function
83 #define OXP_TURBO_SWITCH_REG 0xF1 /* Mini Pro, OneXFly, AOKZOE */
84 #define OXP_2_TURBO_SWITCH_REG 0xEB /* OXP2 and X1 */
85 #define OXP_MINI_TURBO_SWITCH_REG 0x1E /* Mini AO7 */
87 #define OXP_MINI_TURBO_TAKE_VAL 0x01 /* Mini AO7 */
88 #define OXP_TURBO_TAKE_VAL 0x40 /* All other models */
90 #define OXP_TURBO_RETURN_VAL 0x00 /* Common return val */
92 static const struct dmi_system_id dmi_table[] = {
95 DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
96 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
98 .driver_data = (void *)aok_zoe_a1,
102 DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
103 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"),
105 .driver_data = (void *)aok_zoe_a1,
109 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
110 DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
112 .driver_data = (void *)aya_neo_2,
116 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
117 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
119 .driver_data = (void *)aya_neo_air,
123 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
124 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
126 .driver_data = (void *)aya_neo_air_1s,
130 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
131 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
133 .driver_data = (void *)aya_neo_air_plus_mendo,
137 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
138 DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
140 .driver_data = (void *)aya_neo_air_pro,
144 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
145 DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
147 .driver_data = (void *)aya_neo_flip,
151 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
152 DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
154 .driver_data = (void *)aya_neo_geek,
158 DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
159 DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
161 .driver_data = (void *)aya_neo_kun,
165 DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
166 DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"),
168 .driver_data = (void *)orange_pi_neo,
172 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
173 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
175 .driver_data = (void *)oxp_mini_amd,
179 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
180 DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 2"),
182 .driver_data = (void *)oxp_2,
186 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
187 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"),
189 .driver_data = (void *)oxp_fly,
193 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
194 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
196 .driver_data = (void *)oxp_mini_amd_a07,
200 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
201 DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
203 .driver_data = (void *)oxp_mini_amd_pro,
207 DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
208 DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1"),
210 .driver_data = (void *)oxp_x1,
215 /* Helper functions to handle EC read/write */
216 static int read_from_ec(u8 reg, int size, long *val)
222 if (!lock_global_acpi_lock())
226 for (i = 0; i < size; i++) {
227 ret = ec_read(reg + i, &buffer);
234 if (!unlock_global_acpi_lock())
240 static int write_to_ec(u8 reg, u8 value)
244 if (!lock_global_acpi_lock())
247 ret = ec_write(reg, value);
249 if (!unlock_global_acpi_lock())
255 /* Turbo button toggle functions */
256 static int tt_toggle_enable(void)
262 case oxp_mini_amd_a07:
263 reg = OXP_MINI_TURBO_SWITCH_REG;
264 val = OXP_MINI_TURBO_TAKE_VAL;
268 case oxp_mini_amd_pro:
269 reg = OXP_TURBO_SWITCH_REG;
270 val = OXP_TURBO_TAKE_VAL;
274 reg = OXP_2_TURBO_SWITCH_REG;
275 val = OXP_TURBO_TAKE_VAL;
280 return write_to_ec(reg, val);
283 static int tt_toggle_disable(void)
289 case oxp_mini_amd_a07:
290 reg = OXP_MINI_TURBO_SWITCH_REG;
291 val = OXP_TURBO_RETURN_VAL;
295 case oxp_mini_amd_pro:
296 reg = OXP_TURBO_SWITCH_REG;
297 val = OXP_TURBO_RETURN_VAL;
301 reg = OXP_2_TURBO_SWITCH_REG;
302 val = OXP_TURBO_RETURN_VAL;
307 return write_to_ec(reg, val);
310 /* Callbacks for turbo toggle attribute */
311 static umode_t tt_toggle_is_visible(struct kobject *kobj,
312 struct attribute *attr, int n)
318 case oxp_mini_amd_a07:
319 case oxp_mini_amd_pro:
328 static ssize_t tt_toggle_store(struct device *dev,
329 struct device_attribute *attr, const char *buf,
335 rval = kstrtobool(buf, &value);
340 rval = tt_toggle_enable();
342 rval = tt_toggle_disable();
350 static ssize_t tt_toggle_show(struct device *dev,
351 struct device_attribute *attr, char *buf)
358 case oxp_mini_amd_a07:
359 reg = OXP_MINI_TURBO_SWITCH_REG;
363 case oxp_mini_amd_pro:
364 reg = OXP_TURBO_SWITCH_REG;
368 reg = OXP_2_TURBO_SWITCH_REG;
374 retval = read_from_ec(reg, 1, &val);
378 return sysfs_emit(buf, "%d\n", !!val);
381 static DEVICE_ATTR_RW(tt_toggle);
383 /* PWM enable/disable functions */
384 static int oxp_pwm_enable(void)
388 return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
392 case aya_neo_air_plus_mendo:
393 case aya_neo_air_pro:
400 case oxp_mini_amd_a07:
401 case oxp_mini_amd_pro:
403 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
409 static int oxp_pwm_disable(void)
413 return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
418 case aya_neo_air_plus_mendo:
419 case aya_neo_air_pro:
426 case oxp_mini_amd_a07:
427 case oxp_mini_amd_pro:
429 return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
435 /* Callbacks for hwmon interface */
436 static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
437 enum hwmon_sensor_types type, u32 attr, int channel)
449 static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
450 u32 attr, int channel, long *val)
457 case hwmon_fan_input:
460 return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val);
463 return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
468 case aya_neo_air_plus_mendo:
469 case aya_neo_air_pro:
475 case oxp_mini_amd_a07:
476 case oxp_mini_amd_pro:
477 return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
488 case hwmon_pwm_input:
491 ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val);
494 /* scale from range [1-244] */
495 *val = ((*val - 1) * 254 / 243) + 1;
499 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
502 /* scale from range [0-184] */
503 *val = (*val * 255) / 184;
508 case aya_neo_air_plus_mendo:
509 case aya_neo_air_pro:
514 case oxp_mini_amd_a07:
515 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
518 /* scale from range [0-100] */
519 *val = (*val * 255) / 100;
523 case oxp_mini_amd_pro:
525 ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
531 case hwmon_pwm_enable:
534 return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
539 case aya_neo_air_plus_mendo:
540 case aya_neo_air_pro:
547 case oxp_mini_amd_a07:
548 case oxp_mini_amd_pro:
550 return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
565 static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
566 u32 attr, int channel, long val)
571 case hwmon_pwm_enable:
573 return oxp_pwm_enable();
575 return oxp_pwm_disable();
577 case hwmon_pwm_input:
578 if (val < 0 || val > 255)
582 /* scale to range [1-244] */
583 val = ((val - 1) * 243 / 254) + 1;
584 return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val);
587 /* scale to range [0-184] */
588 val = (val * 184) / 255;
589 return write_to_ec(OXP_SENSOR_PWM_REG, val);
593 case aya_neo_air_plus_mendo:
594 case aya_neo_air_pro:
599 case oxp_mini_amd_a07:
600 /* scale to range [0-100] */
601 val = (val * 100) / 255;
602 return write_to_ec(OXP_SENSOR_PWM_REG, val);
605 case oxp_mini_amd_pro:
606 return write_to_ec(OXP_SENSOR_PWM_REG, val);
621 /* Known sensors in the OXP EC controllers */
622 static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
623 HWMON_CHANNEL_INFO(fan,
625 HWMON_CHANNEL_INFO(pwm,
626 HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
630 static struct attribute *oxp_ec_attrs[] = {
631 &dev_attr_tt_toggle.attr,
635 static struct attribute_group oxp_ec_attribute_group = {
636 .is_visible = tt_toggle_is_visible,
637 .attrs = oxp_ec_attrs,
640 static const struct attribute_group *oxp_ec_groups[] = {
641 &oxp_ec_attribute_group,
645 static const struct hwmon_ops oxp_ec_hwmon_ops = {
646 .is_visible = oxp_ec_hwmon_is_visible,
647 .read = oxp_platform_read,
648 .write = oxp_platform_write,
651 static const struct hwmon_chip_info oxp_ec_chip_info = {
652 .ops = &oxp_ec_hwmon_ops,
653 .info = oxp_platform_sensors,
656 /* Initialization logic */
657 static int oxp_platform_probe(struct platform_device *pdev)
659 struct device *dev = &pdev->dev;
660 struct device *hwdev;
662 hwdev = devm_hwmon_device_register_with_info(dev, "oxpec", NULL,
663 &oxp_ec_chip_info, NULL);
665 return PTR_ERR_OR_ZERO(hwdev);
668 static struct platform_driver oxp_platform_driver = {
670 .name = "oxp-platform",
671 .dev_groups = oxp_ec_groups,
673 .probe = oxp_platform_probe,
676 static struct platform_device *oxp_platform_device;
678 static int __init oxp_platform_init(void)
680 const struct dmi_system_id *dmi_entry;
682 dmi_entry = dmi_first_match(dmi_table);
686 board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
689 * Have to check for AMD processor here because DMI strings are the same
690 * between Intel and AMD boards on older OneXPlayer devices, the only way
691 * to tell them apart is the CPU. Old Intel boards have an unsupported EC.
693 if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
696 oxp_platform_device =
697 platform_create_bundle(&oxp_platform_driver,
698 oxp_platform_probe, NULL, 0, NULL, 0);
700 return PTR_ERR_OR_ZERO(oxp_platform_device);
703 static void __exit oxp_platform_exit(void)
705 platform_device_unregister(oxp_platform_device);
706 platform_driver_unregister(&oxp_platform_driver);
709 MODULE_DEVICE_TABLE(dmi, dmi_table);
711 module_init(oxp_platform_init);
712 module_exit(oxp_platform_exit);
715 MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
716 MODULE_LICENSE("GPL");