platform/x86: asus-wmi: Support the GPU fan on TUF laptops
authorLuke D. Jones <luke@ljones.dev>
Fri, 26 Aug 2022 00:42:10 +0000 (12:42 +1200)
committerHans de Goede <hdegoede@redhat.com>
Fri, 26 Aug 2022 09:35:30 +0000 (11:35 +0200)
Add support for TUF laptops which have the ability to control
the GPU fan. This will show as a second fan in hwmon, and has
the ability to run as boost (fullspeed), or auto.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
Link: https://lore.kernel.org/r/20220826004210.356534-3-luke@ljones.dev
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
drivers/platform/x86/asus-wmi.c
include/linux/platform_data/x86/asus-wmi.h

index 94e0be8..eebc20c 100644 (file)
@@ -226,7 +226,9 @@ struct asus_wmi {
        u32 tablet_switch_dev_id;
 
        enum fan_type fan_type;
+       enum fan_type gpu_fan_type;
        int fan_pwm_mode;
+       int gpu_fan_pwm_mode;
        int agfn_pwm;
 
        bool fan_boost_mode_available;
@@ -1734,6 +1736,18 @@ static int asus_fan_set_auto(struct asus_wmi *asus)
                return -ENXIO;
        }
 
+       /*
+        * Modern models like the G713 also have GPU fan control (this is not AGFN)
+        */
+       if (asus->gpu_fan_type == FAN_TYPE_SPEC83) {
+               status = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL,
+                                              0, &retval);
+               if (status)
+                       return status;
+
+               if (retval != 1)
+                       return -EIO;
+       }
 
        return 0;
 }
@@ -1936,9 +1950,57 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
                       deci_kelvin_to_millicelsius(value & 0xFFFF));
 }
 
+/* GPU fan on modern ROG laptops */
+static ssize_t pwm2_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->gpu_fan_pwm_mode);
+}
+
+static ssize_t pwm2_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_GPU_FAN_CTRL,
+                                   value, &retval);
+       if (ret)
+               return ret;
+
+       if (retval != 1)
+               return -EIO;
+
+       asus->gpu_fan_pwm_mode = state;
+       return count;
+}
+
 /* Fan1 */
 static DEVICE_ATTR_RW(pwm1);
 static DEVICE_ATTR_RW(pwm1_enable);
+static DEVICE_ATTR_RW(pwm2_enable);
 static DEVICE_ATTR_RO(fan1_input);
 static DEVICE_ATTR_RO(fan1_label);
 
@@ -1948,6 +2010,7 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
 static struct attribute *hwmon_attributes[] = {
        &dev_attr_pwm1.attr,
        &dev_attr_pwm1_enable.attr,
+       &dev_attr_pwm2_enable.attr,
        &dev_attr_fan1_input.attr,
        &dev_attr_fan1_label.attr,
 
@@ -1970,6 +2033,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
            || attr == &dev_attr_pwm1_enable.attr) {
                if (asus->fan_type == FAN_TYPE_NONE)
                        return 0;
+       } else if (attr == &dev_attr_pwm2_enable.attr) {
+               if (asus->gpu_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,
@@ -2012,6 +2078,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->fan_type = FAN_TYPE_NONE;
        asus->agfn_pwm = -1;
 
@@ -2020,6 +2087,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
        else if (asus_wmi_has_agfn_fan(asus))
                asus->fan_type = FAN_TYPE_AGFN;
 
+       /*  Modern models like G713 also have GPU fan control */
+       if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL))
+               asus->gpu_fan_type = FAN_TYPE_SPEC83;
+
        if (asus->fan_type == FAN_TYPE_NONE)
                return -ENODEV;
 
index 6e8a95c..31d810e 100644 (file)
@@ -79,6 +79,7 @@
 #define ASUS_WMI_DEVID_THERMAL_CTRL    0x00110011
 #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_CPU_FAN_CURVE   0x00110024
 #define ASUS_WMI_DEVID_GPU_FAN_CURVE   0x00110025