summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/asus-wmi.c125
-rw-r--r--include/linux/platform_data/x86/asus-wmi.h1
2 files changed, 101 insertions, 25 deletions
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 25f1e256c442..34dfbed65332 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -67,6 +67,7 @@ MODULE_LICENSE("GPL");
#define ASUS_FAN_SFUN_WRITE 0x07
/* Based on standard hwmon pwmX_enable values */
+#define ASUS_FAN_CTRL_FULLSPEED 0
#define ASUS_FAN_CTRL_MANUAL 1
#define ASUS_FAN_CTRL_AUTO 2
@@ -153,6 +154,7 @@ struct asus_rfkill {
enum fan_type {
FAN_TYPE_NONE = 0,
FAN_TYPE_AGFN, /* deprecated on newer platforms */
+ FAN_TYPE_SPEC83, /* starting in Spec 8.3, use CPU_FAN_CTRL */
};
struct asus_wmi {
@@ -1211,10 +1213,29 @@ static bool asus_wmi_has_agfn_fan(struct asus_wmi *asus)
static int asus_fan_set_auto(struct asus_wmi *asus)
{
int status;
+ u32 retval;
- status = asus_agfn_fan_speed_write(asus, 0, NULL);
- if (status)
+ switch (asus->fan_type) {
+ case FAN_TYPE_SPEC83:
+ status = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL,
+ 0, &retval);
+ if (status)
+ return status;
+
+ if (retval != 1)
+ return -EIO;
+ break;
+
+ case FAN_TYPE_AGFN:
+ status = asus_agfn_fan_speed_write(asus, 0, NULL);
+ if (status)
+ return -ENXIO;
+ break;
+
+ default:
return -ENXIO;
+ }
+
return 0;
}
@@ -1287,13 +1308,29 @@ static ssize_t fan1_input_show(struct device *dev,
int value;
int ret;
- /* no speed readable on manual mode */
- if (asus->fan_pwm_mode == ASUS_FAN_CTRL_MANUAL)
- return -ENXIO;
+ switch (asus->fan_type) {
+ case FAN_TYPE_SPEC83:
+ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL,
+ &value);
+ if (ret < 0)
+ return ret;
- ret = asus_agfn_fan_speed_read(asus, 1, &value);
- if (ret) {
- pr_warn("reading fan speed failed: %d\n", ret);
+ value &= 0xffff;
+ break;
+
+ case FAN_TYPE_AGFN:
+ /* no speed readable on manual mode */
+ if (asus->fan_pwm_mode == ASUS_FAN_CTRL_MANUAL)
+ return -ENXIO;
+
+ ret = asus_agfn_fan_speed_read(asus, 1, &value);
+ if (ret) {
+ pr_warn("reading fan speed failed: %d\n", ret);
+ return -ENXIO;
+ }
+ break;
+
+ default:
return -ENXIO;
}
@@ -1306,6 +1343,15 @@ static ssize_t pwm1_enable_show(struct device *dev,
{
struct asus_wmi *asus = dev_get_drvdata(dev);
+ /*
+ * Just read back the cached pwm mode.
+ *
+ * For the CPU_FAN device, the spec indicates that we should be
+ * able to read the device status and consult bit 19 to see if we
+ * are in Full On or Automatic mode. However, this does not work
+ * in practice on X532FL at least (the bit is always 0) and there's
+ * also nothing in the DSDT to indicate that this behaviour exists.
+ */
return sprintf(buf, "%d\n", asus->fan_pwm_mode);
}
@@ -1316,25 +1362,48 @@ static ssize_t pwm1_enable_store(struct device *dev,
struct asus_wmi *asus = dev_get_drvdata(dev);
int status = 0;
int state;
+ int value;
int ret;
+ u32 retval;
ret = kstrtouint(buf, 10, &state);
if (ret)
return ret;
- switch (state) {
- case ASUS_FAN_CTRL_MANUAL:
- break;
+ if (asus->fan_type == FAN_TYPE_SPEC83) {
+ 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;
+ }
- case ASUS_FAN_CTRL_AUTO:
- status = asus_fan_set_auto(asus);
- if (status)
- return status;
- break;
+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL,
+ value, &retval);
+ if (ret)
+ return ret;
- default:
- return -EINVAL;
+ if (retval != 1)
+ return -EIO;
+ } else if (asus->fan_type == FAN_TYPE_AGFN) {
+ switch (state) {
+ case ASUS_FAN_CTRL_MANUAL:
+ break;
+
+ case ASUS_FAN_CTRL_AUTO:
+ status = asus_fan_set_auto(asus);
+ if (status)
+ return status;
+ break;
+
+ default:
+ return -EINVAL;
+ }
}
asus->fan_pwm_mode = state;
@@ -1392,9 +1461,11 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
struct asus_wmi *asus = dev_get_drvdata(dev->parent);
u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
- if (attr == &dev_attr_fan1_input.attr
+ if (attr == &dev_attr_pwm1.attr) {
+ if (asus->fan_type != FAN_TYPE_AGFN)
+ return 0;
+ } else if (attr == &dev_attr_fan1_input.attr
|| attr == &dev_attr_fan1_label.attr
- || attr == &dev_attr_pwm1.attr
|| attr == &dev_attr_pwm1_enable.attr) {
if (asus->fan_type == FAN_TYPE_NONE)
return 0;
@@ -1443,13 +1514,17 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
asus->fan_type = FAN_TYPE_NONE;
asus->agfn_pwm = -1;
- if (asus_wmi_has_agfn_fan(asus)) {
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL))
+ asus->fan_type = FAN_TYPE_SPEC83;
+ else if (asus_wmi_has_agfn_fan(asus))
asus->fan_type = FAN_TYPE_AGFN;
- asus_fan_set_auto(asus);
- asus->fan_pwm_mode = ASUS_FAN_CTRL_AUTO;
- }
- return asus->fan_type != FAN_TYPE_NONE;
+ if (asus->fan_type == FAN_TYPE_NONE)
+ return -ENODEV;
+
+ asus_fan_set_auto(asus);
+ asus->fan_pwm_mode = ASUS_FAN_CTRL_AUTO;
+ return 0;
}
/* Fan mode *******************************************************************/
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 5ae9c062a1f6..409e16064f4b 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -73,6 +73,7 @@
/* Fan, Thermal */
#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */
+#define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013
/* Power */
#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012