From patchwork Tue Nov 23 23:27:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= X-Patchwork-Id: 12635555 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 93A67C433F5 for ; Tue, 23 Nov 2021 23:27:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229959AbhKWXaZ (ORCPT ); Tue, 23 Nov 2021 18:30:25 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46396 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240237AbhKWXaU (ORCPT ); Tue, 23 Nov 2021 18:30:20 -0500 Received: from todd.t-8ch.de (todd.t-8ch.de [IPv6:2a01:4f8:c010:41de::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A60E6C061574; Tue, 23 Nov 2021 15:27:11 -0800 (PST) From: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=weissschuh.net; s=mail; t=1637710028; bh=SZYLz9pODZYhp1MPf438WzgYeqxIh6cyZNNo+eLNyiI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hWN8rkyGx/czcemUfLKEY/DftrxEJYrMHZqBUsVqt91Ak4lgZ6b33Dg99Va0FwvId 5anYDVmzroeWtQeN8C2gkXn3faA6P8N7JWnykqxOc5n33wifVz0d+ujVTiv9LEV2XP PUZWr7qcm8ZAOk59SUxd0d+d7rrjQLfMYU4WSovM= To: linux-pm@vger.kernel.org, Sebastian Reichel , ibm-acpi-devel@lists.sourceforge.net, platform-driver-x86@vger.kernel.org, Mark Gross , Hans de Goede , Henrique de Moraes Holschuh Cc: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , linux-kernel@vger.kernel.org, linrunner@gmx.net, bberg@redhat.com, hadess@hadess.net, markpearson@lenovo.com, nicolopiazzalunga@gmail.com, njoshi1@lenovo.com, smclt30p@gmail.com Subject: [PATCH v2 1/4] power: supply: add charge_behaviour attributes Date: Wed, 24 Nov 2021 00:27:01 +0100 Message-Id: <20211123232704.25394-2-linux@weissschuh.net> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20211123232704.25394-1-linux@weissschuh.net> References: <20211123232704.25394-1-linux@weissschuh.net> MIME-Version: 1.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1637710019; l=2492; s=20211113; h=from:subject; bh=SZYLz9pODZYhp1MPf438WzgYeqxIh6cyZNNo+eLNyiI=; b=wEL2amfTqT1FYd22a4d7WEiSv3LHb/lYYaZ7ZkQQhWQcBIuUWr92Dru0OR29hjho/e3lJMWFXUQR p6TSb02cDo2UtQok+PIrNP2zesS2ITVHAJU1u3lqwBsslWPDjf8O X-Developer-Key: i=linux@weissschuh.net; a=ed25519; pk=9LP6KM4vD/8CwHW7nouRBhWLyQLcK1MkP6aTZbzUlj4= Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org This a revised version of "[RFC] add standardized attributes for force_discharge and inhibit_charge" [0], incorporating discussion results. The biggest change is the switch from two boolean attributes to a single enum attribute. [0] https://lore.kernel.org/platform-driver-x86/21569a89-8303-8573-05fb-c2fec29983d1@gmail.com/ Signed-off-by: Thomas Weißschuh --- Documentation/ABI/testing/sysfs-class-power | 14 ++++++++++++++ include/linux/power_supply.h | 7 +++++++ 2 files changed, 21 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index f7904efc4cfa..cece094764f8 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -455,6 +455,20 @@ Description: "Unknown", "Charging", "Discharging", "Not charging", "Full" +What: /sys/class/power_supply//charge_behaviour +Date: November 2021 +Contact: linux-pm@vger.kernel.org +Description: + Represents the charging behaviour. + + Access: Read, Write + + Valid values: + ================ ==================================== + auto: Charge normally, respect thresholds + inhibit-charge: Do not charge while AC is attached + force-discharge: Force discharge while AC is attached + What: /sys/class/power_supply//technology Date: May 2007 Contact: linux-pm@vger.kernel.org diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 9ca1f120a211..70c333e86293 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -132,6 +132,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD, /* in percents! */ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD, /* in percents! */ + POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, POWER_SUPPLY_PROP_INPUT_POWER_LIMIT, @@ -202,6 +203,12 @@ enum power_supply_usb_type { POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID, /* Apple Charging Method */ }; +enum power_supply_charge_behaviour { + POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO = 0, + POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE, + POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE, +}; + enum power_supply_notifier_events { PSY_EVENT_PROP_CHANGED, }; From patchwork Tue Nov 23 23:27:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= X-Patchwork-Id: 12635557 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 06AF1C4321E for ; Tue, 23 Nov 2021 23:27:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240371AbhKWXa1 (ORCPT ); Tue, 23 Nov 2021 18:30:27 -0500 Received: from todd.t-8ch.de ([159.69.126.157]:55485 "EHLO todd.t-8ch.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240234AbhKWXaY (ORCPT ); Tue, 23 Nov 2021 18:30:24 -0500 From: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=weissschuh.net; s=mail; t=1637710028; bh=ubpC/4tVq2wPO3RjwZsGHEo8sdCshhNkUuFARYO2hlg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NlNIdkYeXjBMf+ZkMSwEKARWpzUuFtUM2v0++eDFPVXVW4niDr99KpYrElnPCIb8y N9AwJQ4WdlIycMz1wiM/h0BBykWYhxWY2ZpuqmueQ6uwxrno/C7TErErBNovVupROV PozOZri5Xf7+O5KwNKhu4TccJLlP0jNNy7tAz5bA= To: linux-pm@vger.kernel.org, Sebastian Reichel , ibm-acpi-devel@lists.sourceforge.net, platform-driver-x86@vger.kernel.org, Mark Gross , Hans de Goede , Henrique de Moraes Holschuh Cc: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , linux-kernel@vger.kernel.org, linrunner@gmx.net, bberg@redhat.com, hadess@hadess.net, markpearson@lenovo.com, nicolopiazzalunga@gmail.com, njoshi1@lenovo.com, smclt30p@gmail.com Subject: [PATCH v2 2/4] power: supply: add helpers for charge_behaviour sysfs Date: Wed, 24 Nov 2021 00:27:02 +0100 Message-Id: <20211123232704.25394-3-linux@weissschuh.net> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20211123232704.25394-1-linux@weissschuh.net> References: <20211123232704.25394-1-linux@weissschuh.net> MIME-Version: 1.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1637710019; l=3306; s=20211113; h=from:subject; bh=ubpC/4tVq2wPO3RjwZsGHEo8sdCshhNkUuFARYO2hlg=; b=eMMI5CuiEYHqc4kRREJLyPoXw87ZNBQLiFITVqfqWbxdFeYulEM3XuvMKUX/rYNsPq2wSKDvlvgF STKS7sEnB1waXnU7NezjuI2a5lywAbjMtty01u2JVV8nlrWlFBwQ X-Developer-Key: i=linux@weissschuh.net; a=ed25519; pk=9LP6KM4vD/8CwHW7nouRBhWLyQLcK1MkP6aTZbzUlj4= Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org These helper functions can be used by drivers to implement their own sysfs-attributes. This is useful for ACPI-drivers extending the default ACPI-battery with their own charge_behaviour attributes. Signed-off-by: Thomas Weißschuh --- drivers/power/supply/power_supply_sysfs.c | 55 +++++++++++++++++++++++ include/linux/power_supply.h | 9 ++++ 2 files changed, 64 insertions(+) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index c3d7cbcd4fad..5e3b8c15ddbe 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -133,6 +133,12 @@ static const char * const POWER_SUPPLY_SCOPE_TEXT[] = { [POWER_SUPPLY_SCOPE_DEVICE] = "Device", }; +static const char * const POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[] = { + [POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO] = "auto", + [POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE] = "inhibit-charge", + [POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE] = "force-discharge", +}; + static struct power_supply_attr power_supply_attrs[] = { /* Properties of type `int' */ POWER_SUPPLY_ENUM_ATTR(STATUS), @@ -484,3 +490,52 @@ int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } + +ssize_t power_supply_charge_behaviour_show(struct device *dev, + unsigned int available_behaviours, + enum power_supply_charge_behaviour current_behaviour, + char *buf) +{ + bool match = false, available, active; + ssize_t count = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT); i++) { + available = available_behaviours & BIT(i); + active = i == current_behaviour; + + if (available && active) { + count += sysfs_emit_at(buf, count, "[%s] ", + POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]); + match = true; + } else if (available) { + count += sysfs_emit_at(buf, count, "%s ", + POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[i]); + } + } + + if (!match) { + dev_warn(dev, "driver reporting unsupported charge behaviour\n"); + return -EINVAL; + } + + if (count) + buf[count - 1] = '\n'; + + return count; +} +EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_show); + +int power_supply_charge_behaviour_parse(unsigned int available_behaviours, const char *buf) +{ + int i = sysfs_match_string(POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT, buf); + + if (i < 0) + return i; + + if (available_behaviours & BIT(i)) + return i; + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(power_supply_charge_behaviour_parse); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 70c333e86293..71f0379c2af8 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -546,4 +546,13 @@ static inline void power_supply_remove_hwmon_sysfs(struct power_supply *psy) {} #endif +#ifdef CONFIG_SYSFS +ssize_t power_supply_charge_behaviour_show(struct device *dev, + unsigned int available_behaviours, + enum power_supply_charge_behaviour behaviour, + char *buf); + +int power_supply_charge_behaviour_parse(unsigned int available_behaviours, const char *buf); +#endif + #endif /* __LINUX_POWER_SUPPLY_H__ */ From patchwork Tue Nov 23 23:27:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= X-Patchwork-Id: 12635563 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 E4908C41535 for ; Tue, 23 Nov 2021 23:27:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240495AbhKWXa2 (ORCPT ); Tue, 23 Nov 2021 18:30:28 -0500 Received: from todd.t-8ch.de ([159.69.126.157]:41009 "EHLO todd.t-8ch.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240215AbhKWXaY (ORCPT ); Tue, 23 Nov 2021 18:30:24 -0500 From: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=weissschuh.net; s=mail; t=1637710029; bh=pszJ8TGazGuvxexqpltLSJ+3bJo+VwdtuFcNULoFLfw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=P/yQm2GufR400nhnNbaNAILFGeznccogxSFIBwXL8dyiEb/rnxraSYiWAK6lr3YFd 3gmFR2lCXMVV+l9hj5H7tVW0hFw+YfPnGNxo6IpWofovRVsJ/RdOBRIIjmjGn6zpBz b448HfK3eJ9nKUvfFT5QG9Ftqnv7wEzt8lvzrgh8= To: linux-pm@vger.kernel.org, Sebastian Reichel , ibm-acpi-devel@lists.sourceforge.net, platform-driver-x86@vger.kernel.org, Mark Gross , Hans de Goede , Henrique de Moraes Holschuh Cc: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , linux-kernel@vger.kernel.org, linrunner@gmx.net, bberg@redhat.com, hadess@hadess.net, markpearson@lenovo.com, nicolopiazzalunga@gmail.com, njoshi1@lenovo.com, smclt30p@gmail.com Subject: [PATCH v2 3/4] platform/x86: thinkpad_acpi: support force-discharge Date: Wed, 24 Nov 2021 00:27:03 +0100 Message-Id: <20211123232704.25394-4-linux@weissschuh.net> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20211123232704.25394-1-linux@weissschuh.net> References: <20211123232704.25394-1-linux@weissschuh.net> MIME-Version: 1.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1637710019; l=7259; s=20211113; h=from:subject; bh=pszJ8TGazGuvxexqpltLSJ+3bJo+VwdtuFcNULoFLfw=; b=HntqHGVYa0z8SXeBLoU7xPhQqyep59YGddMAxVfR3x02Iw4UZD/I7l+gYBx56ghAcUjKJXgZT/JO Nou86YocBy+iNRbb8MMXAP1FWsiIicHV9ipAtpjGvN/ql1CSu/2Z X-Developer-Key: i=linux@weissschuh.net; a=ed25519; pk=9LP6KM4vD/8CwHW7nouRBhWLyQLcK1MkP6aTZbzUlj4= Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org This adds support for the force-discharge charge_behaviour through the embedded controller of ThinkPads. Co-developed-by: Thomas Koch Signed-off-by: Thomas Koch Co-developed-by: Nicolò Piazzalunga Signed-off-by: Nicolò Piazzalunga Signed-off-by: Thomas Weißschuh --- This patch is based on https://lore.kernel.org/platform-driver-x86/c2504700-06e9-e7d8-80f7-de90b0b6dfb5@gmail.com/ --- drivers/platform/x86/thinkpad_acpi.c | 131 ++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 9c632df734bb..e3567cc686fa 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9319,6 +9319,8 @@ static struct ibm_struct mute_led_driver_data = { #define SET_START "BCCS" #define GET_STOP "BCSG" #define SET_STOP "BCSS" +#define GET_DISCHARGE "BDSG" +#define SET_DISCHARGE "BDSS" enum { BAT_ANY = 0, @@ -9335,6 +9337,7 @@ enum { /* This is used in the get/set helpers */ THRESHOLD_START, THRESHOLD_STOP, + FORCE_DISCHARGE, }; struct tpacpi_battery_data { @@ -9342,6 +9345,7 @@ struct tpacpi_battery_data { int start_support; int charge_stop; int stop_support; + unsigned int charge_behaviours; }; struct tpacpi_battery_driver_data { @@ -9399,6 +9403,12 @@ static int tpacpi_battery_get(int what, int battery, int *ret) if (*ret == 0) *ret = 100; return 0; + case FORCE_DISCHARGE: + if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_DISCHARGE, ret, battery)) + return -ENODEV; + /* The force discharge status is in bit 0 */ + *ret = *ret & 0x01; + return 0; default: pr_crit("wrong parameter: %d", what); return -EINVAL; @@ -9427,12 +9437,49 @@ static int tpacpi_battery_set(int what, int battery, int value) return -ENODEV; } return 0; + case FORCE_DISCHARGE: + /* Force discharge is in bit 0, + * break on AC attach is in bit 1 (won't work on some ThinkPads), + * battery ID is in bits 8-9, 2 bits. + */ + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(SET_DISCHARGE, &ret, param))) { + pr_err("failed to set force discharge on %d", battery); + return -ENODEV; + } + return 0; default: pr_crit("wrong parameter: %d", what); return -EINVAL; } } +static int tpacpi_battery_set_validate(int what, int battery, int value) +{ + int ret, v; + + ret = tpacpi_battery_set(what, battery, value); + if (ret < 0) + return ret; + + ret = tpacpi_battery_get(what, battery, &v); + if (ret < 0) + return ret; + + if (v == value) + return 0; + + msleep(500); + + ret = tpacpi_battery_get(what, battery, &v); + if (ret < 0) + return ret; + + if (v == value) + return 0; + + return -EIO; +} + static int tpacpi_battery_probe(int battery) { int ret = 0; @@ -9445,6 +9492,8 @@ static int tpacpi_battery_probe(int battery) * 2) Check for support * 3) Get the current stop threshold * 4) Check for support + * 5) Get the current force discharge status + * 6) Check for support */ if (acpi_has_method(hkey_handle, GET_START)) { if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, &ret, battery)) { @@ -9481,10 +9530,25 @@ static int tpacpi_battery_probe(int battery) return -ENODEV; } } - pr_info("battery %d registered (start %d, stop %d)", - battery, - battery_info.batteries[battery].charge_start, - battery_info.batteries[battery].charge_stop); + if (acpi_has_method(hkey_handle, GET_DISCHARGE)) { + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_DISCHARGE, &ret, battery))) { + pr_err("Error probing battery discharge; %d\n", battery); + return -ENODEV; + } + /* Support is marked in bit 8 */ + if (ret & BIT(8)) + battery_info.batteries[battery].charge_behaviours |= + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE); + } + + battery_info.batteries[battery].charge_behaviours |= + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO); + + pr_info("battery %d registered (start %d, stop %d, behaviours: 0x%x)\n", + battery, + battery_info.batteries[battery].charge_start, + battery_info.batteries[battery].charge_stop, + battery_info.batteries[battery].charge_behaviours); return 0; } @@ -9619,6 +9683,28 @@ static ssize_t charge_control_end_threshold_show(struct device *device, return tpacpi_battery_show(THRESHOLD_STOP, device, buf); } +static ssize_t charge_behaviour_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + enum power_supply_charge_behaviour active = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; + struct power_supply *supply = to_power_supply(dev); + unsigned int available; + int ret, battery; + + battery = tpacpi_battery_get_id(supply->desc->name); + available = battery_info.batteries[battery].charge_behaviours; + + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) { + if (tpacpi_battery_get(FORCE_DISCHARGE, battery, &ret)) + return -ENODEV; + if (ret) + active = POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE; + } + + return power_supply_charge_behaviour_show(dev, available, active, buf); +} + static ssize_t charge_control_start_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -9633,8 +9719,44 @@ static ssize_t charge_control_end_threshold_store(struct device *dev, return tpacpi_battery_store(THRESHOLD_STOP, dev, buf, count); } +static ssize_t charge_behaviour_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct power_supply *supply = to_power_supply(dev); + int selected, battery, ret = 0; + unsigned int available; + + battery = tpacpi_battery_get_id(supply->desc->name); + available = battery_info.batteries[battery].charge_behaviours; + selected = power_supply_charge_behaviour_parse(available, buf); + + if (selected < 0) + return selected; + + switch (selected) { + case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) + ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0); + if (ret < 0) + return ret; + break; + case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE: + ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 1); + if (ret < 0) + return ret; + break; + default: + dev_err(dev, "Unexpected charge behaviour: %d\n", selected); + return -EINVAL; + } + + return count; +} + static DEVICE_ATTR_RW(charge_control_start_threshold); static DEVICE_ATTR_RW(charge_control_end_threshold); +static DEVICE_ATTR_RW(charge_behaviour); static struct device_attribute dev_attr_charge_start_threshold = __ATTR( charge_start_threshold, 0644, @@ -9653,6 +9775,7 @@ static struct attribute *tpacpi_battery_attrs[] = { &dev_attr_charge_control_end_threshold.attr, &dev_attr_charge_start_threshold.attr, &dev_attr_charge_stop_threshold.attr, + &dev_attr_charge_behaviour.attr, NULL, }; From patchwork Tue Nov 23 23:27:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= X-Patchwork-Id: 12635561 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 2F6F9C4332F for ; Tue, 23 Nov 2021 23:27:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240286AbhKWXa0 (ORCPT ); Tue, 23 Nov 2021 18:30:26 -0500 Received: from todd.t-8ch.de ([159.69.126.157]:48181 "EHLO todd.t-8ch.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240231AbhKWXaY (ORCPT ); Tue, 23 Nov 2021 18:30:24 -0500 From: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=weissschuh.net; s=mail; t=1637710029; bh=qU9W2kmHIbsmZrsfsVtyjLYvoHKferUQSNYZI6CIAs4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uQQfHok7cpILqH8Ek2abRVvBX9IuxjCTbszBlViHa9ibngmrD1hm0cnIkG+PgaLbx BktxrK0jsBJc3CCzpye3UQUJ7sjNMqK2bhVp9+8gwezeY/4RxIxIXpUOktorljvK/g mKZb1hL4LEViC75sEj2o8nq9co9tDXdfnm8a32W0= To: linux-pm@vger.kernel.org, Sebastian Reichel , ibm-acpi-devel@lists.sourceforge.net, platform-driver-x86@vger.kernel.org, Mark Gross , Hans de Goede , Henrique de Moraes Holschuh Cc: =?utf-8?q?Thomas_Wei=C3=9Fschuh?= , linux-kernel@vger.kernel.org, linrunner@gmx.net, bberg@redhat.com, hadess@hadess.net, markpearson@lenovo.com, nicolopiazzalunga@gmail.com, njoshi1@lenovo.com, smclt30p@gmail.com Subject: [PATCH v2 4/4] platform/x86: thinkpad_acpi: support inhibit-charge Date: Wed, 24 Nov 2021 00:27:04 +0100 Message-Id: <20211123232704.25394-5-linux@weissschuh.net> X-Mailer: git-send-email 2.34.0 In-Reply-To: <20211123232704.25394-1-linux@weissschuh.net> References: <20211123232704.25394-1-linux@weissschuh.net> MIME-Version: 1.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1637710019; l=5442; s=20211113; h=from:subject; bh=qU9W2kmHIbsmZrsfsVtyjLYvoHKferUQSNYZI6CIAs4=; b=ksoSvuT62RgYUS1iFKYKmvHRymOwZNCvPjLR9hfbyGS2g0nIP1vRZzThFutfXDQyTMXSTP125f6P /Z9LcK5TB9W77YtfUFazqgccF6hkT5AoaP4if7su7J+B47lSAf4j X-Developer-Key: i=linux@weissschuh.net; a=ed25519; pk=9LP6KM4vD/8CwHW7nouRBhWLyQLcK1MkP6aTZbzUlj4= Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org This adds support for the inhibit-charge charge_behaviour through the embedded controller of ThinkPads. Co-developed-by: Thomas Koch Signed-off-by: Thomas Koch Co-developed-by: Nicolò Piazzalunga Signed-off-by: Nicolò Piazzalunga Signed-off-by: Thomas Weißschuh --- This patch is based on https://lore.kernel.org/platform-driver-x86/d2808930-5840-6ffb-3a59-d235cdb1fe16@gmail.com/ --- drivers/platform/x86/thinkpad_acpi.c | 64 +++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e3567cc686fa..7f2f46c71482 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9321,6 +9321,8 @@ static struct ibm_struct mute_led_driver_data = { #define SET_STOP "BCSS" #define GET_DISCHARGE "BDSG" #define SET_DISCHARGE "BDSS" +#define GET_INHIBIT "BICG" +#define SET_INHIBIT "BICS" enum { BAT_ANY = 0, @@ -9338,6 +9340,7 @@ enum { THRESHOLD_START, THRESHOLD_STOP, FORCE_DISCHARGE, + INHIBIT_CHARGE, }; struct tpacpi_battery_data { @@ -9409,6 +9412,12 @@ static int tpacpi_battery_get(int what, int battery, int *ret) /* The force discharge status is in bit 0 */ *ret = *ret & 0x01; return 0; + case INHIBIT_CHARGE: + if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, ret, battery)) + return -ENODEV; + /* The inhibit charge status is in bit 0 */ + *ret = *ret & 0x01; + return 0; default: pr_crit("wrong parameter: %d", what); return -EINVAL; @@ -9447,6 +9456,22 @@ static int tpacpi_battery_set(int what, int battery, int value) return -ENODEV; } return 0; + case INHIBIT_CHARGE: + /* When setting inhibit charge, we set a default value of + * always breaking on AC detach and the effective time is set to + * be permanent. + * The battery ID is in bits 4-5, 2 bits, + * the effective time is in bits 8-23, 2 bytes. + * A time of FFFF indicates forever. + */ + param = value; + param |= battery << 4; + param |= 0xFFFF << 8; + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(SET_INHIBIT, &ret, param))) { + pr_err("failed to set inhibit charge on %d", battery); + return -ENODEV; + } + return 0; default: pr_crit("wrong parameter: %d", what); return -EINVAL; @@ -9494,6 +9519,8 @@ static int tpacpi_battery_probe(int battery) * 4) Check for support * 5) Get the current force discharge status * 6) Check for support + * 7) Get the current inhibit charge status + * 8) Check for support */ if (acpi_has_method(hkey_handle, GET_START)) { if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, &ret, battery)) { @@ -9540,6 +9567,16 @@ static int tpacpi_battery_probe(int battery) battery_info.batteries[battery].charge_behaviours |= BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE); } + if (acpi_has_method(hkey_handle, GET_INHIBIT)) { + if (ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, &ret, battery))) { + pr_err("Error probing battery inhibit charge; %d\n", battery); + return -ENODEV; + } + /* Support is marked in bit 5 */ + if (ret & BIT(5)) + battery_info.batteries[battery].charge_behaviours |= + BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE); + } battery_info.batteries[battery].charge_behaviours |= BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO); @@ -9698,10 +9735,22 @@ static ssize_t charge_behaviour_show(struct device *dev, if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) { if (tpacpi_battery_get(FORCE_DISCHARGE, battery, &ret)) return -ENODEV; - if (ret) + if (ret) { active = POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE; + goto out; + } + } + + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) { + if (tpacpi_battery_get(INHIBIT_CHARGE, battery, &ret)) + return -ENODEV; + if (ret) { + active = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; + goto out; + } } +out: return power_supply_charge_behaviour_show(dev, available, active, buf); } @@ -9738,11 +9787,22 @@ static ssize_t charge_behaviour_store(struct device *dev, case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0); + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) + ret = min(ret, tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 0)); if (ret < 0) return ret; break; case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE: - ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 1); + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) + ret = tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 0); + ret = min(ret, tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 1)); + if (ret < 0) + return ret; + break; + case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: + if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) + ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0); + ret = min(ret, tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 1)); if (ret < 0) return ret; break;