diff options
Diffstat (limited to 'SOURCES/asus-linux.patch')
-rw-r--r-- | SOURCES/asus-linux.patch | 1839 |
1 files changed, 1515 insertions, 324 deletions
diff --git a/SOURCES/asus-linux.patch b/SOURCES/asus-linux.patch index 11e3e80..ed6254a 100644 --- a/SOURCES/asus-linux.patch +++ b/SOURCES/asus-linux.patch @@ -1,312 +1,1342 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Jan200101 <sentrycraft123@gmail.com> -Date: Fri, 19 May 2023 17:45:47 +0200 -Subject: [PATCH] asus_linux +From 5195a8ad57e5076ce520f725a49f595fe617b6d2 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Sun, 4 Jun 2023 18:48:11 +1200 +Subject: [PATCH v2 1/8] platform/x86: asus-wmi: add support for showing + charger mode -Signed-off-by: Jan200101 <sentrycraft123@gmail.com> +Expose a WMI method in sysfs platform for showing which connected +charger the laptop is currently using. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> --- - 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"), -+ }, -+ }, - { } - }; + .../ABI/testing/sysfs-platform-asus-wmi | 10 +++++++++ + drivers/platform/x86/asus-wmi.c | 21 +++++++++++++++++++ + include/linux/platform_data/x86/asus-wmi.h | 3 +++ + 3 files changed, 34 insertions(+) + +diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi +index a77a004a1baa..eb29e3023c7b 100644 +--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi ++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi +@@ -98,3 +98,13 @@ Description: + Enable an LCD response-time boost to reduce or remove ghosting: + * 0 - Disable, + * 1 - Enable ++ ++What: /sys/devices/platform/<platform>/charge_mode ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Get the current charging mode being used: ++ * 1 - Barrel connected charger, ++ * 2 - USB-C charging ++ * 3 - Both connected, barrel used for charging +\ No newline at end of file +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 1038dfdcdd32..f23375d5fb82 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -237,6 +237,7 @@ struct asus_wmi { + u8 fan_boost_mode_mask; + u8 fan_boost_mode; -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 - }; ++ bool charge_mode_available; + bool egpu_enable_available; + bool dgpu_disable_available; + bool gpu_mux_mode_available; +@@ -586,6 +587,22 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus) + asus_wmi_tablet_sw_report(asus, result); + } -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); ++/* Charging mode, 1=Barrel, 2=USB ******************************************/ ++static ssize_t charge_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ int result, value; ++ ++ result = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CHARGE_MODE, &value); ++ if (result < 0) ++ return result; ++ ++ return sysfs_emit(buf, "%d\n", value & 0xff); ++} ++ ++static DEVICE_ATTR_RO(charge_mode); ++ + /* dGPU ********************************************************************/ + static ssize_t dgpu_disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -3462,6 +3479,7 @@ static struct attribute *platform_attributes[] = { + &dev_attr_camera.attr, + &dev_attr_cardr.attr, + &dev_attr_touchpad.attr, ++ &dev_attr_charge_mode.attr, + &dev_attr_egpu_enable.attr, + &dev_attr_dgpu_disable.attr, + &dev_attr_gpu_mux_mode.attr, +@@ -3491,6 +3509,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, + devid = ASUS_WMI_DEVID_LID_RESUME; + else if (attr == &dev_attr_als_enable.attr) + devid = ASUS_WMI_DEVID_ALS_ENABLE; ++ else if (attr == &dev_attr_charge_mode.attr) ++ ok = asus->charge_mode_available; + else if (attr == &dev_attr_egpu_enable.attr) + ok = asus->egpu_enable_available; + else if (attr == &dev_attr_dgpu_disable.attr) +@@ -3757,6 +3777,7 @@ static int asus_wmi_add(struct platform_device *pdev) + if (err) + goto fail_platform; + ++ asus->charge_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CHARGE_MODE); + asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); + asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); + asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX); +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 28234dc9fa6a..f90cafe26af1 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -95,6 +95,9 @@ + /* Keyboard dock */ + #define ASUS_WMI_DEVID_KBD_DOCK 0x00120063 + ++/* Charging mode - 1=Barrel, 2=USB */ ++#define ASUS_WMI_DEVID_CHARGE_MODE 0x0012006C ++ + /* dgpu on/off */ + #define ASUS_WMI_DEVID_EGPU 0x00090019 + +-- +2.41.0 + +From dcc493d84f202bbdf97eb48660179724f744c76d Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Sun, 4 Jun 2023 19:07:31 +1200 +Subject: [PATCH v2 2/8] platform/x86: asus-wmi: add support for showing middle + fan RPM + +Some newer ASUS ROG laptops now have a middle/center fan in addition +to the CPU and GPU fans. This new fan typically blows across the +heatpipes and VRMs betweent eh CPU and GPU. + +This commit exposes that fan to PWM control plus showing RPM. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + drivers/platform/x86/asus-wmi.c | 91 ++++++++++++++++++++++ + include/linux/platform_data/x86/asus-wmi.h | 1 + + 2 files changed, 92 insertions(+) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index f23375d5fb82..375d25ae0aca 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -72,6 +72,7 @@ module_param(fnlock_default, bool, 0444); + + #define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0) + ++#define ASUS_MID_FAN_DESC "mid_fan" + #define ASUS_GPU_FAN_DESC "gpu_fan" + #define ASUS_FAN_DESC "cpu_fan" + #define ASUS_FAN_MFUN 0x13 +@@ -229,8 +230,10 @@ struct asus_wmi { + + enum fan_type fan_type; + enum fan_type gpu_fan_type; ++ enum fan_type mid_fan_type; + int fan_pwm_mode; + int gpu_fan_pwm_mode; ++ int mid_fan_pwm_mode; + int agfn_pwm; + + bool fan_boost_mode_available; +@@ -2129,6 +2132,31 @@ static ssize_t fan2_label_show(struct device *dev, + return sysfs_emit(buf, "%s\n", ASUS_GPU_FAN_DESC); + } + ++/* Middle/Center fan on modern ROG laptops */ ++static ssize_t fan3_input_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ int value; ++ int ret; ++ ++ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_MID_FAN_CTRL, &value); ++ if (ret < 0) ++ return ret; ++ ++ value &= 0xffff; ++ ++ return sysfs_emit(buf, "%d\n", value * 100); ++} ++ ++static ssize_t fan3_label_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ return sysfs_emit(buf, "%s\n", ASUS_MID_FAN_DESC); ++} ++ + static ssize_t pwm2_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +@@ -2175,6 +2203,52 @@ static ssize_t pwm2_enable_store(struct device *dev, + return count; + } + ++static ssize_t pwm3_enable_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ return sysfs_emit(buf, "%d\n", asus->mid_fan_pwm_mode); ++} ++ ++static ssize_t pwm3_enable_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ int state; ++ int value; ++ int ret; ++ u32 retval; ++ ++ ret = kstrtouint(buf, 10, &state); ++ if (ret) ++ return ret; ++ ++ switch (state) { /* standard documented hwmon values */ ++ case ASUS_FAN_CTRL_FULLSPEED: ++ value = 1; + 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)); ++ case ASUS_FAN_CTRL_AUTO: ++ value = 0; + 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 */ - }; ++ default: ++ return -EINVAL; ++ } ++ ++ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_MID_FAN_CTRL, ++ value, &retval); ++ if (ret) ++ return ret; ++ ++ if (retval != 1) ++ return -EIO; ++ ++ asus->mid_fan_pwm_mode = state; ++ return count; ++} ++ + /* Fan1 */ + static DEVICE_ATTR_RW(pwm1); + static DEVICE_ATTR_RW(pwm1_enable); +@@ -2184,6 +2258,10 @@ static DEVICE_ATTR_RO(fan1_label); + static DEVICE_ATTR_RW(pwm2_enable); + static DEVICE_ATTR_RO(fan2_input); + static DEVICE_ATTR_RO(fan2_label); ++/* Fan3 - Middle/center fan */ ++static DEVICE_ATTR_RW(pwm3_enable); ++static DEVICE_ATTR_RO(fan3_input); ++static DEVICE_ATTR_RO(fan3_label); + + /* Temperature */ + static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL); +@@ -2192,10 +2270,13 @@ static struct attribute *hwmon_attributes[] = { + &dev_attr_pwm1.attr, + &dev_attr_pwm1_enable.attr, + &dev_attr_pwm2_enable.attr, ++ &dev_attr_pwm3_enable.attr, + &dev_attr_fan1_input.attr, + &dev_attr_fan1_label.attr, + &dev_attr_fan2_input.attr, + &dev_attr_fan2_label.attr, ++ &dev_attr_fan3_input.attr, ++ &dev_attr_fan3_label.attr, + + &dev_attr_temp1_input.attr, + NULL +@@ -2221,6 +2302,11 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, + || attr == &dev_attr_pwm2_enable.attr) { + if (asus->gpu_fan_type == FAN_TYPE_NONE) + return 0; ++ } else if (attr == &dev_attr_fan3_input.attr ++ || attr == &dev_attr_fan3_label.attr ++ || attr == &dev_attr_pwm3_enable.attr) { ++ if (asus->mid_fan_type == FAN_TYPE_NONE) ++ return 0; + } else if (attr == &dev_attr_temp1_input.attr) { + int err = asus_wmi_get_devstate(asus, + ASUS_WMI_DEVID_THERMAL_CTRL, +@@ -2264,6 +2350,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus) + static int asus_wmi_fan_init(struct asus_wmi *asus) + { + asus->gpu_fan_type = FAN_TYPE_NONE; ++ asus->mid_fan_type = FAN_TYPE_NONE; + asus->fan_type = FAN_TYPE_NONE; + asus->agfn_pwm = -1; +@@ -2278,6 +2365,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus) + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL)) + asus->gpu_fan_type = FAN_TYPE_SPEC83; + ++ /* Some models also have a center/middle fan */ ++ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MID_FAN_CTRL)) ++ asus->mid_fan_type = FAN_TYPE_SPEC83; + -+/* 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 -+}; + if (asus->fan_type == FAN_TYPE_NONE) + return -ENODEV; + +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index f90cafe26af1..2c03bda7703f 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -80,6 +80,7 @@ + #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */ + #define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013 + #define ASUS_WMI_DEVID_GPU_FAN_CTRL 0x00110014 ++#define ASUS_WMI_DEVID_MID_FAN_CTRL 0x00110031 + #define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024 + #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025 + +-- +2.41.0 + +From 3b638cb413bfa9f50433676fdc82bf63ef0fb3d9 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Sun, 4 Jun 2023 19:37:34 +1200 +Subject: [PATCH v2 3/8] platform/x86: asus-wmi: support middle fan custom + curves + +Adds support for fan curves defined for the middle fan which +is available on some ASUS ROG laptops. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + drivers/platform/x86/asus-wmi.c | 77 +++++++++++++++++++++- + include/linux/platform_data/x86/asus-wmi.h | 1 + + 2 files changed, 76 insertions(+), 2 deletions(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 375d25ae0aca..fb27218e51cf 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -113,6 +113,7 @@ module_param(fnlock_default, bool, 0444); + #define FAN_CURVE_BUF_LEN 32 + #define FAN_CURVE_DEV_CPU 0x00 + #define FAN_CURVE_DEV_GPU 0x01 ++#define FAN_CURVE_DEV_MID 0x02 + /* Mask to determine if setting temperature or percentage */ + #define FAN_CURVE_PWM_MASK 0x04 + +@@ -253,7 +254,8 @@ struct asus_wmi { + + bool cpu_fan_curve_available; + bool gpu_fan_curve_available; +- struct fan_curve_data custom_fan_curves[2]; ++ bool mid_fan_curve_available; ++ struct fan_curve_data custom_fan_curves[3]; + + struct platform_profile_handler platform_profile_handler; + bool platform_profile_support; +@@ -2080,6 +2082,8 @@ static ssize_t pwm1_enable_store(struct device *dev, + asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; + if (asus->gpu_fan_curve_available) + asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; ++ if (asus->mid_fan_curve_available) ++ asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false; + + return count; + } +@@ -2531,6 +2535,9 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev) + if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE) + fan_idx = FAN_CURVE_DEV_GPU; + ++ if (fan_dev == ASUS_WMI_DEVID_MID_FAN_CURVE) ++ fan_idx = FAN_CURVE_DEV_MID; + - /* 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 = { + curves = &asus->custom_fan_curves[fan_idx]; + err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf, + FAN_CURVE_BUF_LEN); +@@ -2819,6 +2826,42 @@ static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_pwm, fan_curve, + static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_pwm, fan_curve, + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7); + ++/* MID */ ++static SENSOR_DEVICE_ATTR_RW(pwm3_enable, fan_curve_enable, FAN_CURVE_DEV_GPU); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 0); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 1); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 2); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 3); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 4); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 5); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 6); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_temp, fan_curve, ++ FAN_CURVE_DEV_GPU, 7); ++ ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 0); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 1); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 2); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 3); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 4); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 5); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 6); ++static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_pwm, fan_curve, ++ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7); ++ + static struct attribute *asus_fan_curve_attr[] = { + /* CPU */ + &sensor_dev_attr_pwm1_enable.dev_attr.attr, +@@ -2856,6 +2899,24 @@ static struct attribute *asus_fan_curve_attr[] = { + &sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr, ++ /* MID */ ++ &sensor_dev_attr_pwm3_enable.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point6_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point7_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point8_temp.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point6_pwm.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point7_pwm.dev_attr.attr, ++ &sensor_dev_attr_pwm3_auto_point8_pwm.dev_attr.attr, + NULL }; - module_hid_driver(asus_driver); --MODULE_LICENSE("GPL"); -+MODULE_LICENSE("GPL"); +@@ -2875,6 +2936,9 @@ static umode_t asus_fan_curve_is_visible(struct kobject *kobj, + if (asus->gpu_fan_curve_available && attr->name[3] == '2') + return 0644; + ++ if (asus->mid_fan_curve_available && attr->name[3] == '3') ++ return 0644; ++ + return 0; + } + +@@ -2904,7 +2968,14 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus) + if (err) + return err; + +- if (!asus->cpu_fan_curve_available && !asus->gpu_fan_curve_available) ++ err = fan_curve_check_present(asus, &asus->mid_fan_curve_available, ++ ASUS_WMI_DEVID_MID_FAN_CURVE); ++ if (err) ++ return err; ++ ++ if (!asus->cpu_fan_curve_available ++ && !asus->gpu_fan_curve_available ++ && !asus->mid_fan_curve_available) + return 0; + + hwmon = devm_hwmon_device_register_with_groups( +@@ -2973,6 +3044,8 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus) + asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false; + if (asus->gpu_fan_curve_available) + asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false; ++ if (asus->mid_fan_curve_available) ++ asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false; + + return 0; + } +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 2c03bda7703f..329efc086993 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -83,6 +83,7 @@ + #define ASUS_WMI_DEVID_MID_FAN_CTRL 0x00110031 + #define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024 + #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025 ++#define ASUS_WMI_DEVID_MID_FAN_CURVE 0x00110032 + + /* Power */ + #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 +-- +2.41.0 + +From c43a477f701c2c97e13f1a2ee6e1304beeddbf56 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Sun, 4 Jun 2023 20:01:57 +1200 +Subject: [PATCH v2 4/8] platform/x86: asus-wmi: add WMI method to show if egpu + connected + +Exposes the WMI method which tells if the eGPU is properly connected +on the devices that support it. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + .../ABI/testing/sysfs-platform-asus-wmi | 11 +++++++++- + drivers/platform/x86/asus-wmi.c | 21 +++++++++++++++++++ + include/linux/platform_data/x86/asus-wmi.h | 4 +++- + 3 files changed, 34 insertions(+), 2 deletions(-) + +diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi +index eb29e3023c7b..878daf7c2036 100644 +--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi ++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi +@@ -107,4 +107,13 @@ Description: + Get the current charging mode being used: + * 1 - Barrel connected charger, + * 2 - USB-C charging +- * 3 - Both connected, barrel used for charging \ 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 ++ * 3 - Both connected, barrel used for charging ++ ++What: /sys/devices/platform/<platform>/egpu_connected ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Show if the egpu (XG Mobile) is correctly connected: ++ * 0 - False, ++ * 1 - True +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index fb27218e51cf..0c8a4a46b121 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -243,6 +243,7 @@ struct asus_wmi { + + bool charge_mode_available; + bool egpu_enable_available; ++ bool egpu_connect_available; + bool dgpu_disable_available; + bool gpu_mux_mode_available; + +@@ -709,6 +710,22 @@ static ssize_t egpu_enable_store(struct device *dev, + } + static DEVICE_ATTR_RW(egpu_enable); + ++/* Is eGPU connected? *********************************************************/ ++static ssize_t egpu_connected_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ int result; ++ ++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); ++ if (result < 0) ++ return result; ++ ++ return sysfs_emit(buf, "%d\n", result); ++} ++ ++static DEVICE_ATTR_RO(egpu_connected); ++ + /* gpu mux switch *************************************************************/ + static ssize_t gpu_mux_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +@@ -3645,6 +3662,7 @@ static struct attribute *platform_attributes[] = { + &dev_attr_touchpad.attr, + &dev_attr_charge_mode.attr, + &dev_attr_egpu_enable.attr, ++ &dev_attr_egpu_connected.attr, + &dev_attr_dgpu_disable.attr, + &dev_attr_gpu_mux_mode.attr, + &dev_attr_lid_resume.attr, +@@ -3677,6 +3695,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, + ok = asus->charge_mode_available; + else if (attr == &dev_attr_egpu_enable.attr) + ok = asus->egpu_enable_available; ++ else if (attr == &dev_attr_egpu_connected.attr) ++ ok = asus->egpu_connect_available; + else if (attr == &dev_attr_dgpu_disable.attr) + ok = asus->dgpu_disable_available; + else if (attr == &dev_attr_gpu_mux_mode.attr) +@@ -3943,6 +3963,7 @@ static int asus_wmi_add(struct platform_device *pdev) + + asus->charge_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CHARGE_MODE); + asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU); ++ asus->egpu_connect_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); + asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU); + asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX); + asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE); +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 329efc086993..2034648f8cdf 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -100,7 +100,9 @@ + /* Charging mode - 1=Barrel, 2=USB */ + #define ASUS_WMI_DEVID_CHARGE_MODE 0x0012006C + +-/* dgpu on/off */ ++/* epu is connected? 1 == true */ ++#define ASUS_WMI_DEVID_EGPU_CONNECTED 0x00090018 ++/* egpu on/off */ + #define ASUS_WMI_DEVID_EGPU 0x00090019 + + /* dgpu on/off */ +-- +2.41.0 + +From ba1fcbaa4037e2523c40a7aaa0cab9d75bf75e10 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Tue, 20 Jun 2023 12:26:51 +1200 +Subject: [PATCH v2 5/8] platform/x86: asus-wmi: don't allow eGPU switching if + eGPU not connected + +Check the ASUS_WMI_DEVID_EGPU_CONNECTED method for eGPU connection +before allowing the ASUS_WMI_DEVID_EGPU method to run. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + drivers/platform/x86/asus-wmi.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 0c8a4a46b121..821addb284d7 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -693,6 +693,15 @@ static ssize_t egpu_enable_store(struct device *dev, + if (enable > 1) + return -EINVAL; + ++ err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); ++ if (err < 0) ++ return err; ++ if (err < 1) { ++ err = -ENODEV; ++ pr_warn("Failed to set egpu disable: %d\n", err); ++ return err; ++ } ++ + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); + if (err) { + pr_warn("Failed to set egpu disable: %d\n", err); +-- +2.41.0 + +From 391b0757f19890d67ec0ade558a255421588047e Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Tue, 20 Jun 2023 12:48:31 +1200 +Subject: [PATCH v2 6/8] platform/x86: asus-wmi: add safety checks to gpu + switching + +Add safety checking to dgpu_disable, egpu_enable, gpu_mux_mode. + +These checks prevent users from doing such things as: +- disabling the dGPU while is muxed to drive the internal screen +- enabling the eGPU which also disables the dGPU, while muxed to + the internal screen +- switching the MUX to dGPU while the dGPU is disabled + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + drivers/platform/x86/asus-wmi.c | 50 ++++++++++++++++++++++++++++++++- + 1 file changed, 49 insertions(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 821addb284d7..602426a7fb41 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -645,6 +645,18 @@ static ssize_t dgpu_disable_store(struct device *dev, + if (disable > 1) + return -EINVAL; + ++ if (asus->gpu_mux_mode_available) { ++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX); ++ if (result < 0) ++ /* An error here may signal greater failure of GPU handling */ ++ return result; ++ if (!result && disable) { ++ err = -ENODEV; ++ pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err); ++ return err; ++ } ++ } ++ + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result); + if (err) { + pr_warn("Failed to set dgpu disable: %d\n", err); +@@ -693,7 +705,7 @@ static ssize_t egpu_enable_store(struct device *dev, + if (enable > 1) + return -EINVAL; + +- err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); ++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED); + if (err < 0) + return err; + if (err < 1) { +@@ -702,6 +714,18 @@ static ssize_t egpu_enable_store(struct device *dev, + return err; + } + ++ if (asus->gpu_mux_mode_available) { ++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX); ++ if (result < 0) ++ /* An error here may signal greater failure of GPU handling */ ++ return result; ++ if (!result && enable) { ++ err = -ENODEV; ++ pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err); ++ return err; ++ } ++ } ++ + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result); + if (err) { + pr_warn("Failed to set egpu disable: %d\n", err); +@@ -764,6 +788,30 @@ static ssize_t gpu_mux_mode_store(struct device *dev, + if (optimus > 1) + return -EINVAL; + ++ if (asus->dgpu_disable_available) { ++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU); ++ if (result < 0) ++ /* An error here may signal greater failure of GPU handling */ ++ return result; ++ if (result && !optimus) { ++ err = -ENODEV; ++ pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err); ++ return err; ++ } ++ } ++ ++ if (asus->egpu_enable_available) { ++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU); ++ if (result < 0) ++ /* An error here may signal greater failure of GPU handling */ ++ return result; ++ if (result && !optimus) { ++ err = -ENODEV; ++ pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err); ++ return err; ++ } ++ } ++ + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result); + if (err) { + dev_err(dev, "Failed to set GPU MUX mode: %d\n", err); +-- +2.41.0 + +From 7e181ab671dc4c63eb2b2df5cc50dd3218d9b37d Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Sun, 4 Jun 2023 20:21:10 +1200 +Subject: [PATCH v2 7/8] platform/x86: asus-wmi: support setting mini-LED mode + +Support changing the mini-LED mode on some of the newer ASUS laptops. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + .../ABI/testing/sysfs-platform-asus-wmi | 9 ++++ + drivers/platform/x86/asus-wmi.c | 53 +++++++++++++++++++ + include/linux/platform_data/x86/asus-wmi.h | 1 + + 3 files changed, 63 insertions(+) + +diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi +index 878daf7c2036..5624bdef49cb 100644 +--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi ++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi +@@ -117,3 +117,12 @@ Description: + Show if the egpu (XG Mobile) is correctly connected: + * 0 - False, + * 1 - True ++ ++What: /sys/devices/platform/<platform>/mini_led_mode ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Change the mini-LED mode: ++ * 0 - Single-zone, ++ * 1 - Multi-zone +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 602426a7fb41..1fc9e8afc2f3 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -265,6 +265,7 @@ struct asus_wmi { + bool battery_rsoc_available; + + bool panel_overdrive_available; ++ bool mini_led_mode_available; + + struct hotplug_slot hotplug_slot; + struct mutex hotplug_lock; +@@ -1820,6 +1821,54 @@ static ssize_t panel_od_store(struct device *dev, + } + static DEVICE_ATTR_RW(panel_od); + ++/* Mini-LED mode **************************************************************/ ++static ssize_t mini_led_mode_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ int result; ++ ++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MINI_LED_MODE); ++ if (result < 0) ++ return result; ++ ++ return sysfs_emit(buf, "%d\n", result); ++} ++ ++static ssize_t mini_led_mode_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 mode; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &mode); ++ if (result) ++ return result; ++ ++ if (mode > 1) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MINI_LED_MODE, mode, &result); ++ ++ if (err) { ++ pr_warn("Failed to set mini-LED: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mini_led_mode"); ++ ++ return count; ++} ++static DEVICE_ATTR_RW(mini_led_mode); ++ + /* Quirks *********************************************************************/ + + static void asus_wmi_set_xusb2pr(struct asus_wmi *asus) +@@ -3727,6 +3776,7 @@ static struct attribute *platform_attributes[] = { + &dev_attr_fan_boost_mode.attr, + &dev_attr_throttle_thermal_policy.attr, + &dev_attr_panel_od.attr, ++ &dev_attr_mini_led_mode.attr, + NULL + }; + +@@ -3764,6 +3814,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, + ok = asus->throttle_thermal_policy_available; + else if (attr == &dev_attr_panel_od.attr) + ok = asus->panel_overdrive_available; ++ else if (attr == &dev_attr_mini_led_mode.attr) ++ ok = asus->mini_led_mode_available; + + if (devid != -1) + ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); +@@ -4026,6 +4078,7 @@ static int asus_wmi_add(struct platform_device *pdev) + asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE); + asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); + asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); ++ asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE); + + err = fan_boost_mode_check_present(asus); + if (err) +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index 2034648f8cdf..ea80361ac6c7 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -66,6 +66,7 @@ + #define ASUS_WMI_DEVID_CAMERA 0x00060013 + #define ASUS_WMI_DEVID_LID_FLIP 0x00060062 + #define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077 ++#define ASUS_WMI_DEVID_MINI_LED_MODE 0x0005001E + + /* Storage */ + #define ASUS_WMI_DEVID_CARDREADER 0x00080013 +-- +2.41.0 + +From b297ff51a7a10ed07f176cc8ba8ea7a653c5b725 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Tue, 6 Jun 2023 15:05:01 +1200 +Subject: [PATCH v2 8/8] platform/x86: asus-wmi: expose dGPU and CPU tunables + for ROG + +Expose various CPU and dGPU tunables that are available on many ASUS +ROG laptops. The tunables shown in sysfs will vary depending on the CPU +and dGPU vendor. + +All of these variables are write only and there is no easy way to find +what the defaults are. In general they seem to default to the max value +the vendor sets for the CPU and dGPU package - this is not the same as +the min/max writable value. Values written to these variables that are +beyond the capabilities of the CPU are ignored by the laptop. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + .../ABI/testing/sysfs-platform-asus-wmi | 58 ++++ + drivers/platform/x86/asus-wmi.c | 285 ++++++++++++++++++ + include/linux/platform_data/x86/asus-wmi.h | 9 + + 3 files changed, 352 insertions(+) + +diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi +index 5624bdef49cb..caaccd28fabf 100644 +--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi ++++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi +@@ -126,3 +126,61 @@ Description: + Change the mini-LED mode: + * 0 - Single-zone, + * 1 - Multi-zone ++ ++What: /sys/devices/platform/<platform>/ppt_pl1_spl ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD. ++ Shown on Intel+Nvidia or AMD+Nvidia based systems. ++ * min=5, max=250 ++ ++What: /sys/devices/platform/<platform>/ppt_pl2_sppt ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT, ++ on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems. ++ * min=5, max=250 ++ ++What: /sys/devices/platform/<platform>/ppt_fppt ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only. ++ * min=5, max=250 ++ ++What: /sys/devices/platform/<platform>/ppt_apu_sppt ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Set the APU SPPT limit. Shown on full AMD systems only. ++ * min=5, max=130 ++ ++What: /sys/devices/platform/<platform>/ppt_platform_sppt ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Set the platform SPPT limit. Shown on full AMD systems only. ++ * min=5, max=130 ++ ++What: /sys/devices/platform/<platform>/nv_dynamic_boost ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Set the dynamic boost limit of the Nvidia dGPU: ++ * min=5, max=25 ++ ++What: /sys/devices/platform/<platform>/nv_temp_target ++Date: Jun 2023 ++KernelVersion: 6.5 ++Contact: "Luke Jones" <luke@ljones.dev> ++Description: ++ Set the target temperature limit of the Nvidia dGPU: ++ * min=75, max=87 +diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c +index 1fc9e8afc2f3..d9a353081f91 100644 +--- a/drivers/platform/x86/asus-wmi.c ++++ b/drivers/platform/x86/asus-wmi.c +@@ -117,6 +117,16 @@ module_param(fnlock_default, bool, 0444); + /* Mask to determine if setting temperature or percentage */ + #define FAN_CURVE_PWM_MASK 0x04 + ++/* Limits for tunables available on ASUS ROG laptops */ ++#define PPT_TOTAL_MIN 5 ++#define PPT_TOTAL_MAX 250 ++#define PPT_CPU_MIN 5 ++#define PPT_CPU_MAX 130 ++#define NVIDIA_BOOST_MIN 5 ++#define NVIDIA_BOOST_MAX 25 ++#define NVIDIA_TEMP_MIN 75 ++#define NVIDIA_TEMP_MAX 87 ++ + static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; + + static int throttle_thermal_policy_write(struct asus_wmi *); +@@ -247,6 +257,15 @@ struct asus_wmi { + bool dgpu_disable_available; + bool gpu_mux_mode_available; + ++ /* Tunables provided by ASUS for gaming laptops */ ++ bool ppt_pl2_sppt_available; ++ bool ppt_pl1_spl_available; ++ bool ppt_apu_sppt_available; ++ bool ppt_plat_sppt_available; ++ bool ppt_fppt_available; ++ bool nv_dyn_boost_available; ++ bool nv_temp_tgt_available; ++ + bool kbd_rgb_mode_available; + bool kbd_rgb_state_available; + +@@ -946,6 +965,244 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = { + NULL, + }; + ++/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/ ++static ssize_t ppt_pl2_sppt_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 value; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &value); ++ if (result) ++ return result; ++ ++ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL2_SPPT, value, &result); ++ if (err) { ++ pr_warn("Failed to set ppt_pl2_sppt: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set ppt_pl2_sppt (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt"); ++ ++ return count; ++} ++static DEVICE_ATTR_WO(ppt_pl2_sppt); ++ ++/* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/ ++static ssize_t ppt_pl1_spl_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 value; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &value); ++ if (result) ++ return result; ++ ++ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL1_SPL, value, &result); ++ if (err) { ++ pr_warn("Failed to set ppt_pl1_spl: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set ppt_pl1_spl (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl"); ++ ++ return count; ++} ++static DEVICE_ATTR_WO(ppt_pl1_spl); ++ ++/* Tunable: PPT APU FPPT ******************************************************/ ++static ssize_t ppt_fppt_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 value; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &value); ++ if (result) ++ return result; ++ ++ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result); ++ if (err) { ++ pr_warn("Failed to set ppt_fppt: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set ppt_fppt (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt"); ++ ++ return count; ++} ++static DEVICE_ATTR_WO(ppt_fppt); ++ ++/* Tunable: PPT APU SPPT *****************************************************/ ++static ssize_t ppt_apu_sppt_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 value; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &value); ++ if (result) ++ return result; ++ ++ if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_APU_SPPT, value, &result); ++ if (err) { ++ pr_warn("Failed to set ppt_apu_sppt: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set ppt_apu_sppt (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt"); ++ ++ return count; ++} ++static DEVICE_ATTR_WO(ppt_apu_sppt); ++ ++/* Tunable: PPT platform SPPT ************************************************/ ++static ssize_t ppt_platform_sppt_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 value; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &value); ++ if (result) ++ return result; ++ ++ if (value < PPT_CPU_MIN || value > PPT_CPU_MAX) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PLAT_SPPT, value, &result); ++ if (err) { ++ pr_warn("Failed to set ppt_platform_sppt: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set ppt_platform_sppt (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt"); ++ ++ return count; ++} ++static DEVICE_ATTR_WO(ppt_platform_sppt); ++ ++/* Tunable: NVIDIA dynamic boost *********************************************/ ++static ssize_t nv_dynamic_boost_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 value; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &value); ++ if (result) ++ return result; ++ ++ if (value < NVIDIA_BOOST_MIN || value > NVIDIA_BOOST_MAX) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_DYN_BOOST, value, &result); ++ if (err) { ++ pr_warn("Failed to set nv_dynamic_boost: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set nv_dynamic_boost (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost"); ++ ++ return count; ++} ++static DEVICE_ATTR_WO(nv_dynamic_boost); ++ ++/* Tunable: NVIDIA temperature target ****************************************/ ++static ssize_t nv_temp_target_store(struct device *dev, ++ struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int result, err; ++ u32 value; ++ ++ struct asus_wmi *asus = dev_get_drvdata(dev); ++ ++ result = kstrtou32(buf, 10, &value); ++ if (result) ++ return result; ++ ++ if (value < NVIDIA_TEMP_MIN || value > NVIDIA_TEMP_MAX) ++ return -EINVAL; ++ ++ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_THERM_TARGET, value, &result); ++ if (err) { ++ pr_warn("Failed to set nv_temp_target: %d\n", err); ++ return err; ++ } ++ ++ if (result > 1) { ++ pr_warn("Failed to set nv_temp_target (result): 0x%x\n", result); ++ return -EIO; ++ } ++ ++ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target"); ++ ++ return count; ++} ++static DEVICE_ATTR_WO(nv_temp_target); ++ + /* Battery ********************************************************************/ + + /* The battery maximum charging percentage */ +@@ -3775,6 +4032,13 @@ static struct attribute *platform_attributes[] = { + &dev_attr_als_enable.attr, + &dev_attr_fan_boost_mode.attr, + &dev_attr_throttle_thermal_policy.attr, ++ &dev_attr_ppt_pl2_sppt.attr, ++ &dev_attr_ppt_pl1_spl.attr, ++ &dev_attr_ppt_fppt.attr, ++ &dev_attr_ppt_apu_sppt.attr, ++ &dev_attr_ppt_platform_sppt.attr, ++ &dev_attr_nv_dynamic_boost.attr, ++ &dev_attr_nv_temp_target.attr, + &dev_attr_panel_od.attr, + &dev_attr_mini_led_mode.attr, + NULL +@@ -3812,6 +4076,20 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, + ok = asus->fan_boost_mode_available; + else if (attr == &dev_attr_throttle_thermal_policy.attr) + ok = asus->throttle_thermal_policy_available; ++ else if (attr == &dev_attr_ppt_pl2_sppt.attr) ++ ok = asus->ppt_pl2_sppt_available; ++ else if (attr == &dev_attr_ppt_pl1_spl.attr) ++ ok = asus->ppt_pl1_spl_available; ++ else if (attr == &dev_attr_ppt_fppt.attr) ++ ok = asus->ppt_fppt_available; ++ else if (attr == &dev_attr_ppt_apu_sppt.attr) ++ ok = asus->ppt_apu_sppt_available; ++ else if (attr == &dev_attr_ppt_platform_sppt.attr) ++ ok = asus->ppt_plat_sppt_available; ++ else if (attr == &dev_attr_nv_dynamic_boost.attr) ++ ok = asus->nv_dyn_boost_available; ++ else if (attr == &dev_attr_nv_temp_target.attr) ++ ok = asus->nv_temp_tgt_available; + else if (attr == &dev_attr_panel_od.attr) + ok = asus->panel_overdrive_available; + else if (attr == &dev_attr_mini_led_mode.attr) +@@ -4077,6 +4355,13 @@ static int asus_wmi_add(struct platform_device *pdev) + asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX); + asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE); + asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE); ++ asus->ppt_pl2_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL2_SPPT); ++ asus->ppt_pl1_spl_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL1_SPL); ++ asus->ppt_fppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_FPPT); ++ asus->ppt_apu_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_APU_SPPT); ++ asus->ppt_plat_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PLAT_SPPT); ++ asus->nv_dyn_boost_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_DYN_BOOST); ++ asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET); + asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD); + asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE); + +diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h +index ea80361ac6c7..16e99a1c37fc 100644 +--- a/include/linux/platform_data/x86/asus-wmi.h ++++ b/include/linux/platform_data/x86/asus-wmi.h +@@ -86,6 +86,15 @@ + #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025 + #define ASUS_WMI_DEVID_MID_FAN_CURVE 0x00110032 + ++/* Tunables for AUS ROG laptops */ ++#define ASUS_WMI_DEVID_PPT_PL2_SPPT 0x001200A0 ++#define ASUS_WMI_DEVID_PPT_PL1_SPL 0x001200A3 ++#define ASUS_WMI_DEVID_PPT_APU_SPPT 0x001200B0 ++#define ASUS_WMI_DEVID_PPT_PLAT_SPPT 0x001200B1 ++#define ASUS_WMI_DEVID_PPT_FPPT 0x001200C1 ++#define ASUS_WMI_DEVID_NV_DYN_BOOST 0x001200C0 ++#define ASUS_WMI_DEVID_NV_THERM_TARGET 0x001200C2 ++ + /* Power */ + #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 +-- +2.41.0 + +From 43d8c3f0139b08cd3c0c31ed463d7ae57fcf552c Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Sun, 30 Apr 2023 10:56:34 +1200 +Subject: [PATCH v4 1/1] platform/x86: asus-wmi: add support for ASUS screenpad + +Add support for the WMI methods used to turn off and adjust the +brightness of the secondary "screenpad" device found on some high-end +ASUS laptops like the GX650P series and others. + +These methods are utilised in a new backlight device named asus_screenpad. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + drivers/platform/x86/asus-wmi.c | 128 +++++++++++++++++++++ + drivers/platform/x86/asus-wmi.h | 1 + + include/linux/platform_data/x86/asus-wmi.h | 4 + + 3 files changed, 133 insertions(+) + diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c -index 1038dfdcdd32..14a32e08f900 100644 +index 62cee13f5576..967c92ceb041 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -25,6 +25,7 @@ @@ -317,7 +1347,7 @@ index 1038dfdcdd32..14a32e08f900 100644 #include <linux/module.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> -@@ -200,6 +201,7 @@ struct asus_wmi { +@@ -212,6 +213,7 @@ struct asus_wmi { struct input_dev *inputdev; struct backlight_device *backlight_device; @@ -325,7 +1355,7 @@ index 1038dfdcdd32..14a32e08f900 100644 struct platform_device *platform_device; struct led_classdev wlan_led; -@@ -3208,6 +3210,127 @@ static int is_display_toggle(int code) +@@ -3839,6 +3841,123 @@ static int is_display_toggle(int code) return 0; } @@ -333,8 +1363,9 @@ index 1038dfdcdd32..14a32e08f900 100644 + +static int read_screenpad_backlight_power(struct asus_wmi *asus) +{ -+ int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); ++ int ret; + ++ ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_SCREENPAD_POWER); + if (ret < 0) + return ret; + /* 1 == powered */ @@ -368,9 +1399,7 @@ index 1038dfdcdd32..14a32e08f900 100644 + u32 ctrl_param; + + power = read_screenpad_backlight_power(asus); -+ if (power == -ENODEV) -+ return err; -+ else if (power < 0) ++ if (power < 0) + return power; + + if (bd->props.power != power) { @@ -404,14 +1433,22 @@ index 1038dfdcdd32..14a32e08f900 100644 +{ + struct backlight_device *bd; + struct backlight_properties props; -+ int power, brightness; ++ int err, power; ++ int brightness = 0; + + power = read_screenpad_backlight_power(asus); -+ if (power == -ENODEV) -+ power = FB_BLANK_UNBLANK; -+ else if (power < 0) ++ if (power < 0) + return power; + ++ if (power != FB_BLANK_POWERDOWN) { ++ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness); ++ if (err < 0) ++ return err; ++ } ++ /* default to an acceptable min brightness on boot if too low */ ++ if (brightness < 60) ++ brightness = 60; ++ + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ + props.max_brightness = 255; @@ -424,17 +1461,6 @@ index 1038dfdcdd32..14a32e08f900 100644 + } + + 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; @@ -453,28 +1479,36 @@ index 1038dfdcdd32..14a32e08f900 100644 /* 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) +@@ -4504,6 +4623,12 @@ 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; ++ goto fail_screenpad; + } + 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: +@@ -4527,6 +4652,8 @@ static int asus_wmi_add(struct platform_device *pdev) asus_wmi_backlight_exit(asus); -+ asus_screenpad_exit(asus); fail_backlight: asus_wmi_rfkill_exit(asus); ++fail_screenpad: ++ asus_screenpad_exit(asus); fail_rfkill: + asus_wmi_led_exit(asus); + fail_leds: +@@ -4553,6 +4680,7 @@ static int asus_wmi_remove(struct platform_device *device) + asus = platform_get_drvdata(device); + wmi_remove_notify_handler(asus->driver->event_guid); + asus_wmi_backlight_exit(asus); ++ asus_screenpad_exit(asus); + asus_wmi_input_exit(asus); + asus_wmi_led_exit(asus); + asus_wmi_rfkill_exit(asus); 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 @@ -488,7 +1522,7 @@ index a478ebfd34df..5fbdd0eafa02 100644 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 +index d17ae2eb0f8d..61ba70b32846 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -58,6 +58,10 @@ @@ -502,3 +1536,160 @@ index 28234dc9fa6a..a2d94adb5c80 100644 #define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018 #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075 +-- +2.41.0 + +From 3f62172395b381b53e76dd8bcb8f202f8bad3720 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Fri, 30 Jun 2023 16:24:05 +1200 +Subject: [PATCH v2 1/5] ALSA: hda/realtek: Add quirk for ASUS ROG GX650P + +Adds the required quirk to enable the Cirrus amp and correct pins +on the ASUS ROG GV601V series which uses an I2C connected Cirrus amp. + +While this works if the related _DSD properties are made available, these +aren't included in the ACPI of these laptops (yet). + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + sound/pci/hda/patch_realtek.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index afe8253f9a4f..b41fdf22157c 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -7068,6 +7068,8 @@ enum { + ALC285_FIXUP_SPEAKER2_TO_DAC1, + ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1, + ALC285_FIXUP_ASUS_HEADSET_MIC, ++ ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1, ++ ALC285_FIXUP_ASUS_I2C_HEADSET_MIC, + ALC280_FIXUP_HP_HEADSET_MIC, + ALC221_FIXUP_HP_FRONT_MIC, + ALC292_FIXUP_TPT460, +@@ -8058,6 +8060,22 @@ static const struct hda_fixup alc269_fixups[] = { + .chained = true, + .chain_id = ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1 + }, ++ [ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1] = { ++ .type = HDA_FIXUP_FUNC, ++ .v.func = alc285_fixup_speaker2_to_dac1, ++ .chained = true, ++ .chain_id = ALC287_FIXUP_CS35L41_I2C_2 ++ }, ++ [ALC285_FIXUP_ASUS_I2C_HEADSET_MIC] = { ++ .type = HDA_FIXUP_PINS, ++ .v.pins = (const struct hda_pintbl[]) { ++ { 0x19, 0x03a11050 }, ++ { 0x1b, 0x03a11c30 }, ++ { } ++ }, ++ .chained = true, ++ .chain_id = ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1 ++ }, + [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { +@@ -9573,6 +9591,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), ++ SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650P", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604V", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603V", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601V", ALC285_FIXUP_ASUS_HEADSET_MIC), +-- +2.41.0 + +From c0a696a80313e239f092dcda8c24f26c93eb9167 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Fri, 30 Jun 2023 16:25:02 +1200 +Subject: [PATCH v2 2/5] ALSA: hda/realtek: Add quirk for ASUS ROG GA402X + +Adds the required quirk to enable the Cirrus amp and correct pins +on the ASUS ROG GA402X series which uses an I2C connected Cirrus amp. + +While this works if the related _DSD properties are made available, these +aren't included in the ACPI of these laptops (yet). + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + sound/pci/hda/patch_realtek.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index b41fdf22157c..1fae8e8b1234 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -9592,6 +9592,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), + SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650P", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), ++ SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604V", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603V", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601V", ALC285_FIXUP_ASUS_HEADSET_MIC), +-- +2.41.0 + +From 64411d8f62ef78bb45167fb7f10f87c662148a7c Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Tue, 4 Jul 2023 16:06:46 +1200 +Subject: [PATCH v2 4/5] ALSA: hda/realtek: Add quirk for ASUS ROG G614Jx + +Adds the required quirk to enable the Cirrus amp and correct pins +on the ASUS ROG G614J series which uses an SPI connected Cirrus amp. + +While this works if the related _DSD properties are made available, these +aren't included in the ACPI of these laptops (yet). + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + sound/pci/hda/patch_realtek.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index 50becdc86daa..ba3c113f0be1 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -9573,6 +9573,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401), + SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS), ++ SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JI", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_HEADSET_MIC), + SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC), + SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401), +-- +2.41.0 + +From fb720ee87adcf7ab507b46299652ebd8f0f04f12 Mon Sep 17 00:00:00 2001 +From: "Luke D. Jones" <luke@ljones.dev> +Date: Tue, 4 Jul 2023 16:34:23 +1200 +Subject: [PATCH v2 5/5] Fixes: 31278997add6 (ALSA: hda/realtek - Add headset + quirk for Dell DT) + +Remove an erroneous whitespace. + +Signed-off-by: Luke D. Jones <luke@ljones.dev> +--- + sound/pci/hda/patch_realtek.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c +index ba3c113f0be1..1547c40dc7e9 100644 +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5883,7 +5883,7 @@ static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); +- } ++ } + else + alc_fixup_headset_mode(codec, fix, action); + } +-- +2.41.0 + |