From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Fri, 19 May 2023 17:45:47 +0200 Subject: [PATCH] asus_linux Signed-off-by: Jan200101 --- drivers/acpi/resource.c | 14 ++ drivers/hid/amd-sfh-hid/amd_sfh_client.c | 2 + drivers/hid/amd-sfh-hid/amd_sfh_hid.h | 2 +- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 4 + drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 1 + .../hid_descriptor/amd_sfh_hid_desc.c | 27 ++++ .../hid_descriptor/amd_sfh_hid_desc.h | 7 + .../hid_descriptor/amd_sfh_hid_report_desc.h | 21 +++ drivers/hid/hid-asus.c | 42 +++--- drivers/hid/hid-ids.h | 1 + drivers/platform/x86/asus-wmi.c | 131 ++++++++++++++++++ drivers/platform/x86/asus-wmi.h | 1 + include/linux/platform_data/x86/asus-wmi.h | 4 + 14 files changed, 250 insertions(+), 27 deletions(-) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index e8492b3a393a..01a7befe9625 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -467,6 +467,20 @@ static const struct dmi_system_id asus_laptop[] = { DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"), }, }, + { + .ident = "Asus TUF Gaming A15 FA507NV", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "FA507NV"), + }, + }, + { + .ident = "ASUS TUF Gaming A16 FA617NS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "FA617NS"), + }, + }, { } }; diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index c751d12f5df8..690be680e392 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -146,6 +146,8 @@ static const char *get_sensor_name(int idx) return "gyroscope"; case mag_idx: return "magnetometer"; + case tms_idx: + return "tablet-mode-switch"; case als_idx: return "ALS"; case HPD_IDX: diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h index 528036892c9d..97296f587bc7 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h @@ -11,7 +11,7 @@ #ifndef AMDSFH_HID_H #define AMDSFH_HID_H -#define MAX_HID_DEVICES 5 +#define MAX_HID_DEVICES 6 #define AMD_SFH_HID_VENDOR 0x1022 #define AMD_SFH_HID_PRODUCT 0x0001 diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index c936d6a51c0c..c33f3f202ff7 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -27,6 +27,7 @@ #define ACEL_EN BIT(0) #define GYRO_EN BIT(1) #define MAGNO_EN BIT(2) +#define TMS_EN BIT(15) #define HPD_EN BIT(16) #define ALS_EN BIT(19) @@ -227,6 +228,9 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id) if (MAGNO_EN & activestatus) sensor_id[num_of_sensors++] = mag_idx; + if (TMS_EN & activestatus) + sensor_id[num_of_sensors++] = tms_idx; + if (ALS_EN & activestatus) sensor_id[num_of_sensors++] = als_idx; diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h index dfb7cabd82ef..e18ceee9e5db 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -78,6 +78,7 @@ enum sensor_idx { accel_idx = 0, gyro_idx = 1, mag_idx = 2, + tms_idx = 15, als_idx = 19 }; diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c index f9a8c02d5a7b..181973f35f05 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c @@ -47,6 +47,11 @@ static int get_report_descriptor(int sensor_idx, u8 *rep_desc) memcpy(rep_desc, comp3_report_descriptor, sizeof(comp3_report_descriptor)); break; + case tms_idx: /* tablet mode switch */ + memset(rep_desc, 0, sizeof(tms_report_descriptor)); + memcpy(rep_desc, tms_report_descriptor, + sizeof(tms_report_descriptor)); + break; case als_idx: /* ambient light sensor */ memset(rep_desc, 0, sizeof(als_report_descriptor)); memcpy(rep_desc, als_report_descriptor, @@ -96,6 +101,16 @@ static u32 get_descr_sz(int sensor_idx, int descriptor_name) return sizeof(struct magno_feature_report); } break; + case tms_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(tms_report_descriptor); + case input_size: + return sizeof(struct tms_input_report); + case feature_size: + return sizeof(struct tms_feature_report); + } + break; case als_idx: switch (descriptor_name) { case descr_size: @@ -138,6 +153,7 @@ static u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) struct accel3_feature_report acc_feature; struct gyro_feature_report gyro_feature; struct magno_feature_report magno_feature; + struct tms_feature_report tms_feature; struct hpd_feature_report hpd_feature; struct als_feature_report als_feature; u8 report_size = 0; @@ -173,6 +189,11 @@ static u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) memcpy(feature_report, &magno_feature, sizeof(magno_feature)); report_size = sizeof(magno_feature); break; + case tms_idx: /* tablet mode switch */ + get_common_features(&tms_feature.common_property, report_id); + memcpy(feature_report, &tms_feature, sizeof(tms_feature)); + report_size = sizeof(tms_feature); + break; case als_idx: /* ambient light sensor */ get_common_features(&als_feature.common_property, report_id); als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY; @@ -211,6 +232,7 @@ static u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct accel3_input_report acc_input; struct gyro_input_report gyro_input; struct hpd_input_report hpd_input; + struct tms_input_report tms_input; struct als_input_report als_input; struct hpd_status hpdstatus; u8 report_size = 0; @@ -244,6 +266,11 @@ static u8 get_input_report(u8 current_index, int sensor_idx, int report_id, memcpy(input_report, &magno_input, sizeof(magno_input)); report_size = sizeof(magno_input); break; + case tms_idx: /* tablet mode switch */ + get_common_inputs(&tms_input.common_property, report_id); + report_size = sizeof(tms_input); + memcpy(input_report, &tms_input, sizeof(tms_input)); + break; case als_idx: /* Als */ get_common_inputs(&als_input.common_property, report_id); /* For ALS ,V2 Platforms uses C2P_MSG5 register instead of DRAM access method */ diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h index ebd55675eb62..b22068a47429 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h @@ -111,4 +111,11 @@ struct hpd_input_report { u8 human_presence; } __packed; +struct tms_feature_report { + struct common_feature_property common_property; +} __packed; + +struct tms_input_report { + struct common_input_property common_property; +} __packed; #endif diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h index 697f2791ea9c..96cbc1e5b9a7 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h @@ -644,6 +644,27 @@ static const u8 als_report_descriptor[] = { 0xC0 /* HID end collection */ }; + +/* TABLET MODE SWITCH */ +__maybe_unused // Used by sfh1.0, but not yet implemented in sfh1.1 +static const u8 tms_report_descriptor[] = { +0x06, 0x43, 0xFF, // Usage Page (Vendor Defined 0xFF43) +0x0A, 0x02, 0x02, // Usage (0x0202) +0xA1, 0x01, // Collection (Application) +0x85, 0x11, // Report ID (17) +0x15, 0x00, // Logical Minimum (0) +0x25, 0x01, // Logical Maximum (1) +0x35, 0x00, // Physical Minimum (0) +0x45, 0x01, // Physical Maximum (1) +0x65, 0x00, // Unit (None) +0x55, 0x00, // Unit Exponent (0) +0x75, 0x01, // Report Size (1) +0x95, 0x98, // Report Count (-104) +0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) +0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) +0xC1, 0x00, // End Collection +}; + /* BIOMETRIC PRESENCE*/ static const u8 hpd_report_descriptor[] = { 0x05, 0x20, /* Usage page */ diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index d1094bb1aa42..2bc14e076739 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -883,33 +883,20 @@ static int asus_input_mapping(struct hid_device *hdev, case 0xb5: asus_map_key_clear(KEY_CALC); break; case 0xc4: asus_map_key_clear(KEY_KBDILLUMUP); break; case 0xc5: asus_map_key_clear(KEY_KBDILLUMDOWN); break; + case 0xc7: asus_map_key_clear(KEY_KBDILLUMTOGGLE); break; - /* ASUS touchpad toggle */ - case 0x6b: asus_map_key_clear(KEY_F21); break; + case 0x6b: asus_map_key_clear(KEY_F21); break; /* ASUS touchpad toggle */ + case 0x38: asus_map_key_clear(KEY_PROG1); break; /* ROG key */ + case 0xba: asus_map_key_clear(KEY_PROG2); break; /* Fn+C ASUS Splendid */ + case 0x5c: asus_map_key_clear(KEY_PROG3); break; /* Fn+Space Power4Gear */ + case 0x99: asus_map_key_clear(KEY_PROG4); break; /* Fn+F5 "fan" symbol */ + case 0xae: asus_map_key_clear(KEY_PROG4); break; /* Fn+F5 "fan" symbol */ + case 0x92: asus_map_key_clear(KEY_CALC); break; /* Fn+Ret "Calc" symbol */ + case 0xb2: asus_map_key_clear(KEY_PROG2); break; /* Fn+Left previous aura */ + case 0xb3: asus_map_key_clear(KEY_PROG3); break; /* Fn+Left next aura */ + case 0x6a: asus_map_key_clear(KEY_F13); break; /* Screenpad toggle */ + case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle */ - /* ROG key */ - case 0x38: asus_map_key_clear(KEY_PROG1); break; - - /* Fn+C ASUS Splendid */ - case 0xba: asus_map_key_clear(KEY_PROG2); break; - - /* Fn+Space Power4Gear Hybrid */ - case 0x5c: asus_map_key_clear(KEY_PROG3); break; - - /* Fn+F5 "fan" symbol on FX503VD */ - case 0x99: asus_map_key_clear(KEY_PROG4); break; - - /* Fn+F5 "fan" symbol on N-Key keyboard */ - case 0xae: asus_map_key_clear(KEY_PROG4); break; - - /* Fn+Ret "Calc" symbol on N-Key keyboard */ - case 0x92: asus_map_key_clear(KEY_CALC); break; - - /* Fn+Left Aura mode previous on N-Key keyboard */ - case 0xb2: asus_map_key_clear(KEY_PROG2); break; - - /* Fn+Right Aura mode next on N-Key keyboard */ - case 0xb3: asus_map_key_clear(KEY_PROG3); break; default: /* ASUS lazily declares 256 usages, ignore the rest, @@ -1267,6 +1254,9 @@ static const struct hid_device_id asus_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), QUIRK_ROG_CLAYMORE_II_KEYBOARD }, @@ -1309,4 +1299,4 @@ static struct hid_driver asus_driver = { }; module_hid_driver(asus_driver); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c2e9b6d1fd7d..513290a2e91c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -207,6 +207,7 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 +#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3 0x1a30 #define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 1038dfdcdd32..14a32e08f900 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -200,6 +201,7 @@ struct asus_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; + struct backlight_device *screenpad_backlight_device; struct platform_device *platform_device; struct led_classdev wlan_led; @@ -3208,6 +3210,127 @@ static int is_display_toggle(int code) return 0; } +/* Screenpad backlight *******************************************************/ + +static int read_screenpad_backlight_power(struct asus_wmi *asus) +{ + int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + + if (ret < 0) + return ret; + /* 1 == powered */ + return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; +} + +static int read_screenpad_brightness(struct backlight_device *bd) +{ + struct asus_wmi *asus = bl_get_data(bd); + u32 retval; + int err; + + err = read_screenpad_backlight_power(asus); + if (err < 0) + return err; + /* The device brightness can only be read if powered, so return stored */ + if (err == FB_BLANK_POWERDOWN) + return asus->driver->screenpad_brightness; + + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); + if (err < 0) + return err; + + return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; +} + +static int update_screenpad_bl_status(struct backlight_device *bd) +{ + struct asus_wmi *asus = bl_get_data(bd); + int power, err = 0; + u32 ctrl_param; + + power = read_screenpad_backlight_power(asus); + if (power == -ENODEV) + return err; + else if (power < 0) + return power; + + if (bd->props.power != power) { + if (power != FB_BLANK_UNBLANK) { + /* Only brightness > 0 can power it back on */ + ctrl_param = max(1, asus->driver->screenpad_brightness); + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, + ctrl_param, NULL); + } else { + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL); + } + } else if (power == FB_BLANK_UNBLANK) { + /* Only set brightness if powered on or we get invalid/unsync state */ + ctrl_param = bd->props.brightness; + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); + } + + /* Ensure brightness is stored to turn back on with */ + asus->driver->screenpad_brightness = bd->props.brightness; + + return err; +} + +static const struct backlight_ops asus_screenpad_bl_ops = { + .get_brightness = read_screenpad_brightness, + .update_status = update_screenpad_bl_status, + .options = BL_CORE_SUSPENDRESUME, +}; + +static int asus_screenpad_init(struct asus_wmi *asus) +{ + struct backlight_device *bd; + struct backlight_properties props; + int power, brightness; + + power = read_screenpad_backlight_power(asus); + if (power == -ENODEV) + power = FB_BLANK_UNBLANK; + else if (power < 0) + return power; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ + props.max_brightness = 255; + bd = backlight_device_register("asus_screenpad", + &asus->platform_device->dev, asus, + &asus_screenpad_bl_ops, &props); + if (IS_ERR(bd)) { + pr_err("Could not register backlight device\n"); + return PTR_ERR(bd); + } + + asus->screenpad_backlight_device = bd; + + brightness = read_screenpad_brightness(bd); + if (brightness < 0) + return brightness; + /* + * Counter an odd behaviour where default is set to < 13 if it was 0 on boot. + * 60 is subjective, but accepted as a good compromise to retain visibility. + */ + if (brightness < 60) + brightness = 60; + + asus->driver->screenpad_brightness = brightness; + bd->props.brightness = brightness; + bd->props.power = power; + backlight_update_status(bd); + + return 0; +} + +static void asus_screenpad_exit(struct asus_wmi *asus) +{ + backlight_device_unregister(asus->screenpad_backlight_device); + + asus->screenpad_backlight_device = NULL; +} + /* Fn-lock ********************************************************************/ static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus) @@ -3823,6 +3946,13 @@ static int asus_wmi_add(struct platform_device *pdev) } else if (asus->driver->quirks->wmi_backlight_set_devstate) err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL); + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT)) { + pr_warn("Begin asus_screenpad_init"); + err = asus_screenpad_init(asus); + if (err && err != -ENODEV) + goto fail_backlight; + } + if (asus_wmi_has_fnlock_key(asus)) { asus->fnlock_locked = fnlock_default; asus_wmi_fnlock_update(asus); @@ -3844,6 +3974,7 @@ static int asus_wmi_add(struct platform_device *pdev) fail_wmi_handler: asus_wmi_backlight_exit(asus); + asus_screenpad_exit(asus); fail_backlight: asus_wmi_rfkill_exit(asus); fail_rfkill: diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index a478ebfd34df..5fbdd0eafa02 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -57,6 +57,7 @@ struct quirk_entry { struct asus_wmi_driver { int brightness; int panel_power; + int screenpad_brightness; int wlan_ctrl_by_user; const char *name; diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 28234dc9fa6a..a2d94adb5c80 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -58,6 +58,10 @@ #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 #define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */ #define ASUS_WMI_DEVID_LIGHTBAR 0x00050025 +/* This can only be used to disable the screen, not re-enable */ +#define ASUS_WMI_DEVID_SCREENPAD_POWER 0x00050031 +/* Writing a brightness re-enables the screen if disabled */ +#define ASUS_WMI_DEVID_SCREENPAD_LIGHT 0x00050032 #define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018 #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075