diff --git a/drivers/hid/hid-oxp.c b/drivers/hid/hid-oxp.c index 20a54f337220d..b7427ebf6d1d2 100644 --- a/drivers/hid/hid-oxp.c +++ b/drivers/hid/hid-oxp.c @@ -1386,7 +1386,7 @@ static struct mc_subled oxp_rgb_subled_info[] = { static struct led_classdev_mc oxp_cdev_rgb = { .led_cdev = { - .name = "oxp:rgb:joystick_rings", + .name = "go:rgb:joystick_rings", .color = LED_COLOR_ID_RGB, .brightness = 0x64, .max_brightness = 0x64, diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b54b5212b2047..960b2ae6d94d1 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1056,6 +1056,8 @@ config OXP_EC depends on ACPI_BATTERY depends on HWMON depends on X86 + depends on INPUT + depends on USB help Enables support for the platform EC of OneXPlayer and AOKZOE handheld devices. This includes fan speed, fan controls, and diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c index 99c0dfcf393b7..b4e28ddccc7b4 100644 --- a/drivers/platform/x86/oxpec.c +++ b/drivers/platform/x86/oxpec.c @@ -18,10 +18,12 @@ #include #include #include +#include #include #include #include #include +#include #include /* Handle ACPI lock mechanism */ @@ -43,6 +45,7 @@ enum oxp_board { aok_zoe_a1 = 1, orange_pi_neo, oxp_2, + oxp_3, oxp_fly, oxp_mini_amd, oxp_mini_amd_a07, @@ -50,10 +53,13 @@ enum oxp_board { oxp_x1, oxp_g1_i, oxp_g1_a, + oxp_super_x, }; static enum oxp_board board; static struct device *oxp_dev; +static struct input_dev *oxp_tablet_mode_input; +static struct notifier_block oxp_usb_notifier; /* Fan reading and PWM */ #define OXP_SENSOR_FAN_REG 0x76 /* Fan reading is 2 registers long */ @@ -149,6 +155,13 @@ static const struct dmi_system_id dmi_table[] = { }, .driver_data = (void *)oxp_2, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER 3"), + }, + .driver_data = (void *)oxp_3, + }, { .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), @@ -210,7 +223,7 @@ static const struct dmi_system_id dmi_table[] = { DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER SUPER X"), }, - .driver_data = (void *)oxp_g1_a, + .driver_data = (void *)oxp_super_x, }, { .matches = { @@ -289,9 +302,84 @@ static const struct dmi_system_id dmi_table[] = { }, .driver_data = (void *)oxp_x1, }, + { + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X2Mini PRO"), + }, + .driver_data = (void *)oxp_fly, + }, {}, }; +#define OXP_KEYBOARD_VID_QINHENG 0x1a86 +#define OXP_KEYBOARD_PID_K2445 0x1305 +#define OXP_KEYBOARD_VID_HAILUCK 0x258a +#define OXP_KEYBOARD_PID_HAILUCK 0x001e + +static int oxp_find_keyboard(struct usb_device *udev, void *data) +{ + bool *keyboard_attached = data; + u16 vid = le16_to_cpu(udev->descriptor.idVendor); + u16 pid = le16_to_cpu(udev->descriptor.idProduct); + + switch (board) { + case oxp_x1: + if (vid == OXP_KEYBOARD_VID_HAILUCK && + pid == OXP_KEYBOARD_PID_HAILUCK) + *keyboard_attached = true; + break; + case oxp_super_x: + if (vid == OXP_KEYBOARD_VID_QINHENG && + pid == OXP_KEYBOARD_PID_K2445) + *keyboard_attached = true; + break; + default: + break; + } + + return 0; +} + +static int oxp_usb_notify(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct usb_device *udev = data; + u16 vid = le16_to_cpu(udev->descriptor.idVendor); + u16 pid = le16_to_cpu(udev->descriptor.idProduct); + bool keyboard = false; + + switch (board) { + case oxp_x1: + keyboard = vid == OXP_KEYBOARD_VID_HAILUCK && + pid == OXP_KEYBOARD_PID_HAILUCK; + break; + case oxp_super_x: + keyboard = vid == OXP_KEYBOARD_VID_QINHENG && + pid == OXP_KEYBOARD_PID_K2445; + break; + default: + break; + } + + if (!keyboard) + return NOTIFY_DONE; + + switch (action) { + case USB_DEVICE_ADD: + input_report_switch(oxp_tablet_mode_input, SW_TABLET_MODE, false); + break; + case USB_DEVICE_REMOVE: + input_report_switch(oxp_tablet_mode_input, SW_TABLET_MODE, true); + break; + default: + return NOTIFY_DONE; + } + + input_sync(oxp_tablet_mode_input); + return NOTIFY_OK; +} + /* Helper functions to handle EC read/write */ static int read_from_ec(u8 reg, int size, long *val) { @@ -345,6 +433,7 @@ static umode_t tt_toggle_is_visible(struct kobject *kobj, case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_super_x: return attr->mode; default: break; @@ -374,6 +463,7 @@ static ssize_t tt_toggle_store(struct device *dev, case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_super_x: reg = OXP_TURBO_SWITCH_REG; mask = OXP_TURBO_TAKE_VAL; break; @@ -420,6 +510,7 @@ static ssize_t tt_toggle_show(struct device *dev, case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_super_x: reg = OXP_TURBO_SWITCH_REG; mask = OXP_TURBO_TAKE_VAL; break; @@ -516,6 +607,7 @@ static bool oxp_psy_ext_supported(void) case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_super_x: case oxp_fly: return true; default: @@ -649,6 +741,7 @@ static int oxp_pwm_enable(void) case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_super_x: return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_MANUAL); default: return -EINVAL; @@ -669,6 +762,7 @@ static int oxp_pwm_disable(void) case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_super_x: return write_to_ec(OXP_SENSOR_PWM_ENABLE_REG, PWM_MODE_AUTO); default: return -EINVAL; @@ -689,6 +783,7 @@ static int oxp_pwm_read(long *val) case oxp_x1: case oxp_g1_i: case oxp_g1_a: + case oxp_super_x: return read_from_ec(OXP_SENSOR_PWM_ENABLE_REG, 1, val); default: return -EOPNOTSUPP; @@ -703,6 +798,8 @@ static umode_t oxp_ec_hwmon_is_visible(const void *drvdata, case hwmon_fan: return 0444; case hwmon_pwm: + if (board == oxp_3) + return 0; return 0644; default: return 0; @@ -716,6 +813,7 @@ static int oxp_pwm_fan_speed(long *val) case orange_pi_neo: return read_from_ec(ORANGEPI_SENSOR_FAN_REG, 2, val); case oxp_2: + case oxp_3: case oxp_x1: case oxp_g1_i: return read_from_ec(OXP_2_SENSOR_FAN_REG, 2, val); @@ -725,6 +823,7 @@ static int oxp_pwm_fan_speed(long *val) case oxp_mini_amd_a07: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_super_x: return read_from_ec(OXP_SENSOR_FAN_REG, 2, val); default: return -EOPNOTSUPP; @@ -757,6 +856,7 @@ static int oxp_pwm_input_write(long val) case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_super_x: return write_to_ec(OXP_SENSOR_PWM_REG, val); default: return -EOPNOTSUPP; @@ -796,6 +896,7 @@ static int oxp_pwm_input_read(long *val) case oxp_fly: case oxp_mini_amd_pro: case oxp_g1_a: + case oxp_super_x: default: ret = read_from_ec(OXP_SENSOR_PWM_REG, 1, val); if (ret) @@ -937,6 +1038,7 @@ static const struct hwmon_chip_info oxp_ec_chip_info = { /* Initialization logic */ static int oxp_platform_probe(struct platform_device *pdev) { + bool keyboard_attached = false; struct device *dev = &pdev->dev; struct device *hwdev; int ret; @@ -954,6 +1056,33 @@ static int oxp_platform_probe(struct platform_device *pdev) return ret; } + switch (board) { + case oxp_x1: + case oxp_super_x: + oxp_tablet_mode_input = devm_input_allocate_device(dev); + if (!oxp_tablet_mode_input) + return -ENOMEM; + + oxp_tablet_mode_input->name = "OneXPlayer Tablet Mode Switch"; + oxp_tablet_mode_input->phys = "oxp-platform/input0"; + oxp_tablet_mode_input->id.bustype = BUS_HOST; + input_set_capability(oxp_tablet_mode_input, EV_SW, SW_TABLET_MODE); + + ret = input_register_device(oxp_tablet_mode_input); + if (ret) + return ret; + + oxp_usb_notifier.notifier_call = oxp_usb_notify; + usb_register_notify(&oxp_usb_notifier); + usb_for_each_dev(&keyboard_attached, oxp_find_keyboard); + input_report_switch(oxp_tablet_mode_input, SW_TABLET_MODE, + !keyboard_attached); + input_sync(oxp_tablet_mode_input); + break; + default: + break; + } + return 0; } @@ -994,6 +1123,9 @@ static int __init oxp_platform_init(void) static void __exit oxp_platform_exit(void) { + if (board == oxp_x1 || board == oxp_super_x) + usb_unregister_notify(&oxp_usb_notifier); + platform_device_unregister(oxp_platform_device); platform_driver_unregister(&oxp_platform_driver); }