Skip to content

Commit

Permalink
platform/x86: asus_wmi: Support throttle thermal policy
Browse files Browse the repository at this point in the history
Throttle thermal policy ACPI device is used to control CPU cooling and
throttling. This patch adds sysfs entry for setting current mode and
Fn+F5 hotkey that switches to next.

Policy modes:
* 0x00 - default
* 0x01 - overboost
* 0x02 - silent

Signed-off-by: Leonid Maksymchuk <leonmaxx@gmail.com>
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
  • Loading branch information
Leonid Maksymchuk authored and Andy Shevchenko committed Jan 10, 2020
1 parent df532c1 commit 2daa86e
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Documentation/ABI/testing/sysfs-platform-asus-wmi
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,13 @@ Description:
* 0 - normal,
* 1 - overboost,
* 2 - silent

What: /sys/devices/platform/<platform>/throttle_thermal_policy
Date: Dec 2019
KernelVersion: 5.6
Contact: "Leonid Maksymchuk" <leonmaxx@gmail.com>
Description:
Throttle thermal policy mode:
* 0 - default,
* 1 - overboost,
* 2 - silent
113 changes: 113 additions & 0 deletions drivers/platform/x86/asus-wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ MODULE_LICENSE("GPL");
#define NOTIFY_KBD_BRTDWN 0xc5
#define NOTIFY_KBD_BRTTOGGLE 0xc7
#define NOTIFY_KBD_FBM 0x99
#define NOTIFY_KBD_TTP 0xae

#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)

Expand All @@ -81,6 +82,10 @@ MODULE_LICENSE("GPL");
#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02
#define ASUS_FAN_BOOST_MODES_MASK 0x03

#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT 0
#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1
#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2

#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31

Expand Down Expand Up @@ -198,6 +203,9 @@ struct asus_wmi {
u8 fan_boost_mode_mask;
u8 fan_boost_mode;

bool throttle_thermal_policy_available;
u8 throttle_thermal_policy_mode;

// The RSOC controls the maximum charging percentage.
bool battery_rsoc_available;

Expand Down Expand Up @@ -1724,6 +1732,98 @@ static ssize_t fan_boost_mode_store(struct device *dev,
// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent
static DEVICE_ATTR_RW(fan_boost_mode);

/* Throttle thermal policy ****************************************************/

static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
{
u32 result;
int err;

asus->throttle_thermal_policy_available = false;

err = asus_wmi_get_devstate(asus,
ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
&result);
if (err) {
if (err == -ENODEV)
return 0;
return err;
}

if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
asus->throttle_thermal_policy_available = true;

return 0;
}

static int throttle_thermal_policy_write(struct asus_wmi *asus)
{
int err;
u8 value;
u32 retval;

value = asus->throttle_thermal_policy_mode;

err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
value, &retval);
if (err) {
pr_warn("Failed to set throttle thermal policy: %d\n", err);
return err;
}

if (retval != 1) {
pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n",
retval);
return -EIO;
}

return 0;
}

static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
{
u8 new_mode = asus->throttle_thermal_policy_mode + 1;

if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;

asus->throttle_thermal_policy_mode = new_mode;
return throttle_thermal_policy_write(asus);
}

static ssize_t throttle_thermal_policy_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct asus_wmi *asus = dev_get_drvdata(dev);
u8 mode = asus->throttle_thermal_policy_mode;

return scnprintf(buf, PAGE_SIZE, "%d\n", mode);
}

static ssize_t throttle_thermal_policy_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int result;
u8 new_mode;
struct asus_wmi *asus = dev_get_drvdata(dev);

result = kstrtou8(buf, 10, &new_mode);
if (result < 0)
return result;

if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
return -EINVAL;

asus->throttle_thermal_policy_mode = new_mode;
throttle_thermal_policy_write(asus);

return count;
}

// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
static DEVICE_ATTR_RW(throttle_thermal_policy);

/* Backlight ******************************************************************/

static int read_backlight_power(struct asus_wmi *asus)
Expand Down Expand Up @@ -2005,6 +2105,11 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
return;
}

if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) {
throttle_thermal_policy_switch_next(asus);
return;
}

if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
return;

Expand Down Expand Up @@ -2155,6 +2260,7 @@ static struct attribute *platform_attributes[] = {
&dev_attr_lid_resume.attr,
&dev_attr_als_enable.attr,
&dev_attr_fan_boost_mode.attr,
&dev_attr_throttle_thermal_policy.attr,
NULL
};

Expand All @@ -2178,6 +2284,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
devid = ASUS_WMI_DEVID_ALS_ENABLE;
else if (attr == &dev_attr_fan_boost_mode.attr)
ok = asus->fan_boost_mode_available;
else if (attr == &dev_attr_throttle_thermal_policy.attr)
ok = asus->throttle_thermal_policy_available;

if (devid != -1)
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
Expand Down Expand Up @@ -2437,6 +2545,10 @@ static int asus_wmi_add(struct platform_device *pdev)
if (err)
goto fail_fan_boost_mode;

err = throttle_thermal_policy_check_present(asus);
if (err)
goto fail_throttle_thermal_policy;

err = asus_wmi_sysfs_init(asus->platform_device);
if (err)
goto fail_sysfs;
Expand Down Expand Up @@ -2521,6 +2633,7 @@ static int asus_wmi_add(struct platform_device *pdev)
fail_input:
asus_wmi_sysfs_exit(asus->platform_device);
fail_sysfs:
fail_throttle_thermal_policy:
fail_fan_boost_mode:
fail_platform:
kfree(asus);
Expand Down
1 change: 1 addition & 0 deletions include/linux/platform_data/x86/asus-wmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
#define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018
#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075

/* Misc */
#define ASUS_WMI_DEVID_CAMERA 0x00060013
Expand Down

0 comments on commit 2daa86e

Please sign in to comment.