diff options
Diffstat (limited to 'drivers/platform/x86/asus-wmi.c')
| -rw-r--r-- | drivers/platform/x86/asus-wmi.c | 852 | 
1 files changed, 817 insertions, 35 deletions
| diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 8bef66a2f0ce..9f7e23c5c6b4 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -16,6 +16,7 @@  #include <linux/acpi.h>  #include <linux/backlight.h>  #include <linux/debugfs.h> +#include <linux/delay.h>  #include <linux/dmi.h>  #include <linux/fb.h>  #include <linux/hwmon.h> @@ -25,6 +26,7 @@  #include <linux/input/sparse-keymap.h>  #include <linux/kernel.h>  #include <linux/leds.h> +#include <linux/minmax.h>  #include <linux/module.h>  #include <linux/pci.h>  #include <linux/pci_hotplug.h> @@ -72,6 +74,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 @@ -112,9 +115,29 @@ 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 +/* 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 + +#define ASUS_SCREENPAD_BRIGHT_MIN 20 +#define ASUS_SCREENPAD_BRIGHT_MAX 255 +#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60 + +/* Controls the power state of the USB0 hub on ROG Ally which input is on */ +#define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE" +/* 300ms so far seems to produce a reliable result on AC and battery */ +#define ASUS_USB0_PWR_EC0_CSEE_WAIT 300 +  static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };  static int throttle_thermal_policy_write(struct asus_wmi *); @@ -200,6 +223,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; @@ -229,18 +253,31 @@ 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;  	u8 fan_boost_mode_mask;  	u8 fan_boost_mode; +	bool charge_mode_available;  	bool egpu_enable_available; +	bool egpu_connect_available;  	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; @@ -249,7 +286,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; @@ -258,6 +296,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; @@ -267,6 +306,9 @@ struct asus_wmi {  	bool fnlock_locked; +	/* The ROG Ally device requires the MCU USB device be disconnected before suspend */ +	bool ally_mcu_usb_switch; +  	struct asus_wmi_debug debug;  	struct asus_wmi_driver *driver; @@ -586,6 +628,22 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)  		asus_wmi_tablet_sw_report(asus, result);  } +/* 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) @@ -622,6 +680,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); @@ -670,14 +740,34 @@ 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) { +		pr_warn("Failed to get egpu connection status: %d\n", err); +		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 */ +			pr_warn("Failed to get gpu mux status: %d\n", result); +			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); +		pr_warn("Failed to set egpu state: %d\n", err);  		return err;  	}  	if (result > 1) { -		pr_warn("Failed to set egpu disable (retval): 0x%x\n", result); +		pr_warn("Failed to set egpu state (retval): 0x%x\n", result);  		return -EIO;  	} @@ -687,6 +777,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) @@ -716,6 +822,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); @@ -859,6 +989,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 */ @@ -1734,6 +2102,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) @@ -2070,6 +2486,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;  } @@ -2122,6 +2540,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) @@ -2168,6 +2611,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 ASUS_FAN_CTRL_AUTO: +		value = 0; +		break; +	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); @@ -2177,6 +2666,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); @@ -2185,10 +2678,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 @@ -2214,6 +2710,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, @@ -2257,6 +2758,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; @@ -2271,6 +2773,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; +  	if (asus->fan_type == FAN_TYPE_NONE)  		return -ENODEV; @@ -2418,9 +2924,8 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)  {  	struct fan_curve_data *curves;  	u8 buf[FAN_CURVE_BUF_LEN]; -	int fan_idx = 0; +	int err, fan_idx;  	u8 mode = 0; -	int err;  	if (asus->throttle_thermal_policy_available)  		mode = asus->throttle_thermal_policy_mode; @@ -2430,10 +2935,6 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)  	else if (mode == 1)  		mode = 2; -	if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE) -		fan_idx = FAN_CURVE_DEV_GPU; - -	curves = &asus->custom_fan_curves[fan_idx];  	err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf,  					   FAN_CURVE_BUF_LEN);  	if (err) { @@ -2441,9 +2942,17 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)  		return err;  	} -	fan_curve_copy_from_buf(curves, buf); +	fan_idx = FAN_CURVE_DEV_CPU; +	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; + +	curves = &asus->custom_fan_curves[fan_idx];  	curves->device_id = fan_dev; +	fan_curve_copy_from_buf(curves, buf);  	return 0;  } @@ -2473,7 +2982,7 @@ static struct fan_curve_data *fan_curve_attr_select(struct asus_wmi *asus,  {  	int index = to_sensor_dev_attr(attr)->index; -	return &asus->custom_fan_curves[index & FAN_CURVE_DEV_GPU]; +	return &asus->custom_fan_curves[index];  }  /* Determine which fan the attribute is for if SENSOR_ATTR_2 */ @@ -2482,7 +2991,7 @@ static struct fan_curve_data *fan_curve_attr_2_select(struct asus_wmi *asus,  {  	int nr = to_sensor_dev_attr_2(attr)->nr; -	return &asus->custom_fan_curves[nr & FAN_CURVE_DEV_GPU]; +	return &asus->custom_fan_curves[nr & ~FAN_CURVE_PWM_MASK];  }  static ssize_t fan_curve_show(struct device *dev, @@ -2491,13 +3000,13 @@ static ssize_t fan_curve_show(struct device *dev,  	struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr);  	struct asus_wmi *asus = dev_get_drvdata(dev);  	struct fan_curve_data *data; -	int value, index, nr; +	int value, pwm, index;  	data = fan_curve_attr_2_select(asus, attr); +	pwm = dev_attr->nr & FAN_CURVE_PWM_MASK;  	index = dev_attr->index; -	nr = dev_attr->nr; -	if (nr & FAN_CURVE_PWM_MASK) +	if (pwm)  		value = data->percents[index];  	else  		value = data->temps[index]; @@ -2540,23 +3049,21 @@ static ssize_t fan_curve_store(struct device *dev,  	struct sensor_device_attribute_2 *dev_attr = to_sensor_dev_attr_2(attr);  	struct asus_wmi *asus = dev_get_drvdata(dev);  	struct fan_curve_data *data; +	int err, pwm, index;  	u8 value; -	int err; - -	int pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; -	int index = dev_attr->index;  	data = fan_curve_attr_2_select(asus, attr); +	pwm = dev_attr->nr & FAN_CURVE_PWM_MASK; +	index = dev_attr->index;  	err = kstrtou8(buf, 10, &value);  	if (err < 0)  		return err; -	if (pwm) { +	if (pwm)  		data->percents[index] = value; -	} else { +	else  		data->temps[index] = value; -	}  	/*  	 * Mark as disabled so the user has to explicitly enable to apply a @@ -2669,7 +3176,7 @@ static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point8_temp, fan_curve,  			       FAN_CURVE_DEV_CPU, 7);  static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point1_pwm, fan_curve, -			       FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 0); +				FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 0);  static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point2_pwm, fan_curve,  			       FAN_CURVE_DEV_CPU | FAN_CURVE_PWM_MASK, 1);  static SENSOR_DEVICE_ATTR_2_RW(pwm1_auto_point3_pwm, fan_curve, @@ -2721,6 +3228,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_MID); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 0); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 1); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 2); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 3); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 4); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 5); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 6); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_temp, fan_curve, +			       FAN_CURVE_DEV_MID, 7); + +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 0); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 1); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 2); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 3); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 4); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 5); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 6); +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_pwm, fan_curve, +			       FAN_CURVE_DEV_MID | FAN_CURVE_PWM_MASK, 7); +  static struct attribute *asus_fan_curve_attr[] = {  	/* CPU */  	&sensor_dev_attr_pwm1_enable.dev_attr.attr, @@ -2758,6 +3301,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  }; @@ -2777,6 +3338,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;  } @@ -2806,7 +3370,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( @@ -2875,6 +3446,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;  } @@ -3218,6 +3791,124 @@ static int is_display_toggle(int code)  	return 0;  } +/* Screenpad backlight *******************************************************/ + +static int read_screenpad_backlight_power(struct asus_wmi *asus) +{ +	int ret; + +	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 - ASUS_SCREENPAD_BRIGHT_MIN; + +	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval); +	if (err < 0) +		return err; + +	return (retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK) - ASUS_SCREENPAD_BRIGHT_MIN; +} + +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 < 0) +		return power; + +	if (bd->props.power != power) { +		if (power != FB_BLANK_UNBLANK) { +			/* Only brightness > 0 can power it back on */ +			ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN; +			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 + ASUS_SCREENPAD_BRIGHT_MIN; +		err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL); +	} + +	/* Ensure brightness is stored to turn back on with */ +	if (err == 0) +		asus->driver->screenpad_brightness = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN; + +	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 err, power; +	int brightness = 0; + +	power = read_screenpad_backlight_power(asus); +	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 < ASUS_SCREENPAD_BRIGHT_MIN) +		brightness = ASUS_SCREENPAD_BRIGHT_DEFAULT; + +	memset(&props, 0, sizeof(struct backlight_properties)); +	props.type = BACKLIGHT_RAW; /* ensure this bd is last to be picked */ +	props.max_brightness = ASUS_SCREENPAD_BRIGHT_MAX - ASUS_SCREENPAD_BRIGHT_MIN; +	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; +	asus->driver->screenpad_brightness = brightness; +	bd->props.brightness = brightness - ASUS_SCREENPAD_BRIGHT_MIN; +	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) @@ -3268,7 +3959,6 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)  {  	unsigned int key_value = 1;  	bool autorelease = 1; -	int orig_code = code;  	if (asus->driver->key_filter) {  		asus->driver->key_filter(asus->driver, &code, &key_value, @@ -3277,16 +3967,10 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)  			return;  	} -	if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) -		code = ASUS_WMI_BRN_UP; -	else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) -		code = ASUS_WMI_BRN_DOWN; - -	if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) { -		if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { -			asus_wmi_backlight_notify(asus, orig_code); -			return; -		} +	if (acpi_video_get_backlight_type() == acpi_backlight_vendor && +	    code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNDOWN_MAX) { +		asus_wmi_backlight_notify(asus, code); +		return;  	}  	if (code == NOTIFY_KBD_BRTUP) { @@ -3472,14 +4156,24 @@ 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_egpu_connected.attr,  	&dev_attr_dgpu_disable.attr,  	&dev_attr_gpu_mux_mode.attr,  	&dev_attr_lid_resume.attr,  	&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  }; @@ -3501,8 +4195,12 @@ 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_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) @@ -3511,8 +4209,24 @@ 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) +		ok = asus->mini_led_mode_available;  	if (devid != -1)  		ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); @@ -3767,12 +4481,24 @@ 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->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);  	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); +	asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE) +						&& dmi_match(DMI_BOARD_NAME, "RC71L");  	err = fan_boost_mode_check_present(asus);  	if (err) @@ -3833,6 +4559,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)) { +		err = asus_screenpad_init(asus); +		if (err && err != -ENODEV) +			goto fail_screenpad; +	} +  	if (asus_wmi_has_fnlock_key(asus)) {  		asus->fnlock_locked = fnlock_default;  		asus_wmi_fnlock_update(asus); @@ -3846,6 +4578,12 @@ static int asus_wmi_add(struct platform_device *pdev)  		goto fail_wmi_handler;  	} +	if (asus->driver->i8042_filter) { +		err = i8042_install_filter(asus->driver->i8042_filter); +		if (err) +			pr_warn("Unable to install key filter - %d\n", err); +	} +  	asus_wmi_battery_init(asus);  	asus_wmi_debugfs_init(asus); @@ -3856,6 +4594,8 @@ fail_wmi_handler:  	asus_wmi_backlight_exit(asus);  fail_backlight:  	asus_wmi_rfkill_exit(asus); +fail_screenpad: +	asus_screenpad_exit(asus);  fail_rfkill:  	asus_wmi_led_exit(asus);  fail_leds: @@ -3880,8 +4620,11 @@ static int asus_wmi_remove(struct platform_device *device)  	struct asus_wmi *asus;  	asus = platform_get_drvdata(device); +	if (asus->driver->i8042_filter) +		i8042_remove_filter(asus->driver->i8042_filter);  	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); @@ -3930,6 +4673,43 @@ static int asus_hotk_resume(struct device *device)  		asus_wmi_fnlock_update(asus);  	asus_wmi_tablet_mode_get_state(asus); + +	return 0; +} + +static int asus_hotk_resume_early(struct device *device) +{ +	struct asus_wmi *asus = dev_get_drvdata(device); + +	if (asus->ally_mcu_usb_switch) { +		if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB8))) +			dev_err(device, "ROG Ally MCU failed to connect USB dev\n"); +		else +			msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); +	} +	return 0; +} + +static int asus_hotk_prepare(struct device *device) +{ +	struct asus_wmi *asus = dev_get_drvdata(device); +	int result, err; + +	if (asus->ally_mcu_usb_switch) { +		/* When powersave is enabled it causes many issues with resume of USB hub */ +		result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MCU_POWERSAVE); +		if (result == 1) { +			dev_warn(device, "MCU powersave enabled, disabling to prevent resume issues"); +			err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, 0, &result); +			if (err || result != 1) +				dev_err(device, "Failed to set MCU powersave mode: %d\n", err); +		} +		/* sleep required to ensure USB0 is disabled before sleep continues */ +		if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB7))) +			dev_err(device, "ROG Ally MCU failed to disconnect USB dev\n"); +		else +			msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT); +	}  	return 0;  } @@ -3977,6 +4757,8 @@ static const struct dev_pm_ops asus_pm_ops = {  	.thaw = asus_hotk_thaw,  	.restore = asus_hotk_restore,  	.resume = asus_hotk_resume, +	.resume_early = asus_hotk_resume_early, +	.prepare = asus_hotk_prepare,  };  /* Registration ***************************************************************/ |