Skip to content

Commit e0894ff

Browse files
flukejonesij-intel
authored andcommitted
platform/x86: asus-wmi: disable USB0 hub on ROG Ally before suspend
ASUS have worked around an issue in XInput where it doesn't support USB selective suspend, which causes suspend issues in Windows. They worked around this by adjusting the MCU firmware to disable the USB0 hub when the screen is switched off during the Microsoft DSM suspend path in ACPI. The issue we have with this however is one of timing - the call the tells the MCU to this isn't able to complete before suspend is done so we call this in a prepare() and add a small msleep() to ensure it is done. This must be done before the screen is switched off to prevent a variety of possible races. Further to this the MCU powersave option must also be disabled as it can cause a number of issues such as: - unreliable resume connection of N-Key - complete loss of N-Key if the power is plugged in while suspended Disabling the powersave option prevents this. Without this the MCU is unable to initialise itself correctly on resume. Signed-off-by: "Luke D. Jones" <[email protected]> Tested-by: Philip Mueller <[email protected]> Reviewed-by: Hans de Goede <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ilpo Järvinen <[email protected]>
1 parent fb103b9 commit e0894ff

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

drivers/platform/x86/asus-wmi.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/acpi.h>
1717
#include <linux/backlight.h>
1818
#include <linux/debugfs.h>
19+
#include <linux/delay.h>
1920
#include <linux/dmi.h>
2021
#include <linux/fb.h>
2122
#include <linux/hwmon.h>
@@ -132,6 +133,11 @@ module_param(fnlock_default, bool, 0444);
132133
#define ASUS_SCREENPAD_BRIGHT_MAX 255
133134
#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
134135

136+
/* Controls the power state of the USB0 hub on ROG Ally which input is on */
137+
#define ASUS_USB0_PWR_EC0_CSEE "\\_SB.PCI0.SBRG.EC0.CSEE"
138+
/* 300ms so far seems to produce a reliable result on AC and battery */
139+
#define ASUS_USB0_PWR_EC0_CSEE_WAIT 300
140+
135141
static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
136142

137143
static int throttle_thermal_policy_write(struct asus_wmi *);
@@ -300,6 +306,9 @@ struct asus_wmi {
300306

301307
bool fnlock_locked;
302308

309+
/* The ROG Ally device requires the MCU USB device be disconnected before suspend */
310+
bool ally_mcu_usb_switch;
311+
303312
struct asus_wmi_debug debug;
304313

305314
struct asus_wmi_driver *driver;
@@ -4488,6 +4497,8 @@ static int asus_wmi_add(struct platform_device *pdev)
44884497
asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);
44894498
asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
44904499
asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
4500+
asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
4501+
&& dmi_match(DMI_BOARD_NAME, "RC71L");
44914502

44924503
err = fan_boost_mode_check_present(asus);
44934504
if (err)
@@ -4662,6 +4673,43 @@ static int asus_hotk_resume(struct device *device)
46624673
asus_wmi_fnlock_update(asus);
46634674

46644675
asus_wmi_tablet_mode_get_state(asus);
4676+
4677+
return 0;
4678+
}
4679+
4680+
static int asus_hotk_resume_early(struct device *device)
4681+
{
4682+
struct asus_wmi *asus = dev_get_drvdata(device);
4683+
4684+
if (asus->ally_mcu_usb_switch) {
4685+
if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB8)))
4686+
dev_err(device, "ROG Ally MCU failed to connect USB dev\n");
4687+
else
4688+
msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT);
4689+
}
4690+
return 0;
4691+
}
4692+
4693+
static int asus_hotk_prepare(struct device *device)
4694+
{
4695+
struct asus_wmi *asus = dev_get_drvdata(device);
4696+
int result, err;
4697+
4698+
if (asus->ally_mcu_usb_switch) {
4699+
/* When powersave is enabled it causes many issues with resume of USB hub */
4700+
result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MCU_POWERSAVE);
4701+
if (result == 1) {
4702+
dev_warn(device, "MCU powersave enabled, disabling to prevent resume issues");
4703+
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MCU_POWERSAVE, 0, &result);
4704+
if (err || result != 1)
4705+
dev_err(device, "Failed to set MCU powersave mode: %d\n", err);
4706+
}
4707+
/* sleep required to ensure USB0 is disabled before sleep continues */
4708+
if (ACPI_FAILURE(acpi_execute_simple_method(NULL, ASUS_USB0_PWR_EC0_CSEE, 0xB7)))
4709+
dev_err(device, "ROG Ally MCU failed to disconnect USB dev\n");
4710+
else
4711+
msleep(ASUS_USB0_PWR_EC0_CSEE_WAIT);
4712+
}
46654713
return 0;
46664714
}
46674715

@@ -4709,6 +4757,8 @@ static const struct dev_pm_ops asus_pm_ops = {
47094757
.thaw = asus_hotk_thaw,
47104758
.restore = asus_hotk_restore,
47114759
.resume = asus_hotk_resume,
4760+
.resume_early = asus_hotk_resume_early,
4761+
.prepare = asus_hotk_prepare,
47124762
};
47134763

47144764
/* Registration ***************************************************************/

include/linux/platform_data/x86/asus-wmi.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@
114114
/* Charging mode - 1=Barrel, 2=USB */
115115
#define ASUS_WMI_DEVID_CHARGE_MODE 0x0012006C
116116

117+
/* MCU powersave mode */
118+
#define ASUS_WMI_DEVID_MCU_POWERSAVE 0x001200E2
119+
117120
/* epu is connected? 1 == true */
118121
#define ASUS_WMI_DEVID_EGPU_CONNECTED 0x00090018
119122
/* egpu on/off */

0 commit comments

Comments
 (0)