History

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.

Luke D. Jones committed 2 years ago

Commit e0894ff1 parent fb103b92 files · +53 −0Browse files

Unified · Split

2 files
  1. drivers/platform/x86/asus-wmi.c +50 −0
  2. include/linux/platform_data/x86/asus-wmi.h +3 −0
drivers/platform/x86/asus-wmi.c+50−0
@@ -16,6 +16,7 @@ · 15 unmodified lines
16#include <linux/acpi.h>16#include <linux/acpi.h>
17#include <linux/backlight.h>17#include <linux/backlight.h>
18#include <linux/debugfs.h>18#include <linux/debugfs.h>
19#include <linux/delay.h>
19#include <linux/dmi.h>20#include <linux/dmi.h>
20#include <linux/fb.h>21#include <linux/fb.h>
21#include <linux/hwmon.h>22#include <linux/hwmon.h>
@@ -132,6 +133,11 @@ module_param(fnlock_default, bool, 0444); · 110 unmodified lines
132#define ASUS_SCREENPAD_BRIGHT_MAX 255133#define ASUS_SCREENPAD_BRIGHT_MAX 255
133#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60134#define ASUS_SCREENPAD_BRIGHT_DEFAULT 60
134 135
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
135static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };141static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
136 142
137static int throttle_thermal_policy_write(struct asus_wmi *);143static int throttle_thermal_policy_write(struct asus_wmi *);
@@ -300,6 +306,9 @@ struct asus_wmi { · 162 unmodified lines
300 306
301 bool fnlock_locked;307 bool fnlock_locked;
302 308
309 /* The ROG Ally device requires the MCU USB device be disconnected before suspend */
310 bool ally_mcu_usb_switch;
311
303 struct asus_wmi_debug debug;312 struct asus_wmi_debug debug;
304 313
305 struct asus_wmi_driver *driver;314 struct asus_wmi_driver *driver;
@@ -4488,6 +4497,8 @@ static int asus_wmi_add(struct platform_device *pdev) · 4182 unmodified lines
4488 asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);4497 asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);
4489 asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);4498 asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
4490 asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);4499 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");
4491 4502
4492 err = fan_boost_mode_check_present(asus);4503 err = fan_boost_mode_check_present(asus);
4493 if (err)4504 if (err)
@@ -4662,6 +4673,43 @@ static int asus_hotk_resume(struct device *device) · 168 unmodified lines
4662 asus_wmi_fnlock_update(asus);4673 asus_wmi_fnlock_update(asus);
4663 4674
4664 asus_wmi_tablet_mode_get_state(asus);4675 asus_wmi_tablet_mode_get_state(asus);
4676
4677 return 0;
4678}
4679
4680static 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
4693static 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 }
4665 return 0;4713 return 0;
4666}4714}
4667 4715
@@ -4709,6 +4757,8 @@ static const struct dev_pm_ops asus_pm_ops = { · 41 unmodified lines
4709 .thaw = asus_hotk_thaw,4757 .thaw = asus_hotk_thaw,
4710 .restore = asus_hotk_restore,4758 .restore = asus_hotk_restore,
4711 .resume = asus_hotk_resume,4759 .resume = asus_hotk_resume,
4760 .resume_early = asus_hotk_resume_early,
4761 .prepare = asus_hotk_prepare,
4712};4762};
4713 4763
4714/* Registration ***************************************************************/4764/* Registration ***************************************************************/
include/linux/platform_data/x86/asus-wmi.h+3−0
@@ -114,6 +114,9 @@ · 113 unmodified lines
114/* Charging mode - 1=Barrel, 2=USB */114/* Charging mode - 1=Barrel, 2=USB */
115#define ASUS_WMI_DEVID_CHARGE_MODE 0x0012006C115#define ASUS_WMI_DEVID_CHARGE_MODE 0x0012006C
116 116
117/* MCU powersave mode */
118#define ASUS_WMI_DEVID_MCU_POWERSAVE 0x001200E2
119
117/* epu is connected? 1 == true */120/* epu is connected? 1 == true */
118#define ASUS_WMI_DEVID_EGPU_CONNECTED 0x00090018121#define ASUS_WMI_DEVID_EGPU_CONNECTED 0x00090018
119/* egpu on/off */122/* egpu on/off */

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t