13012bb39SAntheas Kapenekakis // SPDX-License-Identifier: GPL-2.0+
23012bb39SAntheas Kapenekakis /*
33012bb39SAntheas Kapenekakis * Platform driver for OneXPlayer and AOKZOE devices. For the time being,
43012bb39SAntheas Kapenekakis * it also exposes fan controls for AYANEO, and OrangePi Handhelds via
53012bb39SAntheas Kapenekakis * hwmon sysfs.
63012bb39SAntheas Kapenekakis *
73012bb39SAntheas Kapenekakis * Fan control is provided via pwm interface in the range [0-255].
83012bb39SAntheas Kapenekakis * Old AMD boards use [0-100] as range in the EC, the written value is
93012bb39SAntheas Kapenekakis * scaled to accommodate for that. Newer boards like the mini PRO and
103012bb39SAntheas Kapenekakis * AOKZOE are not scaled but have the same EC layout. Newer models
113012bb39SAntheas Kapenekakis * like the 2 and X1 are [0-184] and are scaled to 0-255. OrangePi
123012bb39SAntheas Kapenekakis * are [1-244] and scaled to 0-255.
133012bb39SAntheas Kapenekakis *
143012bb39SAntheas Kapenekakis * Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com>
153012bb39SAntheas Kapenekakis * Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com>
163012bb39SAntheas Kapenekakis * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
173012bb39SAntheas Kapenekakis */
183012bb39SAntheas Kapenekakis
193012bb39SAntheas Kapenekakis #include <linux/acpi.h>
203012bb39SAntheas Kapenekakis #include <linux/dmi.h>
213012bb39SAntheas Kapenekakis #include <linux/hwmon.h>
223012bb39SAntheas Kapenekakis #include <linux/init.h>
233012bb39SAntheas Kapenekakis #include <linux/kernel.h>
243012bb39SAntheas Kapenekakis #include <linux/module.h>
253012bb39SAntheas Kapenekakis #include <linux/platform_device.h>
263012bb39SAntheas Kapenekakis #include <linux/processor.h>
279230b3b8SAntheas Kapenekakis #include <acpi/battery.h>
283012bb39SAntheas Kapenekakis
293012bb39SAntheas Kapenekakis /* Handle ACPI lock mechanism */
303012bb39SAntheas Kapenekakis static u32 oxp_mutex;
313012bb39SAntheas Kapenekakis
323012bb39SAntheas Kapenekakis #define ACPI_LOCK_DELAY_MS 500
333012bb39SAntheas Kapenekakis
lock_global_acpi_lock(void)343012bb39SAntheas Kapenekakis static bool lock_global_acpi_lock(void)
353012bb39SAntheas Kapenekakis {
363012bb39SAntheas Kapenekakis return ACPI_SUCCESS(acpi_acquire_global_lock(ACPI_LOCK_DELAY_MS, &oxp_mutex));
373012bb39SAntheas Kapenekakis }
383012bb39SAntheas Kapenekakis
unlock_global_acpi_lock(void)393012bb39SAntheas Kapenekakis static bool unlock_global_acpi_lock(void)
403012bb39SAntheas Kapenekakis {
413012bb39SAntheas Kapenekakis return ACPI_SUCCESS(acpi_release_global_lock(oxp_mutex));
423012bb39SAntheas Kapenekakis }
433012bb39SAntheas Kapenekakis
443012bb39SAntheas Kapenekakis enum oxp_board {
453012bb39SAntheas Kapenekakis aok_zoe_a1 = 1,
463012bb39SAntheas Kapenekakis aya_neo_2,
473012bb39SAntheas Kapenekakis aya_neo_air,
483012bb39SAntheas Kapenekakis aya_neo_air_1s,
493012bb39SAntheas Kapenekakis aya_neo_air_plus_mendo,
503012bb39SAntheas Kapenekakis aya_neo_air_pro,
513012bb39SAntheas Kapenekakis aya_neo_flip,
523012bb39SAntheas Kapenekakis aya_neo_geek,
533012bb39SAntheas Kapenekakis aya_neo_kun,
543012bb39SAntheas Kapenekakis orange_pi_neo,
553012bb39SAntheas Kapenekakis oxp_2,
563012bb39SAntheas Kapenekakis oxp_fly,
573012bb39SAntheas Kapenekakis oxp_mini_amd,
583012bb39SAntheas Kapenekakis oxp_mini_amd_a07,
593012bb39SAntheas Kapenekakis oxp_mini_amd_pro,
603012bb39SAntheas Kapenekakis oxp_x1,
61*b369395cSAntheas Kapenekakis oxp_g1,
623012bb39SAntheas Kapenekakis };
633012bb39SAntheas Kapenekakis
643012bb39SAntheas Kapenekakis static enum oxp_board board;
659230b3b8SAntheas Kapenekakis static struct device *oxp_dev;
663012bb39SAntheas Kapenekakis
673012bb39SAntheas Kapenekakis /* Fan reading and PWM */
683012bb39SAntheas Kapenekakis #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */
693012bb39SAntheas Kapenekakis #define OXP_2_SENSOR_FAN_REG 0x58 /* Fan reading is 2 registers long */
703012bb39SAntheas Kapenekakis #define OXP_SENSOR_PWM_ENABLE_REG 0x4A /* PWM enable is 1 register long */
713012bb39SAntheas Kapenekakis #define OXP_SENSOR_PWM_REG 0x4B /* PWM reading is 1 register long */
723012bb39SAntheas Kapenekakis #define PWM_MODE_AUTO 0x00
733012bb39SAntheas Kapenekakis #define PWM_MODE_MANUAL 0x01
743012bb39SAntheas Kapenekakis
753012bb39SAntheas Kapenekakis /* OrangePi fan reading and PWM */
763012bb39SAntheas Kapenekakis #define ORANGEPI_SENSOR_FAN_REG 0x78 /* Fan reading is 2 registers long */
773012bb39SAntheas Kapenekakis #define ORANGEPI_SENSOR_PWM_ENABLE_REG 0x40 /* PWM enable is 1 register long */
783012bb39SAntheas Kapenekakis #define ORANGEPI_SENSOR_PWM_REG 0x38 /* PWM reading is 1 register long */
793012bb39SAntheas Kapenekakis
803012bb39SAntheas Kapenekakis /* Turbo button takeover function
813012bb39SAntheas Kapenekakis * Different boards have different values and EC registers
823012bb39SAntheas Kapenekakis * for the same function
833012bb39SAntheas Kapenekakis */
843012bb39SAntheas Kapenekakis #define OXP_TURBO_SWITCH_REG 0xF1 /* Mini Pro, OneXFly, AOKZOE */
853012bb39SAntheas Kapenekakis #define OXP_2_TURBO_SWITCH_REG 0xEB /* OXP2 and X1 */
863012bb39SAntheas Kapenekakis #define OXP_MINI_TURBO_SWITCH_REG 0x1E /* Mini AO7 */
873012bb39SAntheas Kapenekakis
883012bb39SAntheas Kapenekakis #define OXP_MINI_TURBO_TAKE_VAL 0x01 /* Mini AO7 */
893012bb39SAntheas Kapenekakis #define OXP_TURBO_TAKE_VAL 0x40 /* All other models */
903012bb39SAntheas Kapenekakis
9150623acaSAntheas Kapenekakis /* X1 Turbo LED */
9250623acaSAntheas Kapenekakis #define OXP_X1_TURBO_LED_REG 0x57
9350623acaSAntheas Kapenekakis
9450623acaSAntheas Kapenekakis #define OXP_X1_TURBO_LED_OFF 0x01
9550623acaSAntheas Kapenekakis #define OXP_X1_TURBO_LED_ON 0x02
9650623acaSAntheas Kapenekakis
979230b3b8SAntheas Kapenekakis /* Battery extension settings */
989230b3b8SAntheas Kapenekakis #define EC_CHARGE_CONTROL_BEHAVIOURS (BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | \
999230b3b8SAntheas Kapenekakis BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE) | \
1009230b3b8SAntheas Kapenekakis BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE))
1019230b3b8SAntheas Kapenekakis
1029230b3b8SAntheas Kapenekakis #define OXP_X1_CHARGE_LIMIT_REG 0xA3 /* X1 charge limit (%) */
1039230b3b8SAntheas Kapenekakis #define OXP_X1_CHARGE_INHIBIT_REG 0xA4 /* X1 bypass charging */
1049230b3b8SAntheas Kapenekakis
1059230b3b8SAntheas Kapenekakis #define OXP_X1_CHARGE_INHIBIT_MASK_AWAKE 0x01
1069230b3b8SAntheas Kapenekakis /* X1 Mask is 0x0A, F1Pro is 0x02 but the extra bit on the X1 does nothing. */
1079230b3b8SAntheas Kapenekakis #define OXP_X1_CHARGE_INHIBIT_MASK_OFF 0x02
1089230b3b8SAntheas Kapenekakis #define OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS (OXP_X1_CHARGE_INHIBIT_MASK_AWAKE | \
1099230b3b8SAntheas Kapenekakis OXP_X1_CHARGE_INHIBIT_MASK_OFF)
1109230b3b8SAntheas Kapenekakis
1113012bb39SAntheas Kapenekakis static const struct dmi_system_id dmi_table[] = {
1123012bb39SAntheas Kapenekakis {
1133012bb39SAntheas Kapenekakis .matches = {
1143012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
1153012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 AR07"),
1163012bb39SAntheas Kapenekakis },
1173012bb39SAntheas Kapenekakis .driver_data = (void *)aok_zoe_a1,
1183012bb39SAntheas Kapenekakis },
1193012bb39SAntheas Kapenekakis {
1203012bb39SAntheas Kapenekakis .matches = {
1213012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
1223012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1 Pro"),
1233012bb39SAntheas Kapenekakis },
1243012bb39SAntheas Kapenekakis .driver_data = (void *)aok_zoe_a1,
1253012bb39SAntheas Kapenekakis },
1263012bb39SAntheas Kapenekakis {
1273012bb39SAntheas Kapenekakis .matches = {
1283012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1293012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_NAME, "AYANEO 2"),
1303012bb39SAntheas Kapenekakis },
1313012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_2,
1323012bb39SAntheas Kapenekakis },
1333012bb39SAntheas Kapenekakis {
1343012bb39SAntheas Kapenekakis .matches = {
1353012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1363012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR"),
1373012bb39SAntheas Kapenekakis },
1383012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_air,
1393012bb39SAntheas Kapenekakis },
1403012bb39SAntheas Kapenekakis {
1413012bb39SAntheas Kapenekakis .matches = {
1423012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1433012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR 1S"),
1443012bb39SAntheas Kapenekakis },
1453012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_air_1s,
1463012bb39SAntheas Kapenekakis },
1473012bb39SAntheas Kapenekakis {
1483012bb39SAntheas Kapenekakis .matches = {
1493012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1503012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "AB05-Mendocino"),
1513012bb39SAntheas Kapenekakis },
1523012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_air_plus_mendo,
1533012bb39SAntheas Kapenekakis },
1543012bb39SAntheas Kapenekakis {
1553012bb39SAntheas Kapenekakis .matches = {
1563012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1573012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "AIR Pro"),
1583012bb39SAntheas Kapenekakis },
1593012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_air_pro,
1603012bb39SAntheas Kapenekakis },
1613012bb39SAntheas Kapenekakis {
1623012bb39SAntheas Kapenekakis .matches = {
1633012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1643012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_NAME, "FLIP"),
1653012bb39SAntheas Kapenekakis },
1663012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_flip,
1673012bb39SAntheas Kapenekakis },
1683012bb39SAntheas Kapenekakis {
1693012bb39SAntheas Kapenekakis .matches = {
1703012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1713012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_NAME, "GEEK"),
1723012bb39SAntheas Kapenekakis },
1733012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_geek,
1743012bb39SAntheas Kapenekakis },
1753012bb39SAntheas Kapenekakis {
1763012bb39SAntheas Kapenekakis .matches = {
1773012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "AYANEO"),
1783012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "KUN"),
1793012bb39SAntheas Kapenekakis },
1803012bb39SAntheas Kapenekakis .driver_data = (void *)aya_neo_kun,
1813012bb39SAntheas Kapenekakis },
1823012bb39SAntheas Kapenekakis {
1833012bb39SAntheas Kapenekakis .matches = {
1843012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "OrangePi"),
1853012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "NEO-01"),
1863012bb39SAntheas Kapenekakis },
1873012bb39SAntheas Kapenekakis .driver_data = (void *)orange_pi_neo,
1883012bb39SAntheas Kapenekakis },
1893012bb39SAntheas Kapenekakis {
1903012bb39SAntheas Kapenekakis .matches = {
1913012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
1923012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONE XPLAYER"),
1933012bb39SAntheas Kapenekakis },
1943012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_mini_amd,
1953012bb39SAntheas Kapenekakis },
1963012bb39SAntheas Kapenekakis {
1973012bb39SAntheas Kapenekakis .matches = {
1983012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
1993012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 2"),
2003012bb39SAntheas Kapenekakis },
2013012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_2,
2023012bb39SAntheas Kapenekakis },
2033012bb39SAntheas Kapenekakis {
2043012bb39SAntheas Kapenekakis .matches = {
2053012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2063012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"),
2073012bb39SAntheas Kapenekakis },
2083012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_fly,
2093012bb39SAntheas Kapenekakis },
2103012bb39SAntheas Kapenekakis {
2113012bb39SAntheas Kapenekakis .matches = {
2123012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2133012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-01"),
2143012bb39SAntheas Kapenekakis },
2153012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_fly,
2163012bb39SAntheas Kapenekakis },
2173012bb39SAntheas Kapenekakis {
2183012bb39SAntheas Kapenekakis .matches = {
2193012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2203012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 OLED"),
2213012bb39SAntheas Kapenekakis },
2223012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_fly,
2233012bb39SAntheas Kapenekakis },
2243012bb39SAntheas Kapenekakis {
2253012bb39SAntheas Kapenekakis .matches = {
2263012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2273012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1L"),
2283012bb39SAntheas Kapenekakis },
2293012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_fly,
2303012bb39SAntheas Kapenekakis },
2313012bb39SAntheas Kapenekakis {
2323012bb39SAntheas Kapenekakis .matches = {
2333012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2343012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1Pro"),
2353012bb39SAntheas Kapenekakis },
2363012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_fly,
2373012bb39SAntheas Kapenekakis },
2383012bb39SAntheas Kapenekakis {
2393012bb39SAntheas Kapenekakis .matches = {
2403012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2413012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1 EVA-02"),
2423012bb39SAntheas Kapenekakis },
2433012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_fly,
2443012bb39SAntheas Kapenekakis },
2453012bb39SAntheas Kapenekakis {
2463012bb39SAntheas Kapenekakis .matches = {
2473012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
248*b369395cSAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 A"),
249*b369395cSAntheas Kapenekakis },
250*b369395cSAntheas Kapenekakis .driver_data = (void *)oxp_g1,
251*b369395cSAntheas Kapenekakis },
252*b369395cSAntheas Kapenekakis {
253*b369395cSAntheas Kapenekakis .matches = {
254*b369395cSAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
255*b369395cSAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER G1 i"),
256*b369395cSAntheas Kapenekakis },
257*b369395cSAntheas Kapenekakis .driver_data = (void *)oxp_g1,
258*b369395cSAntheas Kapenekakis },
259*b369395cSAntheas Kapenekakis {
260*b369395cSAntheas Kapenekakis .matches = {
261*b369395cSAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2623012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER mini A07"),
2633012bb39SAntheas Kapenekakis },
2643012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_mini_amd_a07,
2653012bb39SAntheas Kapenekakis },
2663012bb39SAntheas Kapenekakis {
2673012bb39SAntheas Kapenekakis .matches = {
2683012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2693012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER Mini Pro"),
2703012bb39SAntheas Kapenekakis },
2713012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_mini_amd_pro,
2723012bb39SAntheas Kapenekakis },
2733012bb39SAntheas Kapenekakis {
2743012bb39SAntheas Kapenekakis .matches = {
2753012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2763012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 A"),
2773012bb39SAntheas Kapenekakis },
2783012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_x1,
2793012bb39SAntheas Kapenekakis },
2803012bb39SAntheas Kapenekakis {
2813012bb39SAntheas Kapenekakis .matches = {
2823012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2833012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 i"),
2843012bb39SAntheas Kapenekakis },
2853012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_x1,
2863012bb39SAntheas Kapenekakis },
2873012bb39SAntheas Kapenekakis {
2883012bb39SAntheas Kapenekakis .matches = {
2893012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2903012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 mini"),
2913012bb39SAntheas Kapenekakis },
2923012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_x1,
2933012bb39SAntheas Kapenekakis },
2943012bb39SAntheas Kapenekakis {
2953012bb39SAntheas Kapenekakis .matches = {
2963012bb39SAntheas Kapenekakis DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
2973012bb39SAntheas Kapenekakis DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Pro"),
2983012bb39SAntheas Kapenekakis },
2993012bb39SAntheas Kapenekakis .driver_data = (void *)oxp_x1,
3003012bb39SAntheas Kapenekakis },
3013012bb39SAntheas Kapenekakis {},
3023012bb39SAntheas Kapenekakis };
3033012bb39SAntheas Kapenekakis
3043012bb39SAntheas Kapenekakis /* Helper functions to handle EC read/write */
read_from_ec(u8 reg,int size,long * val)3053012bb39SAntheas Kapenekakis static int read_from_ec(u8 reg, int size, long *val)
3063012bb39SAntheas Kapenekakis {
3073012bb39SAntheas Kapenekakis u8 buffer;
30838b30882SAntheas Kapenekakis int ret;
30938b30882SAntheas Kapenekakis int i;
3103012bb39SAntheas Kapenekakis
3113012bb39SAntheas Kapenekakis if (!lock_global_acpi_lock())
3123012bb39SAntheas Kapenekakis return -EBUSY;
3133012bb39SAntheas Kapenekakis
3143012bb39SAntheas Kapenekakis *val = 0;
3153012bb39SAntheas Kapenekakis for (i = 0; i < size; i++) {
3163012bb39SAntheas Kapenekakis ret = ec_read(reg + i, &buffer);
3173012bb39SAntheas Kapenekakis if (ret)
3183012bb39SAntheas Kapenekakis return ret;
3193012bb39SAntheas Kapenekakis *val <<= i * 8;
3203012bb39SAntheas Kapenekakis *val += buffer;
3213012bb39SAntheas Kapenekakis }
3223012bb39SAntheas Kapenekakis
3233012bb39SAntheas Kapenekakis if (!unlock_global_acpi_lock())
3243012bb39SAntheas Kapenekakis return -EBUSY;
3253012bb39SAntheas Kapenekakis
3263012bb39SAntheas Kapenekakis return 0;
3273012bb39SAntheas Kapenekakis }
3283012bb39SAntheas Kapenekakis
write_to_ec(u8 reg,u8 value)3293012bb39SAntheas Kapenekakis static int write_to_ec(u8 reg, u8 value)
3303012bb39SAntheas Kapenekakis {
3313012bb39SAntheas Kapenekakis int ret;
3323012bb39SAntheas Kapenekakis
3333012bb39SAntheas Kapenekakis if (!lock_global_acpi_lock())
3343012bb39SAntheas Kapenekakis return -EBUSY;
3353012bb39SAntheas Kapenekakis
3363012bb39SAntheas Kapenekakis ret = ec_write(reg, value);
3373012bb39SAntheas Kapenekakis
3383012bb39SAntheas Kapenekakis if (!unlock_global_acpi_lock())
3393012bb39SAntheas Kapenekakis return -EBUSY;
3403012bb39SAntheas Kapenekakis
3413012bb39SAntheas Kapenekakis return ret;
3423012bb39SAntheas Kapenekakis }
3433012bb39SAntheas Kapenekakis
3443012bb39SAntheas Kapenekakis /* Callbacks for turbo toggle attribute */
tt_toggle_is_visible(struct kobject * kobj,struct attribute * attr,int n)3453012bb39SAntheas Kapenekakis static umode_t tt_toggle_is_visible(struct kobject *kobj,
3463012bb39SAntheas Kapenekakis struct attribute *attr, int n)
3473012bb39SAntheas Kapenekakis {
3483012bb39SAntheas Kapenekakis switch (board) {
3493012bb39SAntheas Kapenekakis case aok_zoe_a1:
3503012bb39SAntheas Kapenekakis case oxp_2:
3513012bb39SAntheas Kapenekakis case oxp_fly:
3523012bb39SAntheas Kapenekakis case oxp_mini_amd_a07:
3533012bb39SAntheas Kapenekakis case oxp_mini_amd_pro:
3543012bb39SAntheas Kapenekakis case oxp_x1:
355*b369395cSAntheas Kapenekakis case oxp_g1:
3563012bb39SAntheas Kapenekakis return attr->mode;
3573012bb39SAntheas Kapenekakis default:
3583012bb39SAntheas Kapenekakis break;
3593012bb39SAntheas Kapenekakis }
3603012bb39SAntheas Kapenekakis return 0;
3613012bb39SAntheas Kapenekakis }
3623012bb39SAntheas Kapenekakis
tt_toggle_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3633012bb39SAntheas Kapenekakis static ssize_t tt_toggle_store(struct device *dev,
3643012bb39SAntheas Kapenekakis struct device_attribute *attr, const char *buf,
3653012bb39SAntheas Kapenekakis size_t count)
3663012bb39SAntheas Kapenekakis {
367e25a982bSAntheas Kapenekakis u8 reg, mask, val;
368e25a982bSAntheas Kapenekakis long raw_val;
369e25a982bSAntheas Kapenekakis bool enable;
37097e3d8acSAntheas Kapenekakis int ret;
3713012bb39SAntheas Kapenekakis
372e25a982bSAntheas Kapenekakis ret = kstrtobool(buf, &enable);
37397e3d8acSAntheas Kapenekakis if (ret)
37497e3d8acSAntheas Kapenekakis return ret;
3753012bb39SAntheas Kapenekakis
376e25a982bSAntheas Kapenekakis switch (board) {
377e25a982bSAntheas Kapenekakis case oxp_mini_amd_a07:
378e25a982bSAntheas Kapenekakis reg = OXP_MINI_TURBO_SWITCH_REG;
379e25a982bSAntheas Kapenekakis mask = OXP_MINI_TURBO_TAKE_VAL;
380e25a982bSAntheas Kapenekakis break;
381e25a982bSAntheas Kapenekakis case aok_zoe_a1:
382e25a982bSAntheas Kapenekakis case oxp_fly:
383e25a982bSAntheas Kapenekakis case oxp_mini_amd_pro:
384e25a982bSAntheas Kapenekakis reg = OXP_TURBO_SWITCH_REG;
385e25a982bSAntheas Kapenekakis mask = OXP_TURBO_TAKE_VAL;
386e25a982bSAntheas Kapenekakis break;
387e25a982bSAntheas Kapenekakis case oxp_2:
388e25a982bSAntheas Kapenekakis case oxp_x1:
389*b369395cSAntheas Kapenekakis case oxp_g1:
390e25a982bSAntheas Kapenekakis reg = OXP_2_TURBO_SWITCH_REG;
391e25a982bSAntheas Kapenekakis mask = OXP_TURBO_TAKE_VAL;
392e25a982bSAntheas Kapenekakis break;
393e25a982bSAntheas Kapenekakis default:
394e25a982bSAntheas Kapenekakis return -EINVAL;
3953012bb39SAntheas Kapenekakis }
396e25a982bSAntheas Kapenekakis
397e25a982bSAntheas Kapenekakis ret = read_from_ec(reg, 1, &raw_val);
398e25a982bSAntheas Kapenekakis if (ret)
399e25a982bSAntheas Kapenekakis return ret;
400e25a982bSAntheas Kapenekakis
401e25a982bSAntheas Kapenekakis val = raw_val;
402e25a982bSAntheas Kapenekakis if (enable)
403e25a982bSAntheas Kapenekakis val |= mask;
404e25a982bSAntheas Kapenekakis else
405e25a982bSAntheas Kapenekakis val &= ~mask;
406e25a982bSAntheas Kapenekakis
407e25a982bSAntheas Kapenekakis ret = write_to_ec(reg, val);
40897e3d8acSAntheas Kapenekakis if (ret)
40997e3d8acSAntheas Kapenekakis return ret;
4103012bb39SAntheas Kapenekakis
4113012bb39SAntheas Kapenekakis return count;
4123012bb39SAntheas Kapenekakis }
4133012bb39SAntheas Kapenekakis
tt_toggle_show(struct device * dev,struct device_attribute * attr,char * buf)4143012bb39SAntheas Kapenekakis static ssize_t tt_toggle_show(struct device *dev,
4153012bb39SAntheas Kapenekakis struct device_attribute *attr, char *buf)
4163012bb39SAntheas Kapenekakis {
417e25a982bSAntheas Kapenekakis u8 reg, mask;
4183012bb39SAntheas Kapenekakis int retval;
4193012bb39SAntheas Kapenekakis long val;
4203012bb39SAntheas Kapenekakis
4213012bb39SAntheas Kapenekakis switch (board) {
4223012bb39SAntheas Kapenekakis case oxp_mini_amd_a07:
4233012bb39SAntheas Kapenekakis reg = OXP_MINI_TURBO_SWITCH_REG;
424e25a982bSAntheas Kapenekakis mask = OXP_MINI_TURBO_TAKE_VAL;
4253012bb39SAntheas Kapenekakis break;
4263012bb39SAntheas Kapenekakis case aok_zoe_a1:
4273012bb39SAntheas Kapenekakis case oxp_fly:
4283012bb39SAntheas Kapenekakis case oxp_mini_amd_pro:
4293012bb39SAntheas Kapenekakis reg = OXP_TURBO_SWITCH_REG;
430e25a982bSAntheas Kapenekakis mask = OXP_TURBO_TAKE_VAL;
4313012bb39SAntheas Kapenekakis break;
4323012bb39SAntheas Kapenekakis case oxp_2:
4333012bb39SAntheas Kapenekakis case oxp_x1:
434*b369395cSAntheas Kapenekakis case oxp_g1:
4353012bb39SAntheas Kapenekakis reg = OXP_2_TURBO_SWITCH_REG;
436e25a982bSAntheas Kapenekakis mask = OXP_TURBO_TAKE_VAL;
4373012bb39SAntheas Kapenekakis break;
4383012bb39SAntheas Kapenekakis default:
4393012bb39SAntheas Kapenekakis return -EINVAL;
4403012bb39SAntheas Kapenekakis }
4413012bb39SAntheas Kapenekakis
4423012bb39SAntheas Kapenekakis retval = read_from_ec(reg, 1, &val);
4433012bb39SAntheas Kapenekakis if (retval)
4443012bb39SAntheas Kapenekakis return retval;
4453012bb39SAntheas Kapenekakis
446e25a982bSAntheas Kapenekakis return sysfs_emit(buf, "%d\n", (val & mask) == mask);
4473012bb39SAntheas Kapenekakis }
4483012bb39SAntheas Kapenekakis
4493012bb39SAntheas Kapenekakis static DEVICE_ATTR_RW(tt_toggle);
4503012bb39SAntheas Kapenekakis
45150623acaSAntheas Kapenekakis /* Callbacks for turbo LED attribute */
tt_led_is_visible(struct kobject * kobj,struct attribute * attr,int n)45250623acaSAntheas Kapenekakis static umode_t tt_led_is_visible(struct kobject *kobj,
45350623acaSAntheas Kapenekakis struct attribute *attr, int n)
45450623acaSAntheas Kapenekakis {
45550623acaSAntheas Kapenekakis switch (board) {
45650623acaSAntheas Kapenekakis case oxp_x1:
45750623acaSAntheas Kapenekakis return attr->mode;
45850623acaSAntheas Kapenekakis default:
45950623acaSAntheas Kapenekakis break;
46050623acaSAntheas Kapenekakis }
46150623acaSAntheas Kapenekakis return 0;
46250623acaSAntheas Kapenekakis }
46350623acaSAntheas Kapenekakis
tt_led_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)46450623acaSAntheas Kapenekakis static ssize_t tt_led_store(struct device *dev,
46550623acaSAntheas Kapenekakis struct device_attribute *attr, const char *buf,
46650623acaSAntheas Kapenekakis size_t count)
46750623acaSAntheas Kapenekakis {
46850623acaSAntheas Kapenekakis u8 reg, val;
46950623acaSAntheas Kapenekakis bool value;
47050623acaSAntheas Kapenekakis int ret;
47150623acaSAntheas Kapenekakis
47250623acaSAntheas Kapenekakis ret = kstrtobool(buf, &value);
47350623acaSAntheas Kapenekakis if (ret)
47450623acaSAntheas Kapenekakis return ret;
47550623acaSAntheas Kapenekakis
47650623acaSAntheas Kapenekakis switch (board) {
47750623acaSAntheas Kapenekakis case oxp_x1:
47850623acaSAntheas Kapenekakis reg = OXP_X1_TURBO_LED_REG;
47950623acaSAntheas Kapenekakis val = value ? OXP_X1_TURBO_LED_ON : OXP_X1_TURBO_LED_OFF;
48050623acaSAntheas Kapenekakis break;
48150623acaSAntheas Kapenekakis default:
48250623acaSAntheas Kapenekakis return -EINVAL;
48350623acaSAntheas Kapenekakis }
48450623acaSAntheas Kapenekakis
48550623acaSAntheas Kapenekakis ret = write_to_ec(reg, val);
48650623acaSAntheas Kapenekakis if (ret)
48750623acaSAntheas Kapenekakis return ret;
48850623acaSAntheas Kapenekakis
48950623acaSAntheas Kapenekakis return count;
49050623acaSAntheas Kapenekakis }
49150623acaSAntheas Kapenekakis
tt_led_show(struct device * dev,struct device_attribute * attr,char * buf)49250623acaSAntheas Kapenekakis static ssize_t tt_led_show(struct device *dev,
49350623acaSAntheas Kapenekakis struct device_attribute *attr, char *buf)
49450623acaSAntheas Kapenekakis {
49550623acaSAntheas Kapenekakis long enval;
49650623acaSAntheas Kapenekakis long val;
49750623acaSAntheas Kapenekakis int ret;
49850623acaSAntheas Kapenekakis u8 reg;
49950623acaSAntheas Kapenekakis
50050623acaSAntheas Kapenekakis switch (board) {
50150623acaSAntheas Kapenekakis case oxp_x1:
50250623acaSAntheas Kapenekakis reg = OXP_X1_TURBO_LED_REG;
50350623acaSAntheas Kapenekakis enval = OXP_X1_TURBO_LED_ON;
50450623acaSAntheas Kapenekakis break;
50550623acaSAntheas Kapenekakis default:
50650623acaSAntheas Kapenekakis return -EINVAL;
50750623acaSAntheas Kapenekakis }
50850623acaSAntheas Kapenekakis
50950623acaSAntheas Kapenekakis ret = read_from_ec(reg, 1, &val);
51050623acaSAntheas Kapenekakis if (ret)
51150623acaSAntheas Kapenekakis return ret;
51250623acaSAntheas Kapenekakis
51350623acaSAntheas Kapenekakis return sysfs_emit(buf, "%d\n", val == enval);
51450623acaSAntheas Kapenekakis }
51550623acaSAntheas Kapenekakis
51650623acaSAntheas Kapenekakis static DEVICE_ATTR_RW(tt_led);
51750623acaSAntheas Kapenekakis
5189230b3b8SAntheas Kapenekakis /* Callbacks for charge behaviour attributes */
oxp_psy_ext_supported(void)5199230b3b8SAntheas Kapenekakis static bool oxp_psy_ext_supported(void)
5209230b3b8SAntheas Kapenekakis {
5219230b3b8SAntheas Kapenekakis switch (board) {
5229230b3b8SAntheas Kapenekakis case oxp_x1:
523*b369395cSAntheas Kapenekakis case oxp_g1:
5249230b3b8SAntheas Kapenekakis case oxp_fly:
5259230b3b8SAntheas Kapenekakis return true;
5269230b3b8SAntheas Kapenekakis default:
5279230b3b8SAntheas Kapenekakis break;
5289230b3b8SAntheas Kapenekakis }
5299230b3b8SAntheas Kapenekakis return false;
5309230b3b8SAntheas Kapenekakis }
5319230b3b8SAntheas Kapenekakis
oxp_psy_ext_get_prop(struct power_supply * psy,const struct power_supply_ext * ext,void * data,enum power_supply_property psp,union power_supply_propval * val)5329230b3b8SAntheas Kapenekakis static int oxp_psy_ext_get_prop(struct power_supply *psy,
5339230b3b8SAntheas Kapenekakis const struct power_supply_ext *ext,
5349230b3b8SAntheas Kapenekakis void *data,
5359230b3b8SAntheas Kapenekakis enum power_supply_property psp,
5369230b3b8SAntheas Kapenekakis union power_supply_propval *val)
5379230b3b8SAntheas Kapenekakis {
5389230b3b8SAntheas Kapenekakis long raw_val;
5399230b3b8SAntheas Kapenekakis int ret;
5409230b3b8SAntheas Kapenekakis
5419230b3b8SAntheas Kapenekakis switch (psp) {
5429230b3b8SAntheas Kapenekakis case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
5439230b3b8SAntheas Kapenekakis ret = read_from_ec(OXP_X1_CHARGE_LIMIT_REG, 1, &raw_val);
5449230b3b8SAntheas Kapenekakis if (ret)
5459230b3b8SAntheas Kapenekakis return ret;
5469230b3b8SAntheas Kapenekakis if (raw_val < 0 || raw_val > 100)
5479230b3b8SAntheas Kapenekakis return -EINVAL;
5489230b3b8SAntheas Kapenekakis val->intval = raw_val;
5499230b3b8SAntheas Kapenekakis return 0;
5509230b3b8SAntheas Kapenekakis case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
5519230b3b8SAntheas Kapenekakis ret = read_from_ec(OXP_X1_CHARGE_INHIBIT_REG, 1, &raw_val);
5529230b3b8SAntheas Kapenekakis if (ret)
5539230b3b8SAntheas Kapenekakis return ret;
5549230b3b8SAntheas Kapenekakis if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS) ==
5559230b3b8SAntheas Kapenekakis OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS)
5569230b3b8SAntheas Kapenekakis val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
5579230b3b8SAntheas Kapenekakis else if ((raw_val & OXP_X1_CHARGE_INHIBIT_MASK_AWAKE) ==
5589230b3b8SAntheas Kapenekakis OXP_X1_CHARGE_INHIBIT_MASK_AWAKE)
5599230b3b8SAntheas Kapenekakis val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE;
5609230b3b8SAntheas Kapenekakis else
5619230b3b8SAntheas Kapenekakis val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO;
5629230b3b8SAntheas Kapenekakis return 0;
5639230b3b8SAntheas Kapenekakis default:
5649230b3b8SAntheas Kapenekakis return -EINVAL;
5659230b3b8SAntheas Kapenekakis }
5669230b3b8SAntheas Kapenekakis }
5679230b3b8SAntheas Kapenekakis
oxp_psy_ext_set_prop(struct power_supply * psy,const struct power_supply_ext * ext,void * data,enum power_supply_property psp,const union power_supply_propval * val)5689230b3b8SAntheas Kapenekakis static int oxp_psy_ext_set_prop(struct power_supply *psy,
5699230b3b8SAntheas Kapenekakis const struct power_supply_ext *ext,
5709230b3b8SAntheas Kapenekakis void *data,
5719230b3b8SAntheas Kapenekakis enum power_supply_property psp,
5729230b3b8SAntheas Kapenekakis const union power_supply_propval *val)
5739230b3b8SAntheas Kapenekakis {
5749230b3b8SAntheas Kapenekakis long raw_val;
5759230b3b8SAntheas Kapenekakis
5769230b3b8SAntheas Kapenekakis switch (psp) {
5779230b3b8SAntheas Kapenekakis case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
578c5925f43SDan Carpenter if (val->intval < 0 || val->intval > 100)
5799230b3b8SAntheas Kapenekakis return -EINVAL;
5809230b3b8SAntheas Kapenekakis return write_to_ec(OXP_X1_CHARGE_LIMIT_REG, val->intval);
5819230b3b8SAntheas Kapenekakis case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR:
5829230b3b8SAntheas Kapenekakis switch (val->intval) {
5839230b3b8SAntheas Kapenekakis case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
5849230b3b8SAntheas Kapenekakis raw_val = 0;
5859230b3b8SAntheas Kapenekakis break;
5869230b3b8SAntheas Kapenekakis case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE_AWAKE:
5879230b3b8SAntheas Kapenekakis raw_val = OXP_X1_CHARGE_INHIBIT_MASK_AWAKE;
5889230b3b8SAntheas Kapenekakis break;
5899230b3b8SAntheas Kapenekakis case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
5909230b3b8SAntheas Kapenekakis raw_val = OXP_X1_CHARGE_INHIBIT_MASK_ALWAYS;
5919230b3b8SAntheas Kapenekakis break;
5929230b3b8SAntheas Kapenekakis default:
5939230b3b8SAntheas Kapenekakis return -EINVAL;
5949230b3b8SAntheas Kapenekakis }
5959230b3b8SAntheas Kapenekakis
5969230b3b8SAntheas Kapenekakis return write_to_ec(OXP_X1_CHARGE_INHIBIT_REG, raw_val);
5979230b3b8SAntheas Kapenekakis default:
5989230b3b8SAntheas Kapenekakis return -EINVAL;
5999230b3b8SAntheas Kapenekakis }
6009230b3b8SAntheas Kapenekakis }
6019230b3b8SAntheas Kapenekakis
oxp_psy_prop_is_writeable(struct power_supply * psy,const struct power_supply_ext * ext,void * data,enum power_supply_property psp)6029230b3b8SAntheas Kapenekakis static int oxp_psy_prop_is_writeable(struct power_supply *psy,
6039230b3b8SAntheas Kapenekakis const struct power_supply_ext *ext,
6049230b3b8SAntheas Kapenekakis void *data,
6059230b3b8SAntheas Kapenekakis enum power_supply_property psp)
6069230b3b8SAntheas Kapenekakis {
6079230b3b8SAntheas Kapenekakis return true;
6089230b3b8SAntheas Kapenekakis }
6099230b3b8SAntheas Kapenekakis
6109230b3b8SAntheas Kapenekakis static const enum power_supply_property oxp_psy_ext_props[] = {
6119230b3b8SAntheas Kapenekakis POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR,
6129230b3b8SAntheas Kapenekakis POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
6139230b3b8SAntheas Kapenekakis };
6149230b3b8SAntheas Kapenekakis
6159230b3b8SAntheas Kapenekakis static const struct power_supply_ext oxp_psy_ext = {
6169230b3b8SAntheas Kapenekakis .name = "oxp-charge-control",
6179230b3b8SAntheas Kapenekakis .properties = oxp_psy_ext_props,
6189230b3b8SAntheas Kapenekakis .num_properties = ARRAY_SIZE(oxp_psy_ext_props),
6199230b3b8SAntheas Kapenekakis .charge_behaviours = EC_CHARGE_CONTROL_BEHAVIOURS,
6209230b3b8SAntheas Kapenekakis .get_property = oxp_psy_ext_get_prop,
6219230b3b8SAntheas Kapenekakis .set_property = oxp_psy_ext_set_prop,
6229230b3b8SAntheas Kapenekakis .property_is_writeable = oxp_psy_prop_is_writeable,
6239230b3b8SAntheas Kapenekakis };
6249230b3b8SAntheas Kapenekakis
oxp_add_battery(struct power_supply * battery,struct acpi_battery_hook * hook)6259230b3b8SAntheas Kapenekakis static int oxp_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
6269230b3b8SAntheas Kapenekakis {
6279230b3b8SAntheas Kapenekakis return power_supply_register_extension(battery, &oxp_psy_ext, oxp_dev, NULL);
6289230b3b8SAntheas Kapenekakis }
6299230b3b8SAntheas Kapenekakis
oxp_remove_battery(struct power_supply * battery,struct acpi_battery_hook * hook)6309230b3b8SAntheas Kapenekakis static int oxp_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
6319230b3b8SAntheas Kapenekakis {
6329230b3b8SAntheas Kapenekakis power_supply_unregister_extension(battery, &oxp_psy_ext);
6339230b3b8SAntheas Kapenekakis return 0;
6349230b3b8SAntheas Kapenekakis }
6359230b3b8SAntheas Kapenekakis
6369230b3b8SAntheas Kapenekakis static struct acpi_battery_hook battery_hook = {
6379230b3b8SAntheas Kapenekakis .add_battery = oxp_add_battery,
6389230b3b8SAntheas Kapenekakis .remove_battery = oxp_remove_battery,
6399230b3b8SAntheas Kapenekakis .name = "OneXPlayer Battery",
6409230b3b8SAntheas Kapenekakis };
6419230b3b8SAntheas Kapenekakis
6423012bb39SAntheas Kapenekakis /* PWM enable/disable functions */
oxp_pwm_enable(void)6433012bb39SAntheas Kapenekakis static int oxp_pwm_enable(void)
6443012bb39SAntheas Kapenekakis {
6453012bb39SAntheas Kapenekakis switch (board) {
6463012bb39SAntheas Kapenekakis case orange_pi_neo:
6473012bb39SAntheas Kapenekakis return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
6483012bb39SAntheas Kapenekakis case aok_zoe_a1:
6493012bb39SAntheas Kapenekakis case aya_neo_2:
6503012bb39SAntheas Kapenekakis case aya_neo_air:
6513012bb39SAntheas Kapenekakis case aya_neo_air_plus_mendo:
6523012bb39SAntheas Kapenekakis case aya_neo_air_pro:
6533012bb39SAntheas Kapenekakis case aya_neo_flip:
6543012bb39SAntheas Kapenekakis case aya_neo_geek:
6553012bb39SAntheas Kapenekakis case aya_neo_kun:
6563012bb39SAntheas Kapenekakis case oxp_2:
6573012bb39SAntheas Kapenekakis case oxp_fly:
6583012bb39SAntheas Kapenekakis case oxp_mini_amd:
6593012bb39SAntheas Kapenekakis case oxp_mini_amd_a07:
6603012bb39SAntheas Kapenekakis case oxp_mini_amd_pro:
6613012bb39SAntheas Kapenekakis case oxp_x1:
662*b369395cSAntheas Kapenekakis case oxp_g1:
6633012bb39SAntheas Kapenekakis return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL);
6643012bb39SAntheas Kapenekakis default:
6653012bb39SAntheas Kapenekakis return -EINVAL;
6663012bb39SAntheas Kapenekakis }
6673012bb39SAntheas Kapenekakis }
6683012bb39SAntheas Kapenekakis
oxp_pwm_disable(void)6693012bb39SAntheas Kapenekakis static int oxp_pwm_disable(void)
6703012bb39SAntheas Kapenekakis {
6713012bb39SAntheas Kapenekakis switch (board) {
6723012bb39SAntheas Kapenekakis case orange_pi_neo:
6733012bb39SAntheas Kapenekakis return write_to_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
6743012bb39SAntheas Kapenekakis case aok_zoe_a1:
6753012bb39SAntheas Kapenekakis case aya_neo_2:
6763012bb39SAntheas Kapenekakis case aya_neo_air:
6773012bb39SAntheas Kapenekakis case aya_neo_air_1s:
6783012bb39SAntheas Kapenekakis case aya_neo_air_plus_mendo:
6793012bb39SAntheas Kapenekakis case aya_neo_air_pro:
6803012bb39SAntheas Kapenekakis case aya_neo_flip:
6813012bb39SAntheas Kapenekakis case aya_neo_geek:
6823012bb39SAntheas Kapenekakis case aya_neo_kun:
6833012bb39SAntheas Kapenekakis case oxp_2:
6843012bb39SAntheas Kapenekakis case oxp_fly:
6853012bb39SAntheas Kapenekakis case oxp_mini_amd:
6863012bb39SAntheas Kapenekakis case oxp_mini_amd_a07:
6873012bb39SAntheas Kapenekakis case oxp_mini_amd_pro:
6883012bb39SAntheas Kapenekakis case oxp_x1:
689*b369395cSAntheas Kapenekakis case oxp_g1:
6903012bb39SAntheas Kapenekakis return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO);
6913012bb39SAntheas Kapenekakis default:
6923012bb39SAntheas Kapenekakis return -EINVAL;
6933012bb39SAntheas Kapenekakis }
6943012bb39SAntheas Kapenekakis }
6953012bb39SAntheas Kapenekakis
oxp_pwm_read(long * val)6966b89cf6dSAntheas Kapenekakis static int oxp_pwm_read(long *val)
6976b89cf6dSAntheas Kapenekakis {
6986b89cf6dSAntheas Kapenekakis switch (board) {
6996b89cf6dSAntheas Kapenekakis case orange_pi_neo:
7006b89cf6dSAntheas Kapenekakis return read_from_ec(ORANGEPI_SENSOR_PWM_ENABLE_REG, 1, val);
7016b89cf6dSAntheas Kapenekakis case aok_zoe_a1:
7026b89cf6dSAntheas Kapenekakis case aya_neo_2:
7036b89cf6dSAntheas Kapenekakis case aya_neo_air:
7046b89cf6dSAntheas Kapenekakis case aya_neo_air_1s:
7056b89cf6dSAntheas Kapenekakis case aya_neo_air_plus_mendo:
7066b89cf6dSAntheas Kapenekakis case aya_neo_air_pro:
7076b89cf6dSAntheas Kapenekakis case aya_neo_flip:
7086b89cf6dSAntheas Kapenekakis case aya_neo_geek:
7096b89cf6dSAntheas Kapenekakis case aya_neo_kun:
7106b89cf6dSAntheas Kapenekakis case oxp_2:
7116b89cf6dSAntheas Kapenekakis case oxp_fly:
7126b89cf6dSAntheas Kapenekakis case oxp_mini_amd:
7136b89cf6dSAntheas Kapenekakis case oxp_mini_amd_a07:
7146b89cf6dSAntheas Kapenekakis case oxp_mini_amd_pro:
7156b89cf6dSAntheas Kapenekakis case oxp_x1:
716*b369395cSAntheas Kapenekakis case oxp_g1:
7176b89cf6dSAntheas Kapenekakis return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val);
7186b89cf6dSAntheas Kapenekakis default:
7196b89cf6dSAntheas Kapenekakis return -EOPNOTSUPP;
7206b89cf6dSAntheas Kapenekakis }
7216b89cf6dSAntheas Kapenekakis }
7226b89cf6dSAntheas Kapenekakis
7233012bb39SAntheas Kapenekakis /* Callbacks for hwmon interface */
oxp_ec_hwmon_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)7243012bb39SAntheas Kapenekakis static umode_t oxp_ec_hwmon_is_visible(const void *drvdata,
7253012bb39SAntheas Kapenekakis enum hwmon_sensor_types type, u32 attr, int channel)
7263012bb39SAntheas Kapenekakis {
7273012bb39SAntheas Kapenekakis switch (type) {
7283012bb39SAntheas Kapenekakis case hwmon_fan:
7293012bb39SAntheas Kapenekakis return 0444;
7303012bb39SAntheas Kapenekakis case hwmon_pwm:
7313012bb39SAntheas Kapenekakis return 0644;
7323012bb39SAntheas Kapenekakis default:
7333012bb39SAntheas Kapenekakis return 0;
7343012bb39SAntheas Kapenekakis }
7353012bb39SAntheas Kapenekakis }
7363012bb39SAntheas Kapenekakis
737665fab33SAntheas Kapenekakis /* Fan speed read function */
oxp_pwm_fan_speed(long * val)738665fab33SAntheas Kapenekakis static int oxp_pwm_fan_speed(long *val)
739665fab33SAntheas Kapenekakis {
740665fab33SAntheas Kapenekakis switch (board) {
741665fab33SAntheas Kapenekakis case orange_pi_neo:
742665fab33SAntheas Kapenekakis return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val);
743665fab33SAntheas Kapenekakis case oxp_2:
744665fab33SAntheas Kapenekakis case oxp_x1:
745*b369395cSAntheas Kapenekakis case oxp_g1:
746665fab33SAntheas Kapenekakis return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val);
747665fab33SAntheas Kapenekakis case aok_zoe_a1:
748665fab33SAntheas Kapenekakis case aya_neo_2:
749665fab33SAntheas Kapenekakis case aya_neo_air:
750665fab33SAntheas Kapenekakis case aya_neo_air_1s:
751665fab33SAntheas Kapenekakis case aya_neo_air_plus_mendo:
752665fab33SAntheas Kapenekakis case aya_neo_air_pro:
753665fab33SAntheas Kapenekakis case aya_neo_flip:
754665fab33SAntheas Kapenekakis case aya_neo_geek:
755665fab33SAntheas Kapenekakis case aya_neo_kun:
756665fab33SAntheas Kapenekakis case oxp_fly:
757665fab33SAntheas Kapenekakis case oxp_mini_amd:
758665fab33SAntheas Kapenekakis case oxp_mini_amd_a07:
759665fab33SAntheas Kapenekakis case oxp_mini_amd_pro:
760665fab33SAntheas Kapenekakis return read_from_ec(OXP_SENSOR_FAN_REG, 2, val);
761665fab33SAntheas Kapenekakis default:
762665fab33SAntheas Kapenekakis return -EOPNOTSUPP;
763665fab33SAntheas Kapenekakis }
764665fab33SAntheas Kapenekakis }
765665fab33SAntheas Kapenekakis
766b804a9b8SAntheas Kapenekakis /* PWM input read/write functions */
oxp_pwm_input_write(long val)767b804a9b8SAntheas Kapenekakis static int oxp_pwm_input_write(long val)
7683012bb39SAntheas Kapenekakis {
769b804a9b8SAntheas Kapenekakis if (val < 0 || val > 255)
770b804a9b8SAntheas Kapenekakis return -EINVAL;
7713012bb39SAntheas Kapenekakis
7723012bb39SAntheas Kapenekakis switch (board) {
7733012bb39SAntheas Kapenekakis case orange_pi_neo:
774b804a9b8SAntheas Kapenekakis /* scale to range [1-244] */
775b804a9b8SAntheas Kapenekakis val = ((val - 1) * 243 / 254) + 1;
776b804a9b8SAntheas Kapenekakis return write_to_ec(ORANGEPI_SENSOR_PWM_REG, val);
7773012bb39SAntheas Kapenekakis case oxp_2:
7783012bb39SAntheas Kapenekakis case oxp_x1:
779*b369395cSAntheas Kapenekakis case oxp_g1:
780b804a9b8SAntheas Kapenekakis /* scale to range [0-184] */
781b804a9b8SAntheas Kapenekakis val = (val * 184) / 255;
782b804a9b8SAntheas Kapenekakis return write_to_ec(OXP_SENSOR_PWM_REG, val);
7833012bb39SAntheas Kapenekakis case aya_neo_2:
7843012bb39SAntheas Kapenekakis case aya_neo_air:
7853012bb39SAntheas Kapenekakis case aya_neo_air_1s:
7863012bb39SAntheas Kapenekakis case aya_neo_air_plus_mendo:
7873012bb39SAntheas Kapenekakis case aya_neo_air_pro:
7883012bb39SAntheas Kapenekakis case aya_neo_flip:
7893012bb39SAntheas Kapenekakis case aya_neo_geek:
7903012bb39SAntheas Kapenekakis case aya_neo_kun:
7913012bb39SAntheas Kapenekakis case oxp_mini_amd:
7923012bb39SAntheas Kapenekakis case oxp_mini_amd_a07:
793b804a9b8SAntheas Kapenekakis /* scale to range [0-100] */
794b804a9b8SAntheas Kapenekakis val = (val * 100) / 255;
795b804a9b8SAntheas Kapenekakis return write_to_ec(OXP_SENSOR_PWM_REG, val);
796b804a9b8SAntheas Kapenekakis case aok_zoe_a1:
797b804a9b8SAntheas Kapenekakis case oxp_fly:
7983012bb39SAntheas Kapenekakis case oxp_mini_amd_pro:
799b804a9b8SAntheas Kapenekakis return write_to_ec(OXP_SENSOR_PWM_REG, val);
8003012bb39SAntheas Kapenekakis default:
801b804a9b8SAntheas Kapenekakis return -EOPNOTSUPP;
8023012bb39SAntheas Kapenekakis }
8033012bb39SAntheas Kapenekakis }
804b804a9b8SAntheas Kapenekakis
oxp_pwm_input_read(long * val)805b804a9b8SAntheas Kapenekakis static int oxp_pwm_input_read(long *val)
806b804a9b8SAntheas Kapenekakis {
807b804a9b8SAntheas Kapenekakis int ret;
808b804a9b8SAntheas Kapenekakis
8093012bb39SAntheas Kapenekakis switch (board) {
8103012bb39SAntheas Kapenekakis case orange_pi_neo:
8113012bb39SAntheas Kapenekakis ret = read_from_ec(ORANGEPI_SENSOR_PWM_REG, 1, val);
8123012bb39SAntheas Kapenekakis if (ret)
8133012bb39SAntheas Kapenekakis return ret;
8143012bb39SAntheas Kapenekakis /* scale from range [1-244] */
8153012bb39SAntheas Kapenekakis *val = ((*val - 1) * 254 / 243) + 1;
8163012bb39SAntheas Kapenekakis break;
8173012bb39SAntheas Kapenekakis case oxp_2:
8183012bb39SAntheas Kapenekakis case oxp_x1:
819*b369395cSAntheas Kapenekakis case oxp_g1:
8203012bb39SAntheas Kapenekakis ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
8213012bb39SAntheas Kapenekakis if (ret)
8223012bb39SAntheas Kapenekakis return ret;
8233012bb39SAntheas Kapenekakis /* scale from range [0-184] */
8243012bb39SAntheas Kapenekakis *val = (*val * 255) / 184;
8253012bb39SAntheas Kapenekakis break;
8263012bb39SAntheas Kapenekakis case aya_neo_2:
8273012bb39SAntheas Kapenekakis case aya_neo_air:
8283012bb39SAntheas Kapenekakis case aya_neo_air_1s:
8293012bb39SAntheas Kapenekakis case aya_neo_air_plus_mendo:
8303012bb39SAntheas Kapenekakis case aya_neo_air_pro:
8313012bb39SAntheas Kapenekakis case aya_neo_flip:
8323012bb39SAntheas Kapenekakis case aya_neo_geek:
8333012bb39SAntheas Kapenekakis case aya_neo_kun:
8343012bb39SAntheas Kapenekakis case oxp_mini_amd:
8353012bb39SAntheas Kapenekakis case oxp_mini_amd_a07:
8363012bb39SAntheas Kapenekakis ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
8373012bb39SAntheas Kapenekakis if (ret)
8383012bb39SAntheas Kapenekakis return ret;
8393012bb39SAntheas Kapenekakis /* scale from range [0-100] */
8403012bb39SAntheas Kapenekakis *val = (*val * 255) / 100;
8413012bb39SAntheas Kapenekakis break;
8423012bb39SAntheas Kapenekakis case aok_zoe_a1:
8433012bb39SAntheas Kapenekakis case oxp_fly:
8443012bb39SAntheas Kapenekakis case oxp_mini_amd_pro:
8453012bb39SAntheas Kapenekakis default:
8463012bb39SAntheas Kapenekakis ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val);
8473012bb39SAntheas Kapenekakis if (ret)
8483012bb39SAntheas Kapenekakis return ret;
8493012bb39SAntheas Kapenekakis break;
8503012bb39SAntheas Kapenekakis }
8513012bb39SAntheas Kapenekakis return 0;
852b804a9b8SAntheas Kapenekakis }
853b804a9b8SAntheas Kapenekakis
oxp_platform_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)854b804a9b8SAntheas Kapenekakis static int oxp_platform_read(struct device *dev, enum hwmon_sensor_types type,
855b804a9b8SAntheas Kapenekakis u32 attr, int channel, long *val)
856b804a9b8SAntheas Kapenekakis {
857b804a9b8SAntheas Kapenekakis int ret;
858b804a9b8SAntheas Kapenekakis
859b804a9b8SAntheas Kapenekakis switch (type) {
860b804a9b8SAntheas Kapenekakis case hwmon_fan:
861b804a9b8SAntheas Kapenekakis switch (attr) {
862b804a9b8SAntheas Kapenekakis case hwmon_fan_input:
863665fab33SAntheas Kapenekakis return oxp_pwm_fan_speed(val);
864b804a9b8SAntheas Kapenekakis default:
865b804a9b8SAntheas Kapenekakis break;
866b804a9b8SAntheas Kapenekakis }
867b804a9b8SAntheas Kapenekakis break;
868b804a9b8SAntheas Kapenekakis case hwmon_pwm:
869b804a9b8SAntheas Kapenekakis switch (attr) {
870b804a9b8SAntheas Kapenekakis case hwmon_pwm_input:
871b804a9b8SAntheas Kapenekakis return oxp_pwm_input_read(val);
8723012bb39SAntheas Kapenekakis case hwmon_pwm_enable:
87336a65fa8SAntheas Kapenekakis ret = oxp_pwm_read(val);
87436a65fa8SAntheas Kapenekakis if (ret)
87536a65fa8SAntheas Kapenekakis return ret;
87636a65fa8SAntheas Kapenekakis
87736a65fa8SAntheas Kapenekakis /* Check for auto and return 2 */
87836a65fa8SAntheas Kapenekakis if (!*val) {
87936a65fa8SAntheas Kapenekakis *val = 2;
88036a65fa8SAntheas Kapenekakis return 0;
88136a65fa8SAntheas Kapenekakis }
88236a65fa8SAntheas Kapenekakis
88336a65fa8SAntheas Kapenekakis /* Return 0 if at full fan speed, 1 otherwise */
88436a65fa8SAntheas Kapenekakis ret = oxp_pwm_fan_speed(val);
88536a65fa8SAntheas Kapenekakis if (ret)
88636a65fa8SAntheas Kapenekakis return ret;
88736a65fa8SAntheas Kapenekakis
88836a65fa8SAntheas Kapenekakis if (*val == 255)
88936a65fa8SAntheas Kapenekakis *val = 0;
89036a65fa8SAntheas Kapenekakis else
89136a65fa8SAntheas Kapenekakis *val = 1;
89236a65fa8SAntheas Kapenekakis
89336a65fa8SAntheas Kapenekakis return 0;
8943012bb39SAntheas Kapenekakis default:
8953012bb39SAntheas Kapenekakis break;
8963012bb39SAntheas Kapenekakis }
8973012bb39SAntheas Kapenekakis break;
8983012bb39SAntheas Kapenekakis default:
8993012bb39SAntheas Kapenekakis break;
9003012bb39SAntheas Kapenekakis }
9013012bb39SAntheas Kapenekakis return -EOPNOTSUPP;
9023012bb39SAntheas Kapenekakis }
9033012bb39SAntheas Kapenekakis
oxp_platform_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)9043012bb39SAntheas Kapenekakis static int oxp_platform_write(struct device *dev, enum hwmon_sensor_types type,
9053012bb39SAntheas Kapenekakis u32 attr, int channel, long val)
9063012bb39SAntheas Kapenekakis {
90736a65fa8SAntheas Kapenekakis int ret;
90836a65fa8SAntheas Kapenekakis
9093012bb39SAntheas Kapenekakis switch (type) {
9103012bb39SAntheas Kapenekakis case hwmon_pwm:
9113012bb39SAntheas Kapenekakis switch (attr) {
9123012bb39SAntheas Kapenekakis case hwmon_pwm_enable:
9133012bb39SAntheas Kapenekakis if (val == 1)
9143012bb39SAntheas Kapenekakis return oxp_pwm_enable();
91536a65fa8SAntheas Kapenekakis else if (val == 2)
9163012bb39SAntheas Kapenekakis return oxp_pwm_disable();
91736a65fa8SAntheas Kapenekakis else if (val != 0)
9183012bb39SAntheas Kapenekakis return -EINVAL;
91936a65fa8SAntheas Kapenekakis
92036a65fa8SAntheas Kapenekakis /* Enable PWM and set to max speed */
92136a65fa8SAntheas Kapenekakis ret = oxp_pwm_enable();
92236a65fa8SAntheas Kapenekakis if (ret)
92336a65fa8SAntheas Kapenekakis return ret;
92436a65fa8SAntheas Kapenekakis return oxp_pwm_input_write(255);
9253012bb39SAntheas Kapenekakis case hwmon_pwm_input:
926b804a9b8SAntheas Kapenekakis return oxp_pwm_input_write(val);
9273012bb39SAntheas Kapenekakis default:
9283012bb39SAntheas Kapenekakis break;
9293012bb39SAntheas Kapenekakis }
9303012bb39SAntheas Kapenekakis break;
9313012bb39SAntheas Kapenekakis default:
9323012bb39SAntheas Kapenekakis break;
9333012bb39SAntheas Kapenekakis }
9343012bb39SAntheas Kapenekakis return -EOPNOTSUPP;
9353012bb39SAntheas Kapenekakis }
9363012bb39SAntheas Kapenekakis
9373012bb39SAntheas Kapenekakis /* Known sensors in the OXP EC controllers */
9383012bb39SAntheas Kapenekakis static const struct hwmon_channel_info * const oxp_platform_sensors[] = {
9393012bb39SAntheas Kapenekakis HWMON_CHANNEL_INFO(fan,
9403012bb39SAntheas Kapenekakis HWMON_F_INPUT),
9413012bb39SAntheas Kapenekakis HWMON_CHANNEL_INFO(pwm,
9423012bb39SAntheas Kapenekakis HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
9433012bb39SAntheas Kapenekakis NULL,
9443012bb39SAntheas Kapenekakis };
9453012bb39SAntheas Kapenekakis
946b72e0b67SAntheas Kapenekakis static struct attribute *oxp_tt_toggle_attrs[] = {
9473012bb39SAntheas Kapenekakis &dev_attr_tt_toggle.attr,
9483012bb39SAntheas Kapenekakis NULL
9493012bb39SAntheas Kapenekakis };
9503012bb39SAntheas Kapenekakis
951b72e0b67SAntheas Kapenekakis static const struct attribute_group oxp_tt_toggle_attribute_group = {
9523012bb39SAntheas Kapenekakis .is_visible = tt_toggle_is_visible,
953b72e0b67SAntheas Kapenekakis .attrs = oxp_tt_toggle_attrs,
9543012bb39SAntheas Kapenekakis };
9553012bb39SAntheas Kapenekakis
95650623acaSAntheas Kapenekakis static struct attribute *oxp_tt_led_attrs[] = {
95750623acaSAntheas Kapenekakis &dev_attr_tt_led.attr,
95850623acaSAntheas Kapenekakis NULL
95950623acaSAntheas Kapenekakis };
96050623acaSAntheas Kapenekakis
96150623acaSAntheas Kapenekakis static const struct attribute_group oxp_tt_led_attribute_group = {
96250623acaSAntheas Kapenekakis .is_visible = tt_led_is_visible,
96350623acaSAntheas Kapenekakis .attrs = oxp_tt_led_attrs,
96450623acaSAntheas Kapenekakis };
96550623acaSAntheas Kapenekakis
9663012bb39SAntheas Kapenekakis static const struct attribute_group *oxp_ec_groups[] = {
967b72e0b67SAntheas Kapenekakis &oxp_tt_toggle_attribute_group,
96850623acaSAntheas Kapenekakis &oxp_tt_led_attribute_group,
9693012bb39SAntheas Kapenekakis NULL
9703012bb39SAntheas Kapenekakis };
9713012bb39SAntheas Kapenekakis
9723012bb39SAntheas Kapenekakis static const struct hwmon_ops oxp_ec_hwmon_ops = {
9733012bb39SAntheas Kapenekakis .is_visible = oxp_ec_hwmon_is_visible,
9743012bb39SAntheas Kapenekakis .read = oxp_platform_read,
9753012bb39SAntheas Kapenekakis .write = oxp_platform_write,
9763012bb39SAntheas Kapenekakis };
9773012bb39SAntheas Kapenekakis
9783012bb39SAntheas Kapenekakis static const struct hwmon_chip_info oxp_ec_chip_info = {
9793012bb39SAntheas Kapenekakis .ops = &oxp_ec_hwmon_ops,
9803012bb39SAntheas Kapenekakis .info = oxp_platform_sensors,
9813012bb39SAntheas Kapenekakis };
9823012bb39SAntheas Kapenekakis
9833012bb39SAntheas Kapenekakis /* Initialization logic */
oxp_platform_probe(struct platform_device * pdev)9843012bb39SAntheas Kapenekakis static int oxp_platform_probe(struct platform_device *pdev)
9853012bb39SAntheas Kapenekakis {
9863012bb39SAntheas Kapenekakis struct device *dev = &pdev->dev;
9873012bb39SAntheas Kapenekakis struct device *hwdev;
9889230b3b8SAntheas Kapenekakis int ret;
9893012bb39SAntheas Kapenekakis
9909230b3b8SAntheas Kapenekakis oxp_dev = dev;
99136a65fa8SAntheas Kapenekakis hwdev = devm_hwmon_device_register_with_info(dev, "oxp_ec", NULL,
9923012bb39SAntheas Kapenekakis &oxp_ec_chip_info, NULL);
9933012bb39SAntheas Kapenekakis
9949230b3b8SAntheas Kapenekakis if (IS_ERR(hwdev))
9959230b3b8SAntheas Kapenekakis return PTR_ERR(hwdev);
9969230b3b8SAntheas Kapenekakis
9979230b3b8SAntheas Kapenekakis if (oxp_psy_ext_supported()) {
9989230b3b8SAntheas Kapenekakis ret = devm_battery_hook_register(dev, &battery_hook);
9999230b3b8SAntheas Kapenekakis if (ret)
10009230b3b8SAntheas Kapenekakis return ret;
10019230b3b8SAntheas Kapenekakis }
10029230b3b8SAntheas Kapenekakis
10039230b3b8SAntheas Kapenekakis return 0;
10043012bb39SAntheas Kapenekakis }
10053012bb39SAntheas Kapenekakis
10063012bb39SAntheas Kapenekakis static struct platform_driver oxp_platform_driver = {
10073012bb39SAntheas Kapenekakis .driver = {
10083012bb39SAntheas Kapenekakis .name = "oxp-platform",
10093012bb39SAntheas Kapenekakis .dev_groups = oxp_ec_groups,
10103012bb39SAntheas Kapenekakis },
10113012bb39SAntheas Kapenekakis .probe = oxp_platform_probe,
10123012bb39SAntheas Kapenekakis };
10133012bb39SAntheas Kapenekakis
10143012bb39SAntheas Kapenekakis static struct platform_device *oxp_platform_device;
10153012bb39SAntheas Kapenekakis
oxp_platform_init(void)10163012bb39SAntheas Kapenekakis static int __init oxp_platform_init(void)
10173012bb39SAntheas Kapenekakis {
10183012bb39SAntheas Kapenekakis const struct dmi_system_id *dmi_entry;
10193012bb39SAntheas Kapenekakis
10203012bb39SAntheas Kapenekakis dmi_entry = dmi_first_match(dmi_table);
10213012bb39SAntheas Kapenekakis if (!dmi_entry)
10223012bb39SAntheas Kapenekakis return -ENODEV;
10233012bb39SAntheas Kapenekakis
10243012bb39SAntheas Kapenekakis board = (enum oxp_board)(unsigned long)dmi_entry->driver_data;
10253012bb39SAntheas Kapenekakis
10263012bb39SAntheas Kapenekakis /*
10273012bb39SAntheas Kapenekakis * Have to check for AMD processor here because DMI strings are the same
10283012bb39SAntheas Kapenekakis * between Intel and AMD boards on older OneXPlayer devices, the only way
10293012bb39SAntheas Kapenekakis * to tell them apart is the CPU. Old Intel boards have an unsupported EC.
10303012bb39SAntheas Kapenekakis */
10313012bb39SAntheas Kapenekakis if (board == oxp_mini_amd && boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
10323012bb39SAntheas Kapenekakis return -ENODEV;
10333012bb39SAntheas Kapenekakis
10343012bb39SAntheas Kapenekakis oxp_platform_device =
10353012bb39SAntheas Kapenekakis platform_create_bundle(&oxp_platform_driver,
10363012bb39SAntheas Kapenekakis oxp_platform_probe, NULL, 0, NULL, 0);
10373012bb39SAntheas Kapenekakis
10383012bb39SAntheas Kapenekakis return PTR_ERR_OR_ZERO(oxp_platform_device);
10393012bb39SAntheas Kapenekakis }
10403012bb39SAntheas Kapenekakis
oxp_platform_exit(void)10413012bb39SAntheas Kapenekakis static void __exit oxp_platform_exit(void)
10423012bb39SAntheas Kapenekakis {
10433012bb39SAntheas Kapenekakis platform_device_unregister(oxp_platform_device);
10443012bb39SAntheas Kapenekakis platform_driver_unregister(&oxp_platform_driver);
10453012bb39SAntheas Kapenekakis }
10463012bb39SAntheas Kapenekakis
10473012bb39SAntheas Kapenekakis MODULE_DEVICE_TABLE(dmi, dmi_table);
10483012bb39SAntheas Kapenekakis
10493012bb39SAntheas Kapenekakis module_init(oxp_platform_init);
10503012bb39SAntheas Kapenekakis module_exit(oxp_platform_exit);
10513012bb39SAntheas Kapenekakis
10523012bb39SAntheas Kapenekakis MODULE_AUTHOR("Joaquín Ignacio Aramendía <samsagax@gmail.com>");
10533012bb39SAntheas Kapenekakis MODULE_DESCRIPTION("Platform driver that handles EC sensors of OneXPlayer devices");
10543012bb39SAntheas Kapenekakis MODULE_LICENSE("GPL");
1055