From patchwork Tue Sep 27 20:45:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Armin Wolf X-Patchwork-Id: 12991383 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6BC3BC54EE9 for ; Tue, 27 Sep 2022 20:45:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231587AbiI0Upr (ORCPT ); Tue, 27 Sep 2022 16:45:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34964 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231707AbiI0Upq (ORCPT ); Tue, 27 Sep 2022 16:45:46 -0400 Received: from mout.gmx.net (mout.gmx.net [212.227.15.15]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 60EE572FDC; Tue, 27 Sep 2022 13:45:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1664311527; bh=/SX6Itfe956cQHBuREIX2bQWe53jniUVaVFpuVsRRzQ=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=M6gdcd9Dt3nK83sVaE8VkYBwLR21DP78olZXbSEVoEl7kCzurWG1f2pmBbYQVcK8A vzxUMI1NWof5j7TbdZDGamTN0HgBas6jFG1ibr569JDtKvgDKXicty0O7l5KMNenE2 Dt+nh3DSLwN1dhzvPnKZJiet7lslnaKm1xr5el4c= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from esprimo-mx.users.agdsn.de ([141.30.226.129]) by mail.gmx.net (mrgmx005 [212.227.17.190]) with ESMTPSA (Nemesis) id 1MUXtS-1olybO45IG-00QV1y; Tue, 27 Sep 2022 22:45:27 +0200 From: Armin Wolf To: hdegoede@redhat.com, markgross@kernel.org Cc: rafael@kernel.org, lenb@kernel.org, hmh@hmh.eng.br, matan@svgalib.org, corentin.chary@gmail.com, jeremy@system76.com, productdev@system76.com, mario.limonciello@amd.com, pobrn@protonmail.com, coproscefalo@gmail.com, platform-driver-x86@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/2] ACPI: battery: Pass battery hook pointer to hook callbacks Date: Tue, 27 Sep 2022 22:45:20 +0200 Message-Id: <20220927204521.601887-2-W_Armin@gmx.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220927204521.601887-1-W_Armin@gmx.de> References: <20220927204521.601887-1-W_Armin@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:rVigeiPzjmZrxqycybkalfTOJ7+raJLwpKF4shbsLG3Ga9N+PXE px1RplMzYVovOWpucS8W7iCIGuKptc+mKgt2g1NRE9T3Ff9N+ZzakZvSXjD7HWiRBkKQ+XG yZ27Y261Yym6FnFkoH32f2zX/hz7fU+eIKIqSuSslVuIeStPVPkJUJch2MzhrRGwaSMXfqZ ajeKiKaanGmj16xkl4nMA== X-UI-Out-Filterresults: notjunk:1;V03:K0:2pr/9gGwuGY=:Eowgf4KZ6NWnd1otXcUQfW VWOlkMkz9g9bulHPh3tIUWFvpRdwLYTNXrtpcB1rO2mZ+tOpqsrLthp7W9dRQG/TzxfkXuIb2 cvSJk85HWzl/EGxCiFdg2tHhBPFFD4GTi2HCP7tFOG6XN1z1PG/ChhXMYETr8PXledv23ldBt QtMQBx3dmGC/7oEyxl39ihbxsNLYdpFlRqjh4fPRW/XPD9DByIqUTBxiQvdB81MUV7xn5kP1o /9rRf6Oubq6cAuES1SMULhM/kagnR2ohc/cPsGjbaR4kDjUWSh89VCOfTBHOES6N5m6IJcGgc CA1oDWGlMaDDrZc6XeN8Y2E1rbe1EWmQ4kpkumutodA/O5nI/xFKr6AIliIJ7ooXGqwh2yZOr jM+OG+CkLC4SjTJBk+tx60WyfVTYYJweRNz21VWEizd2jqVsvWymxRoLcWeBarb03tl4pUx0w qkIWL7EUC3OOcRjMYjyK56f/nhHz6qsU/tPRt87ploZDmH33isQcJebO9SzudRz9tqCKXdfVy 08bDA8tr+OxsyiSy4WAiXaPgHMGemnkmx+gBvoXf18gTvK7edZcBcPgPT6AScTu9jyoKPqM68 QmKhcOGkIBQ7mT32b1XTy2VY6tSkowK2X2i0EA5uSD+AJZqBIa/aJM06dtLxTW4q9U2pIAwnL stV09m0AspiB4X5OTU54kl9QAuRR6+kDnFOpSNE0u+DtmgTB/0XQNykytG8Cp6efcZAxS7mbR QH6zKl0PltJhkB2KtFVZ8IHpZwYCSzJ3DQMQyva+tqX/mWrt2vQpp4XQ5Ivg+hZcxeiuqGghg qcrSgSK8LHYiQB4zDtwcazvMgrMhLdY/O1j2l9wT3vtdebm6VGaX1o8PU/lurppCVVaZlgK+Q MMM+Mxgmc7vS0O4l8cmXPxSLIPeWNhSk3lxbsP4/0PgKFW9EbOETBLb0TOJBiH4NrfSXeDa85 GjekejTm/dAt2DLjnSM8WU2450t5BM4Po0N1Sv2hv6VIETGqSXmfJOoIOkPgu08h+jwZcwD1C Yf5d7HXNHNviDmGOgPyDPoXorD+EfSUf7ZeK8lXa5nvaTVt69GaP99mkHz1cuMbTDlpcWDsZd FUrss6RWAsSwJPMt/MEkITQU4GDlMKOTIkTJNMI8JBnGIZIf9Fw7HDUsOcBX+knJi7H+E9JRX jONgJyodGmwYGBcyKr+hmkuJ3A Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Right now, is impossible for battery hook callbacks to access instance-specific data, forcing most drivers to provide some sort of global state. This however is difficult for drivers which can be instantiated multiple times and/or are hotplug-capable. Pass a pointer to the batetry hook to those callbacks for usage with container_of(). Signed-off-by: Armin Wolf Acked-by: Rafael J. Wysocki --- drivers/acpi/battery.c | 8 ++++---- drivers/platform/x86/asus-wmi.c | 4 ++-- drivers/platform/x86/huawei-wmi.c | 4 ++-- drivers/platform/x86/lg-laptop.c | 4 ++-- drivers/platform/x86/system76_acpi.c | 4 ++-- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- drivers/platform/x86/toshiba_acpi.c | 4 ++-- include/acpi/battery.h | 4 ++-- 8 files changed, 18 insertions(+), 18 deletions(-) -- 2.30.2 diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 306513fec1e1..9482b0b6eadc 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -696,7 +696,7 @@ static void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock) if (lock) mutex_lock(&hook_mutex); list_for_each_entry(battery, &acpi_battery_list, list) { - hook->remove_battery(battery->bat); + hook->remove_battery(battery->bat, hook); } list_del(&hook->list); if (lock) @@ -724,7 +724,7 @@ void battery_hook_register(struct acpi_battery_hook *hook) * its attributes. */ list_for_each_entry(battery, &acpi_battery_list, list) { - if (hook->add_battery(battery->bat)) { + if (hook->add_battery(battery->bat, hook)) { /* * If a add-battery returns non-zero, * the registration of the extension has failed, @@ -762,7 +762,7 @@ static void battery_hook_add_battery(struct acpi_battery *battery) * during the battery module initialization. */ list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) { - if (hook_node->add_battery(battery->bat)) { + if (hook_node->add_battery(battery->bat, hook_node)) { /* * The notification of the extensions has failed, to * prevent further errors we will unload the extension. @@ -785,7 +785,7 @@ static void battery_hook_remove_battery(struct acpi_battery *battery) * custom attributes from the battery. */ list_for_each_entry(hook, &battery_hook_list, list) { - hook->remove_battery(battery->bat); + hook->remove_battery(battery->bat, hook); } /* Then, just remove the battery from the list */ list_del(&battery->list); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ae46af731de9..446669d11095 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -882,7 +882,7 @@ static ssize_t charge_control_end_threshold_show(struct device *device, static DEVICE_ATTR_RW(charge_control_end_threshold); -static int asus_wmi_battery_add(struct power_supply *battery) +static int asus_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { /* The WMI method does not provide a way to specific a battery, so we * just assume it is the first battery. @@ -909,7 +909,7 @@ static int asus_wmi_battery_add(struct power_supply *battery) return 0; } -static int asus_wmi_battery_remove(struct power_supply *battery) +static int asus_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold); diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c index eac3e6b4ea11..1dec4427053a 100644 --- a/drivers/platform/x86/huawei-wmi.c +++ b/drivers/platform/x86/huawei-wmi.c @@ -468,7 +468,7 @@ static DEVICE_ATTR_RW(charge_control_start_threshold); static DEVICE_ATTR_RW(charge_control_end_threshold); static DEVICE_ATTR_RW(charge_control_thresholds); -static int huawei_wmi_battery_add(struct power_supply *battery) +static int huawei_wmi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { int err = 0; @@ -483,7 +483,7 @@ static int huawei_wmi_battery_add(struct power_supply *battery) return err; } -static int huawei_wmi_battery_remove(struct power_supply *battery) +static int huawei_wmi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_file(&battery->dev, &dev_attr_charge_control_start_threshold); device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold); diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index 332868b140ed..d662b64b0ba9 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -546,7 +546,7 @@ static DEVICE_ATTR_RW(fn_lock); static DEVICE_ATTR_RW(charge_control_end_threshold); static DEVICE_ATTR_RW(battery_care_limit); -static int lg_battery_add(struct power_supply *battery) +static int lg_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { if (device_create_file(&battery->dev, &dev_attr_charge_control_end_threshold)) @@ -555,7 +555,7 @@ static int lg_battery_add(struct power_supply *battery) return 0; } -static int lg_battery_remove(struct power_supply *battery) +static int lg_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_file(&battery->dev, &dev_attr_charge_control_end_threshold); diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index 958df41ad509..9031bd53253f 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -254,7 +254,7 @@ static struct attribute *system76_battery_attrs[] = { ATTRIBUTE_GROUPS(system76_battery); -static int system76_battery_add(struct power_supply *battery) +static int system76_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { // System76 EC only supports 1 battery if (strcmp(battery->desc->name, "BAT0") != 0) @@ -266,7 +266,7 @@ static int system76_battery_add(struct power_supply *battery) return 0; } -static int system76_battery_remove(struct power_supply *battery) +static int system76_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_groups(&battery->dev, system76_battery_groups); return 0; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 8fbe21ebcc52..75ba9e61264e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9897,7 +9897,7 @@ ATTRIBUTE_GROUPS(tpacpi_battery); /* ACPI battery hooking */ -static int tpacpi_battery_add(struct power_supply *battery) +static int tpacpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { int batteryid = tpacpi_battery_get_id(battery->desc->name); @@ -9908,7 +9908,7 @@ static int tpacpi_battery_add(struct power_supply *battery) return 0; } -static int tpacpi_battery_remove(struct power_supply *battery) +static int tpacpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_groups(&battery->dev, tpacpi_battery_groups); return 0; diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 43cc25351aea..c8f01f8f435d 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -3113,7 +3113,7 @@ static struct attribute *toshiba_acpi_battery_attrs[] = { ATTRIBUTE_GROUPS(toshiba_acpi_battery); -static int toshiba_acpi_battery_add(struct power_supply *battery) +static int toshiba_acpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) { if (toshiba_acpi == NULL) { pr_err("Init order issue\n"); @@ -3126,7 +3126,7 @@ static int toshiba_acpi_battery_add(struct power_supply *battery) return 0; } -static int toshiba_acpi_battery_remove(struct power_supply *battery) +static int toshiba_acpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) { device_remove_groups(&battery->dev, toshiba_acpi_battery_groups); return 0; diff --git a/include/acpi/battery.h b/include/acpi/battery.h index b8d56b702c7a..611a2561a014 100644 --- a/include/acpi/battery.h +++ b/include/acpi/battery.h @@ -12,8 +12,8 @@ struct acpi_battery_hook { const char *name; - int (*add_battery)(struct power_supply *battery); - int (*remove_battery)(struct power_supply *battery); + int (*add_battery)(struct power_supply *battery, struct acpi_battery_hook *hook); + int (*remove_battery)(struct power_supply *battery, struct acpi_battery_hook *hook); struct list_head list; }; From patchwork Tue Sep 27 20:45:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Armin Wolf X-Patchwork-Id: 12991384 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 397B6C6FA82 for ; Tue, 27 Sep 2022 20:45:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232488AbiI0Upw (ORCPT ); Tue, 27 Sep 2022 16:45:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35236 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232261AbiI0Upu (ORCPT ); Tue, 27 Sep 2022 16:45:50 -0400 Received: from mout.gmx.net (mout.gmx.net [212.227.17.21]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0A9EAFF3C2; Tue, 27 Sep 2022 13:45:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1664311529; bh=G7ZbgOc4H7a8PLktj4EmRtojg+lQwmZ743trNDnHyCU=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=jocVMcQdqr+KWdt078ehSDb4xkwW1ZyJjQ6/O/CjFfGJc6pagnDE764tIKrHEuaVd Ljy2LJkoX9gZdbXqEwuN8seWkNm6k9TzrwIOck5pb99Sj6u60+08dnX3hEcNoO6gse +bC8wXlCpNfBT+U1yEUmy7DeI8nAvnte+fBTUAWI= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from esprimo-mx.users.agdsn.de ([141.30.226.129]) by mail.gmx.net (mrgmx105 [212.227.17.168]) with ESMTPSA (Nemesis) id 1Md6Mt-1pBnGE0rVj-00aCj5; Tue, 27 Sep 2022 22:45:29 +0200 From: Armin Wolf To: hdegoede@redhat.com, markgross@kernel.org Cc: rafael@kernel.org, lenb@kernel.org, hmh@hmh.eng.br, matan@svgalib.org, corentin.chary@gmail.com, jeremy@system76.com, productdev@system76.com, mario.limonciello@amd.com, pobrn@protonmail.com, coproscefalo@gmail.com, platform-driver-x86@vger.kernel.org, linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] platform/x86: dell: Add new dell-wmi-ddv driver Date: Tue, 27 Sep 2022 22:45:21 +0200 Message-Id: <20220927204521.601887-3-W_Armin@gmx.de> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220927204521.601887-1-W_Armin@gmx.de> References: <20220927204521.601887-1-W_Armin@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:i1hZZh1MrKRfJ/1k17iJIQ49w9XVfFPp5NiAm+EFQ/k8EEWKzQ3 6oQNv/aBnN46ieiOXag5exbKQydh255DuuzT66LiF/7eCEEGUGgTVTnxqU4bn4+F7YVqWVp KhB+KJiYPIgEodvrOszy/DV+eMkacmYHHEarNt4Smhd0xZvVp1g6oAr0syJl56QE5jJZE0A rvdipp/wV6PWs/YqBjpvQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:WpWGBr6PgcI=:jp7mwLQ3s4T3E6QA5ML9Vc TrxV4RA7vPJJROLSIXMP2MgOr6h/Ne8nPqKHRvg3TOTETucM9pySS0iHIRg+dqZIM/6Gs9+17 c8MryuzIDnyjq/rRemVOzdJIXHJPDV9iMGP/bV9mWdiin4u//Y7lk7EbpHJoD9ihJ2UT4+28A scXK1LvY2/MBr5DdP8OPmNwljEfLzCGYFaI1SLXiyGL0G/c7NZZ0yCGtFrghyMAfARfSkAu/w nqPzJRpV3SleqE7vap/0lxCPhbU8AXULyYOfOQUAhxJimb5WRT60+8b9VvaqSsgM2wHH5tjJI F5/sq9rq6fB5uHlKOLogl4Vb7dDwMhE4DiavHcGNZPodMWVFm3InCZEmP2xlBH+vOT9wJ/bFH l70gNkSPlFIB03Aenwh70qxGgfXttO9SbARnScQHN/w2tC+dGI5LFPW+Rx7xirCCJJaYXWSzP O6dr0MLFZ8RdS3ppLdiF+rgGEQB7yUbc85wZyV1RLPZA6i4tIqfDnUrBC9WtjmNzcXDh2szAj XkhEOcNDjmY2e6bDVVP8JUM3Z+2o1t3QtSvuhmWwz78N4ZKetmdnt/7DJNAjaPlQFwyi9cZ4p tWLYhBcndZU7aDVZUEB1gs6g53Q+QNNcNY745UjnuhhmqaOtkooHTgJljko47AVXT3BBK+yYH SS8kolsOKZZ2wCbiLQHvOg2zBdEp1iMUHMUiHVqMnAJKQPbY2e0dyJNqCgVaXpO4opkvoae5M +ehwSCu0XoVMG2+IB6WDZtbt+kxNobyIrinyhpSnNrBTUlUmsbVKQGC/HNctXAcD2VQGJ47M3 e6ftBfYpda147+yS5HUO3dAlN6CmzRIahjEdxa0dD1vxltMNH7NYjwjNJtOUOo3+VeOa/k6+O HX7/oFg6OboWIS6EwJP616rRY7djL/WtFORZ+OnVhw5zmuDLRTrh8s9l3TGZl8RkS8FG/6Y+9 8Z4Mt6tWU7EMhE2hyWamRzRS70SmKx62BcGRaJOWlXxdSznvdIdw9sQrRCz//63Yk99dQKlLk xIXEZDiYafd1zWVvrdSQZyZdypLhwN+8tGpd/MBS9YogiZ2IWEZkqV4o7XCblFrX++0fi5eQ6 2/sXJliFtCEltU8Wv7/VkQM2RzzyLbkraAPBsrjMNGxVHvYJFielw7nthrop9wbVSZZ/GHYhV BXgpBwynfU0g1d4P+7Zw0PiLEl Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org The dell-wmi-ddv driver adds support for reading the current temperature and ePPID of ACPI batteries on supported Dell machines. Since the WMI interface used by this driver does not do any input validation and thus cannot be used for probing, the driver depends on the ACPI battery extension machanism to discover batteries. The driver also supports a debugfs interface for retrieving buffers containing fan and thermal sensor information. Since the meaing of the content of those buffers is currently unknown, the interface is meant for reverse-engineering and will likely be replaced with an hwmon interface once the meaning has been understood. The driver was tested on a Dell Inspiron 3505. Signed-off-by: Armin Wolf --- .../ABI/testing/debugfs-dell-wmi-ddv | 21 + .../ABI/testing/sysfs-platform-dell-wmi-ddv | 7 + MAINTAINERS | 7 + drivers/platform/x86/dell/Kconfig | 13 + drivers/platform/x86/dell/Makefile | 1 + drivers/platform/x86/dell/dell-wmi-ddv.c | 361 ++++++++++++++++++ drivers/platform/x86/wmi.c | 1 + 7 files changed, 411 insertions(+) create mode 100644 Documentation/ABI/testing/debugfs-dell-wmi-ddv create mode 100644 Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv create mode 100644 drivers/platform/x86/dell/dell-wmi-ddv.c -- 2.30.2 diff --git a/Documentation/ABI/testing/debugfs-dell-wmi-ddv b/Documentation/ABI/testing/debugfs-dell-wmi-ddv new file mode 100644 index 000000000000..fbcc5d6f7388 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-dell-wmi-ddv @@ -0,0 +1,21 @@ +What: /sys/kernel/debug/dell-wmi-ddv-/fan_sensor_information +Date: September 2022 +KernelVersion: 6.1 +Contact: Armin Wolf +Description: + This file contains the contents of the fan sensor information buffer, + which contains fan sensor entries and a terminating character (0xFF). + + Each fan sensor entry consists of three bytes with an unknown meaning, + interested people may use this file for reverse-engineering. + +What: /sys/kernel/debug/dell-wmi-ddv-/thermal_sensor_information +Date: September 2022 +KernelVersion: 6.1 +Contact: Armin Wolf +Description: + This file contains the contents of the thermal sensor information buffer, + which contains thermal sensor entries and a terminating character (0xFF). + + Each thermal sensor entry consists of five bytes with an unknown meaning, + interested people may use this file for reverse-engineering. diff --git a/Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv b/Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv new file mode 100644 index 000000000000..1d97ad615c66 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv @@ -0,0 +1,7 @@ +What: /sys/class/power_supply//eppid +Date: September 2022 +KernelVersion: 6.1 +Contact: Armin Wolf +Description: + Reports the Dell ePPID (electronic Dell Piece Part Identification) + of the ACPI battery. diff --git a/MAINTAINERS b/MAINTAINERS index 6bb894ea4a77..d9fd4c9eebbc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5821,6 +5821,13 @@ L: Dell.Client.Kernel@dell.com S: Maintained F: drivers/platform/x86/dell/dell-wmi-descriptor.c +DELL WMI DDV DRIVER +M: Armin Wolf +S: Maintained +F: Documentation/ABI/testing/debugfs-dell-wmi-ddv +F: Documentation/ABI/testing/sysfs-platform-dell-wmi-ddv +F: drivers/platform/x86/dell/dell-wmi-ddv.c + DELL WMI SYSMAN DRIVER M: Divya Bharathi M: Prasanth Ksr diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index 25421e061c47..d319de8f2132 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -189,6 +189,19 @@ config DELL_WMI_DESCRIPTOR default n depends on ACPI_WMI +config DELL_WMI_DDV + tristate "Dell WMI sensors Support" + default m + depends on ACPI_BATTERY + depends on ACPI_WMI + help + This option adds support for WMI-based sensors like + battery temperature sensors found on some Dell notebooks. + It also supports reading of the battery ePPID. + + To compile this drivers as a module, choose M here: the module will + be called dell-wmi-ddv. + config DELL_WMI_LED tristate "External LED on Dell Business Netbooks" default m diff --git a/drivers/platform/x86/dell/Makefile b/drivers/platform/x86/dell/Makefile index ddba1df71e80..1b8942426622 100644 --- a/drivers/platform/x86/dell/Makefile +++ b/drivers/platform/x86/dell/Makefile @@ -19,5 +19,6 @@ dell-wmi-objs := dell-wmi-base.o dell-wmi-$(CONFIG_DELL_WMI_PRIVACY) += dell-wmi-privacy.o obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o obj-$(CONFIG_DELL_WMI_DESCRIPTOR) += dell-wmi-descriptor.o +obj-$(CONFIG_DELL_WMI_DDV) += dell-wmi-ddv.o obj-$(CONFIG_DELL_WMI_LED) += dell-wmi-led.o obj-$(CONFIG_DELL_WMI_SYSMAN) += dell-wmi-sysman/ diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c new file mode 100644 index 000000000000..6ccce90f475d --- /dev/null +++ b/drivers/platform/x86/dell/dell-wmi-ddv.c @@ -0,0 +1,361 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * dell-wmi-ddv.c -- Linux driver for WMI sensor information on Dell notebooks. + * + * Copyright (C) 2022 Armin Wolf + */ + +#define pr_format(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "dell-wmi-ddv" + +#define DELL_DDV_SUPPORTED_INTERFACE 2 +#define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608" + +enum dell_ddv_method { + DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01, + DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02, + DELL_DDV_BATTERY_MANUFACTURE_NAME = 0x03, + DELL_DDV_BATTERY_MANUFACTURE_DATE = 0x04, + DELL_DDV_BATTERY_SERIAL_NUMBER = 0x05, + DELL_DDV_BATTERY_CHEMISTRY_VALUE = 0x06, + DELL_DDV_BATTERY_TEMPERATURE = 0x07, + DELL_DDV_BATTERY_CURRENT = 0x08, + DELL_DDV_BATTERY_VOLTAGE = 0x09, + DELL_DDV_BATTERY_MANUFACTURER_ACCESS = 0x0A, + DELL_DDV_BATTERY_RELATIVE_CHARGE_STATE = 0x0B, + DELL_DDV_BATTERY_CYCLE_COUNT = 0x0C, + DELL_DDV_BATTERY_EPPID = 0x0D, + DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E, + DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F, + DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10, + + DELL_DDV_INTERFACE_VERSION = 0x12, + + DELL_DDV_FAN_SENSOR_INFORMATION = 0x20, + DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22, +}; + +struct dell_wmi_ddv_data { + struct acpi_battery_hook hook; + struct device_attribute temp_attr, eppid_attr; + struct wmi_device *wdev; +}; + +static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg, + union acpi_object **result, acpi_object_type type) +{ + struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; + const struct acpi_buffer in = { + .length = sizeof(arg), + .pointer = &arg, + }; + union acpi_object *obj; + acpi_status ret; + + ret = wmidev_evaluate_method(wdev, 0x0, method, &in, &out); + if (ACPI_FAILURE(ret)) + return -EIO; + + obj = out.pointer; + if (!obj) + return -ENODATA; + + if (obj->type != type) { + kfree(obj); + return -EIO; + } + + *result = obj; + + return 0; +} + +static int dell_wmi_ddv_query_integer(struct wmi_device *wdev, enum dell_ddv_method method, + u32 arg, u32 *res) +{ + union acpi_object *obj; + int ret; + + ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_INTEGER); + if (ret < 0) + return ret; + + if (obj->integer.value <= U32_MAX) + *res = (u32)obj->integer.value; + else + ret = -ERANGE; + + kfree(obj); + + return ret; +} + +static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_method method, + u32 arg, union acpi_object **result) +{ + union acpi_object *obj; + u64 buffer_size; + int ret; + + ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_PACKAGE); + if (ret < 0) + return ret; + + if (obj->package.count != 2) + goto err_free; + + if (obj->package.elements[0].type != ACPI_TYPE_INTEGER) + goto err_free; + + buffer_size = obj->package.elements[0].integer.value; + + if (obj->package.elements[1].type != ACPI_TYPE_BUFFER) + goto err_free; + + if (buffer_size != obj->package.elements[1].buffer.length) { + dev_warn(&wdev->dev, + FW_WARN "ACPI buffer size (%llu) does not match WMI buffer size (%d)\n", + buffer_size, obj->package.elements[1].buffer.length); + + goto err_free; + } + + *result = obj; + + return 0; + +err_free: + kfree(obj); + + return -EIO; +} + +static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method, + u32 arg, union acpi_object **result) +{ + return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING); +} + +static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index) +{ + const char *uid_str = acpi_device_uid(acpi_dev); + + if (!uid_str) + return -ENODEV; + + return kstrtou32(uid_str, 10, index); +} + +static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr); + u32 index, value; + int ret; + + ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index); + if (ret < 0) + return ret; + + ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value); + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", DIV_ROUND_CLOSEST(value, 10)); +} + +static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr); + union acpi_object *obj; + u32 index; + int ret; + + ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index); + if (ret < 0) + return ret; + + ret = dell_wmi_ddv_query_string(data->wdev, DELL_DDV_BATTERY_EPPID, index, &obj); + if (ret < 0) + return ret; + + ret = sysfs_emit(buf, "%s\n", obj->string.pointer); + + kfree(obj); + + return ret; +} + +static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); + u32 index; + int ret; + + /* Return 0 instead of error to avoid being unloaded */ + ret = dell_wmi_ddv_battery_index(to_acpi_device(battery->dev.parent), &index); + if (ret < 0) + return 0; + + ret = device_create_file(&battery->dev, &data->temp_attr); + if (ret < 0) + return ret; + + ret = device_create_file(&battery->dev, &data->eppid_attr); + if (ret < 0) { + device_remove_file(&battery->dev, &data->temp_attr); + + return ret; + } + + return 0; +} + +static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook) +{ + struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook); + + device_remove_file(&battery->dev, &data->temp_attr); + device_remove_file(&battery->dev, &data->eppid_attr); + + return 0; +} + +static void dell_wmi_ddv_battery_remove(void *data) +{ + struct acpi_battery_hook *hook = data; + + battery_hook_unregister(hook); +} + +static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data) +{ + data->hook.name = "Dell DDV Battery Extension"; + data->hook.add_battery = dell_wmi_ddv_add_battery; + data->hook.remove_battery = dell_wmi_ddv_remove_battery; + + sysfs_attr_init(&data->temp_attr.attr); + data->temp_attr.attr.name = "temp"; + data->temp_attr.attr.mode = 0444; + data->temp_attr.show = temp_show; + + sysfs_attr_init(&data->eppid_attr.attr); + data->eppid_attr.attr.name = "eppid"; + data->eppid_attr.attr.mode = 0444; + data->eppid_attr.show = eppid_show; + + battery_hook_register(&data->hook); + + return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook); +} + +static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method) +{ + struct device *dev = seq->private; + struct dell_wmi_ddv_data *data = dev_get_drvdata(dev); + union acpi_object *obj; + union acpi_object buf; + int ret; + + ret = dell_wmi_ddv_query_buffer(data->wdev, method, 0, &obj); + if (ret < 0) + return ret; + + buf = obj->package.elements[1]; + ret = seq_write(seq, buf.buffer.pointer, buf.buffer.length); + kfree(obj); + + return ret; +} + +static int dell_wmi_ddv_fan_read(struct seq_file *seq, void *offset) +{ + return dell_wmi_ddv_buffer_read(seq, DELL_DDV_FAN_SENSOR_INFORMATION); +} + +static int dell_wmi_ddv_temp_read(struct seq_file *seq, void *offset) +{ + return dell_wmi_ddv_buffer_read(seq, DELL_DDV_THERMAL_SENSOR_INFORMATION); +} + +static void dell_wmi_ddv_debugfs_remove(void *data) +{ + struct dentry *entry = data; + + debugfs_remove(entry); +} + +static void dell_wmi_ddv_debugfs_init(struct wmi_device *wdev) +{ + struct dentry *entry; + char name[64]; + + scnprintf(name, ARRAY_SIZE(name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev)); + entry = debugfs_create_dir(name, NULL); + + debugfs_create_devm_seqfile(&wdev->dev, "fan_sensor_information", entry, + dell_wmi_ddv_fan_read); + debugfs_create_devm_seqfile(&wdev->dev, "thermal_sensor_information", entry, + dell_wmi_ddv_temp_read); + + devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_debugfs_remove, entry); +} + +static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context) +{ + struct dell_wmi_ddv_data *data; + u32 version; + int ret; + + ret = dell_wmi_ddv_query_integer(wdev, DELL_DDV_INTERFACE_VERSION, 0, &version); + if (ret < 0) + return ret; + + dev_dbg(&wdev->dev, "WMI interface version: %d\n", version); + if (version != DELL_DDV_SUPPORTED_INTERFACE) + return -ENODEV; + + data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + dev_set_drvdata(&wdev->dev, data); + data->wdev = wdev; + + dell_wmi_ddv_debugfs_init(wdev); + + return dell_wmi_ddv_battery_add(data); +} + +static const struct wmi_device_id dell_wmi_ddv_id_table[] = { + { DELL_DDV_GUID, NULL }, + { } +}; +MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table); + +static struct wmi_driver dell_wmi_ddv_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .id_table = dell_wmi_ddv_id_table, + .probe = dell_wmi_ddv_probe, +}; +module_wmi_driver(dell_wmi_ddv_driver); + +MODULE_AUTHOR("Armin Wolf "); +MODULE_DESCRIPTION("Dell WMI sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index aff23309b5d3..f307d8c5c6c3 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -108,6 +108,7 @@ MODULE_DEVICE_TABLE(acpi, wmi_device_ids); /* allow duplicate GUIDs as these device drivers use struct wmi_driver */ static const char * const allow_duplicates[] = { "05901221-D566-11D1-B2F0-00A0C9062910", /* wmi-bmof */ + "8A42EA14-4F2A-FD45-6422-0087F7A7E608", /* dell-wmi-ddv */ NULL };