From patchwork Mon Jul 15 06:54:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Drake X-Patchwork-Id: 11043411 X-Patchwork-Delegate: andy.shevchenko@gmail.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F25BE159A for ; Mon, 15 Jul 2019 06:54:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DCC7426B39 for ; Mon, 15 Jul 2019 06:54:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D092526E16; Mon, 15 Jul 2019 06:54:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D3C9F26B39 for ; Mon, 15 Jul 2019 06:54:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726074AbfGOGyr (ORCPT ); Mon, 15 Jul 2019 02:54:47 -0400 Received: from mail-pl1-f196.google.com ([209.85.214.196]:45754 "EHLO mail-pl1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725787AbfGOGyr (ORCPT ); Mon, 15 Jul 2019 02:54:47 -0400 Received: by mail-pl1-f196.google.com with SMTP id y8so7781770plr.12 for ; Sun, 14 Jul 2019 23:54:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=endlessm-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=h6E0WEH85Y5OoamrCg+T5XsVIDjDKRuLjdGem2CNSus=; b=jXALk52DuxM7mXuDYMNUtySgBCn3PGdK9br2dSKf/yjnXW8V3swXMKtapkvafyiEtn fbXmFloLE46CZw2vXV3M7B3piLlq7OeR/Z9QDxti1PAc6QjtZcuBtDRiTvZD47xFGMgg rgzhTHGRuJPvjgR23PLD2fWqIAqQcmrNWCIjrG0igWSRo9U/2KFb+g3g7E2Uo5zDDzL4 xfTZYhk+ZBD3/b8lh0JBjGHcudLVknXwonm8ZpEzgBRULHPNd+YR7chWKSq2CpTAEmBI PpFs53hEYmumUrn8NCwmzOW7t6wE1f+6aH4iHgCYCJv8UA/i7IUEePsWhLFOR6u922fy oGkQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=h6E0WEH85Y5OoamrCg+T5XsVIDjDKRuLjdGem2CNSus=; b=Lpe53fUzPUeWkm/kXCC+MHoUmRaCVazoe4JGlfM7w6dSxSlX8JNUN185VXYaZiJIkH kiVHZweBuN0AcHGFzo6IhmGaHJqj03EavwOwdn4TamJA39XjBjKFQIBmqJiaQjXuP9A9 FEvGFvsHV3gPTaBbQclvge52G6Ly1ia5opNxnpeuPMfXmQMpdN5CP5PSDpXwOGBDmfYp XDPJSHfZ+ZCHyFz9I1kt0oXAZTAgEAPP75tzdpYBUVMpREKU7eblvYUiFgMSDQzyZYwl x+UuHZIVmYuEYgH0iD/9VbNmRfNglS7Aq9HqnbzkjuV7ctet2dsyXQuwAsbf/neoVvN/ 1uog== X-Gm-Message-State: APjAAAUjfaQqS56YaDW2HmijnlVk+m5hBpdn3RWbdpYtMh0TI65v9hW1 Bl8PGqbTsnZQlFlyWbOa3nlNqQ== X-Google-Smtp-Source: APXvYqwiJ8QsTsbthgSjbi6M+9zDuEiZXcL1wORDkmcKnowTNg1zoDte1XbyOZm0NA18QVollbB5sw== X-Received: by 2002:a17:902:2b8a:: with SMTP id l10mr26529391plb.283.1563173685418; Sun, 14 Jul 2019 23:54:45 -0700 (PDT) Received: from limbo.local (123-204-46-122.static.seed.net.tw. [123.204.46.122]) by smtp.gmail.com with ESMTPSA id y22sm19183257pfo.39.2019.07.14.23.54.42 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Sun, 14 Jul 2019 23:54:44 -0700 (PDT) From: Daniel Drake To: corentin.chary@gmail.com, dvhart@infradead.org, andy@infradead.org Cc: platform-driver-x86@vger.kernel.org, yurii.pavlovskyi@gmail.com, linux@endlessm.com Subject: [PATCH 1/3] platform/x86: asus: cleanup AGFN fan handling Date: Mon, 15 Jul 2019 14:54:37 +0800 Message-Id: <20190715065439.27159-1-drake@endlessm.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The asus-wmi driver currently uses the "AGFN" interface and the FAN_CTRL device for fan control. According to the spec, this interface is very dated and marked as pending removal from products currently in development. Clean up the way that the AGFN fan is detected and handled, also preparing the driver for the introduction of an alternate fan control method needed to support recent Asus products. Not anticipating further development of this interface, simplify the code by dropping any notion of being able to control multiple AGFN fans (this was already limited to just a single fan through only exposing a single fan in sysfs). Check for the presence of AGFN fans at probe time, simplifying the code flow in asus_hwmon_sysfs_is_visible(). Signed-off-by: Daniel Drake --- drivers/platform/x86/asus-wmi.c | 238 +++++++++------------ include/linux/platform_data/x86/asus-wmi.h | 4 +- 2 files changed, 109 insertions(+), 133 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 65ce96dffdb1..0a1410ea2250 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -78,6 +78,8 @@ MODULE_LICENSE("GPL"); #define ASUS_FAN_MFUN 0x13 #define ASUS_FAN_SFUN_READ 0x06 #define ASUS_FAN_SFUN_WRITE 0x07 + +/* Based on standard hwmon pwmX_enable values */ #define ASUS_FAN_CTRL_MANUAL 1 #define ASUS_FAN_CTRL_AUTO 2 @@ -133,7 +135,7 @@ struct agfn_args { } __packed; /* struct used for calling fan read and write methods */ -struct fan_args { +struct agfn_fan_args { struct agfn_args agfn; /* common fields */ u8 fan; /* fan number: 0: set auto mode 1: 1st fan */ u32 speed; /* read: RPM/100 - write: 0-255 */ @@ -161,6 +163,11 @@ struct asus_rfkill { u32 dev_id; }; +enum fan_type { + FAN_TYPE_NONE = 0, + FAN_TYPE_AGFN, /* deprecated on newer platforms */ +}; + struct asus_wmi { int dsts_id; int spec; @@ -191,9 +198,9 @@ struct asus_wmi { struct asus_rfkill gps; struct asus_rfkill uwb; - bool asus_hwmon_fan_manual_mode; - int asus_hwmon_num_fans; - int asus_hwmon_pwm; + enum fan_type fan_type; + int fan_pwm_mode; + int agfn_pwm; bool fan_boost_mode_available; u8 fan_boost_mode_mask; @@ -1139,10 +1146,10 @@ static void asus_wmi_set_als(void) /* Hwmon device ***************************************************************/ -static int asus_hwmon_agfn_fan_speed_read(struct asus_wmi *asus, int fan, +static int asus_agfn_fan_speed_read(struct asus_wmi *asus, int fan, int *speed) { - struct fan_args args = { + struct agfn_fan_args args = { .agfn.len = sizeof(args), .agfn.mfun = ASUS_FAN_MFUN, .agfn.sfun = ASUS_FAN_SFUN_READ, @@ -1166,10 +1173,10 @@ static int asus_hwmon_agfn_fan_speed_read(struct asus_wmi *asus, int fan, return 0; } -static int asus_hwmon_agfn_fan_speed_write(struct asus_wmi *asus, int fan, +static int asus_agfn_fan_speed_write(struct asus_wmi *asus, int fan, int *speed) { - struct fan_args args = { + struct agfn_fan_args args = { .agfn.len = sizeof(args), .agfn.mfun = ASUS_FAN_MFUN, .agfn.sfun = ASUS_FAN_SFUN_WRITE, @@ -1189,7 +1196,7 @@ static int asus_hwmon_agfn_fan_speed_write(struct asus_wmi *asus, int fan, return -ENXIO; if (speed && fan == 1) - asus->asus_hwmon_pwm = *speed; + asus->agfn_pwm = *speed; return 0; } @@ -1198,87 +1205,75 @@ static int asus_hwmon_agfn_fan_speed_write(struct asus_wmi *asus, int fan, * Check if we can read the speed of one fan. If true we assume we can also * control it. */ -static int asus_hwmon_get_fan_number(struct asus_wmi *asus, int *num_fans) +static bool asus_wmi_has_agfn_fan(struct asus_wmi *asus) { int status; - int speed = 0; + int speed; + u32 value; - *num_fans = 0; + status = asus_agfn_fan_speed_read(asus, 1, &speed); + if (status != 0) + return false; - status = asus_hwmon_agfn_fan_speed_read(asus, 1, &speed); - if (!status) - *num_fans = 1; + status = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); + if (status != 0) + return false; - return 0; + /* + * We need to find a better way, probably using sfun, + * bits or spec ... + * Currently we disable it if: + * - ASUS_WMI_UNSUPPORTED_METHOD is returned + * - reverved bits are non-zero + * - sfun and presence bit are not set + */ + return !(value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 + || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))); } -static int asus_hwmon_fan_set_auto(struct asus_wmi *asus) +static int asus_fan_set_auto(struct asus_wmi *asus) { int status; - status = asus_hwmon_agfn_fan_speed_write(asus, 0, NULL); + status = asus_agfn_fan_speed_write(asus, 0, NULL); if (status) return -ENXIO; - asus->asus_hwmon_fan_manual_mode = false; - return 0; } -static int asus_hwmon_fan_rpm_show(struct device *dev, int fan) +static ssize_t pwm1_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct asus_wmi *asus = dev_get_drvdata(dev); - int value; - int ret; - - /* no speed readable on manual mode */ - if (asus->asus_hwmon_fan_manual_mode) - return -ENXIO; - - ret = asus_hwmon_agfn_fan_speed_read(asus, fan+1, &value); - if (ret) { - pr_warn("reading fan speed failed: %d\n", ret); - return -ENXIO; - } - - return value; -} - -static void asus_hwmon_pwm_show(struct asus_wmi *asus, int fan, int *value) -{ int err; + int value; - if (asus->asus_hwmon_pwm >= 0) { - *value = asus->asus_hwmon_pwm; - return; - } + /* If we already set a value then just return it */ + if (asus->agfn_pwm >= 0) + return sprintf(buf, "%d\n", asus->agfn_pwm); - err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, value); + /* + * If we haven't set already set a value through the AGFN interface, + * we read a current value through the (now-deprecated) FAN_CTRL device. + */ + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); if (err < 0) - return; + return err; - *value &= 0xFF; - - if (*value == 1) /* Low Speed */ - *value = 85; - else if (*value == 2) - *value = 170; - else if (*value == 3) - *value = 255; - else if (*value) { - pr_err("Unknown fan speed %#x\n", *value); - *value = -1; + value &= 0xFF; + + if (value == 1) /* Low Speed */ + value = 85; + else if (value == 2) + value = 170; + else if (value == 3) + value = 255; + else if (value) { + pr_err("Unknown fan speed %#x\n", value); + value = -1; } -} - -static ssize_t pwm1_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct asus_wmi *asus = dev_get_drvdata(dev); - int value; - - asus_hwmon_pwm_show(asus, 0, &value); return sprintf(buf, "%d\n", value); } @@ -1298,11 +1293,11 @@ static ssize_t pwm1_store(struct device *dev, value = clamp(value, 0, 255); - state = asus_hwmon_agfn_fan_speed_write(asus, 1, &value); + state = asus_agfn_fan_speed_write(asus, 1, &value); if (state) pr_warn("Setting fan speed failed: %d\n", state); else - asus->asus_hwmon_fan_manual_mode = true; + asus->fan_pwm_mode = ASUS_FAN_CTRL_MANUAL; return count; } @@ -1311,10 +1306,21 @@ static ssize_t fan1_input_show(struct device *dev, struct device_attribute *attr, char *buf) { - int value = asus_hwmon_fan_rpm_show(dev, 0); + struct asus_wmi *asus = dev_get_drvdata(dev); + int value; + int ret; - return sprintf(buf, "%d\n", value < 0 ? -1 : value*100); + /* 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; + } + return sprintf(buf, "%d\n", value < 0 ? -1 : value*100); } static ssize_t pwm1_enable_show(struct device *dev, @@ -1323,10 +1329,7 @@ static ssize_t pwm1_enable_show(struct device *dev, { struct asus_wmi *asus = dev_get_drvdata(dev); - if (asus->asus_hwmon_fan_manual_mode) - return sprintf(buf, "%d\n", ASUS_FAN_CTRL_MANUAL); - - return sprintf(buf, "%d\n", ASUS_FAN_CTRL_AUTO); + return sprintf(buf, "%d\n", asus->fan_pwm_mode); } static ssize_t pwm1_enable_store(struct device *dev, @@ -1343,14 +1346,21 @@ static ssize_t pwm1_enable_store(struct device *dev, if (ret) return ret; - if (state == ASUS_FAN_CTRL_MANUAL) - asus->asus_hwmon_fan_manual_mode = true; - else - status = asus_hwmon_fan_set_auto(asus); + switch (state) { + case ASUS_FAN_CTRL_MANUAL: + break; - if (status) - return status; + case ASUS_FAN_CTRL_AUTO: + status = asus_fan_set_auto(asus); + if (status) + return status; + break; + default: + return -EINVAL; + } + + asus->fan_pwm_mode = state; return count; } @@ -1404,59 +1414,31 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, struct device *dev = container_of(kobj, struct device, kobj); struct platform_device *pdev = to_platform_device(dev->parent); struct asus_wmi *asus = platform_get_drvdata(pdev); - int dev_id = -1; - int fan_attr = -1; u32 value = ASUS_WMI_UNSUPPORTED_METHOD; - bool ok = true; - - if (attr == &dev_attr_pwm1.attr) - dev_id = ASUS_WMI_DEVID_FAN_CTRL; - else if (attr == &dev_attr_temp1_input.attr) - dev_id = ASUS_WMI_DEVID_THERMAL_CTRL; - if (attr == &dev_attr_fan1_input.attr || attr == &dev_attr_fan1_label.attr || attr == &dev_attr_pwm1.attr || attr == &dev_attr_pwm1_enable.attr) { - fan_attr = 1; - } - - if (dev_id != -1) { - int err = asus_wmi_get_devstate(asus, dev_id, &value); + if (asus->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, + &value); - if (err < 0 && fan_attr == -1) + if (err < 0) return 0; /* can't return negative here */ - } - if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) { - /* - * We need to find a better way, probably using sfun, - * bits or spec ... - * Currently we disable it if: - * - ASUS_WMI_UNSUPPORTED_METHOD is returned - * - reverved bits are non-zero - * - sfun and presence bit are not set - */ - if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 - || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) - ok = false; - else - ok = fan_attr <= asus->asus_hwmon_num_fans; - } else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) { /* * If the temperature value in deci-Kelvin is near the absolute * zero temperature, something is clearly wrong */ if (value == 0 || value == 1) - ok = false; - } else if (fan_attr <= asus->asus_hwmon_num_fans && fan_attr != -1) { - ok = true; - } else { - ok = false; + return 0; } - return ok ? attr->mode : 0; + return attr->mode; } static const struct attribute_group hwmon_attribute_group = { @@ -1482,21 +1464,16 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus) static int asus_wmi_fan_init(struct asus_wmi *asus) { - int status; - - asus->asus_hwmon_pwm = -1; - asus->asus_hwmon_num_fans = -1; - asus->asus_hwmon_fan_manual_mode = false; + asus->fan_type = FAN_TYPE_NONE; + asus->agfn_pwm = -1; - status = asus_hwmon_get_fan_number(asus, &asus->asus_hwmon_num_fans); - if (status) { - asus->asus_hwmon_num_fans = 0; - pr_warn("Could not determine number of fans: %d\n", status); - return -ENXIO; + 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; } - pr_info("Number of fans: %d\n", asus->asus_hwmon_num_fans); - return 0; + return asus->fan_type != FAN_TYPE_NONE; } /* Fan mode *******************************************************************/ @@ -2348,7 +2325,6 @@ static int asus_wmi_add(struct platform_device *pdev) goto fail_input; err = asus_wmi_fan_init(asus); /* probably no problems on error */ - asus_hwmon_fan_set_auto(asus); err = asus_wmi_hwmon_init(asus); if (err) @@ -2440,7 +2416,7 @@ static int asus_wmi_remove(struct platform_device *device) asus_wmi_rfkill_exit(asus); asus_wmi_debugfs_exit(asus); asus_wmi_sysfs_exit(asus->platform_device); - asus_hwmon_fan_set_auto(asus); + asus_fan_set_auto(asus); kfree(asus); return 0; diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 4802cd2c7309..5ae9c062a1f6 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -12,7 +12,7 @@ #define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */ #define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */ #define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */ -#define ASUS_WMI_METHODID_AGFN 0x4E464741 /* FaN? */ +#define ASUS_WMI_METHODID_AGFN 0x4E464741 /* Atk Generic FuNction */ #define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */ #define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */ #define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */ @@ -72,7 +72,7 @@ /* Fan, Thermal */ #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 -#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 +#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */ /* Power */ #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 From patchwork Mon Jul 15 06:54:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Drake X-Patchwork-Id: 11043409 X-Patchwork-Delegate: andy.shevchenko@gmail.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 906AD13B1 for ; Mon, 15 Jul 2019 06:54:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 76B3526D08 for ; Mon, 15 Jul 2019 06:54:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6A7C226E1A; Mon, 15 Jul 2019 06:54:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0D5BB26D08 for ; Mon, 15 Jul 2019 06:54:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726075AbfGOGys (ORCPT ); Mon, 15 Jul 2019 02:54:48 -0400 Received: from mail-pf1-f193.google.com ([209.85.210.193]:38569 "EHLO mail-pf1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725787AbfGOGys (ORCPT ); Mon, 15 Jul 2019 02:54:48 -0400 Received: by mail-pf1-f193.google.com with SMTP id y15so6963804pfn.5 for ; Sun, 14 Jul 2019 23:54:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=endlessm-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=IM6Br9LwmV7TwM7Dv5wfYnH9fPYtAwKNqtfCQO/JrmA=; b=y/iyaibFDd8ipuYBDuBbqO4prxbQb1K/zdpSq75sgPuMnI+4ManODSKsLdo2wRV7Rg 2GGEgKSwphdwBDuxr4YO9RDFryXmtf+Bnl1YmMOoBVaxgIsAB9UxGMYxCSnj4epzhmp4 8kzV69cP8JfhcyjtvPhajsUCgjyl9Nzt4W92Er9KROXoM9dY3dSXskDE/AOg5D0sRRFu Dty3DlRY1A7wQYtOP1ARI3We6V6kVMezaVLVn+YfO1kmu78rwwrpDErDGcE8sbWJgKud 5kmTNNxL0zW12nW61u7WPbC5ilmVrc+5AuhhJFKa8zVqEjiDR/mEonOW3/8IbLMpLlu0 40Lw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=IM6Br9LwmV7TwM7Dv5wfYnH9fPYtAwKNqtfCQO/JrmA=; b=Xzq46ZswPQhsMyhB1qzlHCzaz+8UJBgGc7ibSAJ/iUOjCh7PjvbMvxysbHOp77qqLS 745uixAtym9D7+h7Y/uWbPQZ9J5epqoCS+b+jnWiLtsmh6TxLSnt/sD1ODJSQ54VfVRV WxIv8eevuub6I3jaxkYcej+K93M//vRstUozknIh9ckmb9pMld3WTipf7j40WIPhhyIH 2oRfjaWqLJSjLaWrCiB3QRqUXU3D5RCHWWFxbEeHtNq+H/Y7AzfOo1IMy6uDe/+u/KhF Cif8g11uV1BSKcYfdj9vvlKFrI/1jwwfrBA9scJxIvy6kWEZwuffh4uaM+BLukI1gGX7 7H+Q== X-Gm-Message-State: APjAAAUChoZfVk7spbInJXL4kvyan1wq57PGdWlTbOegObTmO8ocGZ66 um9tr862wUaxjhOh693S4n24Qw== X-Google-Smtp-Source: APXvYqx4fjduQ11SOyGSrllFGISj9wIjx7vupiK/kgo+l+p6P23v/RVuk6nrkjO6MqkU1abAmMKlJw== X-Received: by 2002:a63:6507:: with SMTP id z7mr24142342pgb.186.1563173687865; Sun, 14 Jul 2019 23:54:47 -0700 (PDT) Received: from limbo.local (123-204-46-122.static.seed.net.tw. [123.204.46.122]) by smtp.gmail.com with ESMTPSA id y22sm19183257pfo.39.2019.07.14.23.54.45 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Sun, 14 Jul 2019 23:54:47 -0700 (PDT) From: Daniel Drake To: corentin.chary@gmail.com, dvhart@infradead.org, andy@infradead.org Cc: platform-driver-x86@vger.kernel.org, yurii.pavlovskyi@gmail.com, linux@endlessm.com Subject: [PATCH 2/3] platform/x86: asus: add a helper for device presence Date: Mon, 15 Jul 2019 14:54:38 +0800 Message-Id: <20190715065439.27159-2-drake@endlessm.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190715065439.27159-1-drake@endlessm.com> References: <20190715065439.27159-1-drake@endlessm.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Factor out the WLAN LED and lightbar LED presence checks into a helper function, which will also be used by the upcoming CPU fan device support. Signed-off-by: Daniel Drake --- drivers/platform/x86/asus-wmi.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 0a1410ea2250..6925b2102f94 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -372,6 +372,14 @@ static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) ASUS_WMI_DSTS_STATUS_BIT); } +static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id) +{ + u32 retval; + int status = asus_wmi_get_devstate(asus, dev_id, &retval); + + return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT); +} + /* LEDs ***********************************************************************/ /* @@ -517,15 +525,6 @@ static int wlan_led_unknown_state(struct asus_wmi *asus) return result & ASUS_WMI_DSTS_UNKNOWN_BIT; } -static int wlan_led_presence(struct asus_wmi *asus) -{ - u32 result; - - asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result); - - return result & ASUS_WMI_DSTS_PRESENCE_BIT; -} - static void wlan_led_update(struct work_struct *work) { int ctrl_param; @@ -592,15 +591,6 @@ static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev) return result & ASUS_WMI_DSTS_LIGHTBAR_MASK; } -static int lightbar_led_presence(struct asus_wmi *asus) -{ - u32 result; - - asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result); - - return result & ASUS_WMI_DSTS_PRESENCE_BIT; -} - static void asus_wmi_led_exit(struct asus_wmi *asus) { if (!IS_ERR_OR_NULL(asus->kbd_led.dev)) @@ -651,7 +641,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus) goto error; } - if (wlan_led_presence(asus) && (asus->driver->quirks->wapf > 0)) { + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_WIRELESS_LED) + && (asus->driver->quirks->wapf > 0)) { INIT_WORK(&asus->wlan_led_work, wlan_led_update); asus->wlan_led.name = "asus::wlan"; @@ -668,7 +659,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus) goto error; } - if (lightbar_led_presence(asus)) { + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_LIGHTBAR)) { INIT_WORK(&asus->lightbar_led_work, lightbar_led_update); asus->lightbar_led.name = "asus::lightbar"; From patchwork Mon Jul 15 06:54:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Drake X-Patchwork-Id: 11043413 X-Patchwork-Delegate: andy.shevchenko@gmail.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DF3D3138D for ; Mon, 15 Jul 2019 06:54:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CE54F26B39 for ; Mon, 15 Jul 2019 06:54:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C294626E16; Mon, 15 Jul 2019 06:54:53 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2E37926B39 for ; Mon, 15 Jul 2019 06:54:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726425AbfGOGyx (ORCPT ); Mon, 15 Jul 2019 02:54:53 -0400 Received: from mail-pf1-f196.google.com ([209.85.210.196]:36635 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725787AbfGOGyw (ORCPT ); Mon, 15 Jul 2019 02:54:52 -0400 Received: by mail-pf1-f196.google.com with SMTP id r7so6963890pfl.3 for ; Sun, 14 Jul 2019 23:54:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=endlessm-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3eQ+ggCZRdBKqPSgoQ3LMIrmfuag6XQ/FmFnMC/2Jg8=; b=D7EH7vvK2srnTdwb0NZ2SH0ObAGd0YJ1BaXsdV1oIpKg9Y13LqSQxkAvQ0EDNKJANH sHS2LCVjNVmJF0H0Z9EMrWvPzCahF7cmtLsKyUDapuqjd6vSydaIRFh2y9QYCdg/ek0i hevyG8uGTPT1On02j9MT+AncRQz7KwjD1pt+oU0UIsHYRx4NlFAiVpjXCyb2/bcYAX4E eMvP8vnspHpyNA9hr+7Hosd9mHllh9LNC/Vot7B7K/NohWCHrx371mo8PyKRc1y+QvwN LJVF1Bm1pzW/8rE7lCWeiyMeBM/QMGHkbNQ3q6jJjvDpscHMf5QBNlaD3aOlE7YHX4Df EQlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3eQ+ggCZRdBKqPSgoQ3LMIrmfuag6XQ/FmFnMC/2Jg8=; b=RIJdXclvrW1Z636hOuENJy/dM4m+ecWlkZw47zrqPXPMzVLDTdr1VPSnMBT4LItino ZGDPTGTtklc6x5KUrrqpvGPJC4bqaoRrQ0zjUUCztpEYKYXOIM1hcvi51L+91IGLULzm p7qLwdLrC6NZC3tnqtgWgRJh/DzsZUUqpS66Gg5d6+ufrZucyKn8fBIXVRxTNyXZyNf6 n1B1NGY1nHxi3R0OBFc8GQ85jV78VxeQqyq70JN5gvfQG+Xecwt7k6YXHZUBvz/RqPV3 AfrD6MlRJjYttuXL/sXBZMSF21toMifFSfyGHMyCxdrngo6LbnR2xd479rrscgTihE/A x+MA== X-Gm-Message-State: APjAAAWRVgfY8+ujmFNjgDur2BEH2tEsgippZStw4k6g7tu0YSq3PdFW UrnVY+9KhO19ZHwncF+m/maKEw== X-Google-Smtp-Source: APXvYqx5NozAlOMoCgKxElNo6eUJJpvz9vbkDR0omin9QSgNs9e6H0U7yxoZ6MNteRHhDzWVywywqw== X-Received: by 2002:a63:24a:: with SMTP id 71mr831060pgc.273.1563173691755; Sun, 14 Jul 2019 23:54:51 -0700 (PDT) Received: from limbo.local (123-204-46-122.static.seed.net.tw. [123.204.46.122]) by smtp.gmail.com with ESMTPSA id y22sm19183257pfo.39.2019.07.14.23.54.48 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Sun, 14 Jul 2019 23:54:51 -0700 (PDT) From: Daniel Drake To: corentin.chary@gmail.com, dvhart@infradead.org, andy@infradead.org Cc: platform-driver-x86@vger.kernel.org, yurii.pavlovskyi@gmail.com, linux@endlessm.com Subject: [PATCH 3/3] platform/x86: asus: fix CPU fan control on recent products Date: Mon, 15 Jul 2019 14:54:39 +0800 Message-Id: <20190715065439.27159-3-drake@endlessm.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190715065439.27159-1-drake@endlessm.com> References: <20190715065439.27159-1-drake@endlessm.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Previously, asus-wmi was using the AGFN interface and FAN_CTRL device for CPU fan control. However, this code has been found to be not fully working on some recent products, and having checked the spec, these interfaces are marked as being removed from future products currently in development. The replacement appears to be the CPU_FAN device, added in spec version 8.3 (March 2014) and present on many modern Asus laptops. Add support for this device, and use it whenever it is detected. The older approach based on AGFN and FAN_CTRL is used as a fallback on products that do not have such device. Other than switching between automatic and full speed, there is no fan speed control through this new interface. Signed-off-by: Daniel Drake --- drivers/platform/x86/asus-wmi.c | 125 ++++++++++++++++----- include/linux/platform_data/x86/asus-wmi.h | 1 + 2 files changed, 101 insertions(+), 25 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 6925b2102f94..28e79d1028c6 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -80,6 +80,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 @@ -166,6 +167,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 { @@ -1225,10 +1227,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; } @@ -1301,13 +1322,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; } @@ -1320,6 +1357,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); } @@ -1330,25 +1376,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; @@ -1407,9 +1476,11 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, struct asus_wmi *asus = platform_get_drvdata(pdev); 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; @@ -1458,13 +1529,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