From patchwork Sun May 13 15:29:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ognjen Galic X-Patchwork-Id: 10396259 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id E217360236 for ; Sun, 13 May 2018 15:29:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CF8EB29051 for ; Sun, 13 May 2018 15:29:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C35BF29073; Sun, 13 May 2018 15:29:50 +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.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=unavailable 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 9646129051 for ; Sun, 13 May 2018 15:29:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751438AbeEMP3o (ORCPT ); Sun, 13 May 2018 11:29:44 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:40878 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751357AbeEMP3n (ORCPT ); Sun, 13 May 2018 11:29:43 -0400 Received: by mail-wr0-f195.google.com with SMTP id v60-v6so9731699wrc.7; Sun, 13 May 2018 08:29:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:subject:message-id:mime-version:content-disposition :user-agent; bh=B05KyI341EUto6tsakIbURvUuvljTTG3P76G40Tk0kY=; b=bclmTi06OQADhv+37PCesYoDtm306qVe5uQmco4PlQCjl0q4a3XLicPVYGYqsqrEy0 +iVwAlznkGVEBasYsChwPYD6t1BbGyEv96JBASWBXO0+j3WVedfqUJ1IMp33bumtRu/b G6m5mh2e9c/GJR9bXmYcXrSeNquNuKUWST8uAcLbfl/+2m4B3fKS6UxneSuTUYdr0D7+ 41z5nLg7I4Iel+GKtNw65Ek4mNvsku9Gj6RnAI4xG7+LDrRUuVvKx9533VNuEPzDljMC Jz09cHeR/dDygkRZEFb25hpQu3xN8qzq7buSVyYpLUE1z8EbEXIuHm9cohYkg/HyIP/U UqVA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:subject:message-id:mime-version :content-disposition:user-agent; bh=B05KyI341EUto6tsakIbURvUuvljTTG3P76G40Tk0kY=; b=KYF372Qk2FEBZSzP8rKbqGuuv7rwZ6jQpKbLz2KqbVQT1+lYM+Pa7phXgd848tZhdA rhl6GpO1EjhiaqlWAUyuv9n/Z01mXBzhD0zaCM4RcJydMljRW2zL16EfU7bhZAt7OMwR SYTk1vKEgqlYjppL/ukm1Iy56PRpN+fzATbwK8Ldqg/wwiAt/Rdk6dI3SV6nuc5BdUW6 Dycb7Iji7PO2LDbGW/y0tLZfVEJdJzriDBV5t9WLo3MtKELmiCquvQSjBOS/RsubJnsh 5grzwryj5T+jcVj+gc0L4t+oigxV4YO9DC4COxNjYyNs1Aq2fh26pZv4sTsmYLQ5g+LA UYsw== X-Gm-Message-State: ALKqPwfrUhNHRIRVf0325NhIMk3L4qRTaJv5H4OPIfIZvhrhFS5nDoyk cPN+k2YXJAofLSt1qa0xiCg= X-Google-Smtp-Source: AB8JxZo/JI2+jC1yKQPFIa+c8BcQIo4hK2yOJouKDqg5ft6/5iiCltKSBH0mLxvEPjTg/ePWeXls9w== X-Received: by 2002:adf:aeea:: with SMTP id y97-v6mr4807245wrc.32.1526225381581; Sun, 13 May 2018 08:29:41 -0700 (PDT) Received: from thinkpad (pppoe-46-239-10-213.teol.net. [46.239.10.213]) by smtp.googlemail.com with ESMTPSA id p189-v6sm4973735wmg.18.2018.05.13.08.29.38 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 13 May 2018 08:29:40 -0700 (PDT) Date: Sun, 13 May 2018 17:29:37 +0200 From: Ognjen Galic To: Andy Shevchenko , "Rafael J. Wysocki" , Ognjen =?utf-8?B?R2FsacSH?= , "Rafael J. Wysocki" , Len Brown , Robert Moore , ACPI Devel Maling List , devel@acpica.org, Darren Hart , Andy Shevchenko , Henrique de Moraes Holschuh , Sebastian Reichel , Platform Driver , ibm-acpi-devel@lists.sourceforge.net, Linux PM , Christoph =?iso-8859-1?Q?B=F6hmwalder?= , Kevin Locke Subject: [PATCH 1/3] thinkpad_acpi: add support for inhibit_charge Message-ID: <20180513152937.GA5072@thinkpad> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.9.4 (2018-02-28) Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Lenovo ThinkPad systems support the prevention of battery charging via a manual override called Inhibit Charge. This patch adds support for that attribute and exposes it via the battery ACPI driver in the generic location: /sys/class/power_supply/BATX/inhibit_charge Signed-off-by: Ognjen Galic --- drivers/platform/x86/thinkpad_acpi.c | 66 +++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index da1ca485..b8b74889 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9233,6 +9233,11 @@ static struct ibm_struct mute_led_driver_data = { #define GET_STOP "BCSG" #define SET_STOP "BCSS" +#define SET_INHIBIT "BICS" +#define GET_INHIBIT "BICG" + +#define INHIBIT_ATTR "inhibit_charge" + #define START_ATTR "charge_start_threshold" #define STOP_ATTR "charge_stop_threshold" @@ -9251,6 +9256,7 @@ enum { /* This is used in the get/set helpers */ THRESHOLD_START, THRESHOLD_STOP, + INHIBIT_CHARGE }; struct tpacpi_battery_data { @@ -9258,6 +9264,7 @@ struct tpacpi_battery_data { int start_support; int charge_stop; int stop_support; + int inhibit_support; }; struct tpacpi_battery_driver_data { @@ -9315,6 +9322,13 @@ static int tpacpi_battery_get(int what, int battery, int *ret) if (*ret == 0) *ret = 100; return 0; + case INHIBIT_CHARGE: + if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, ret, battery)) + return -ENODEV; + + /* The inhibit charge status is in the first bit */ + *ret = *ret & 0x01; + return 0; default: pr_crit("wrong parameter: %d", what); return -EINVAL; @@ -9343,6 +9357,21 @@ static int tpacpi_battery_set(int what, int battery, int value) return -ENODEV; } return 0; + case INHIBIT_CHARGE: + /* When setting inhbitit charge, we set a default vaulue 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 and 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; @@ -9359,6 +9388,8 @@ static int tpacpi_battery_probe(int battery) * 2) Check for support * 3) Get the current stop threshold * 4) Check for support + * 5) Check for inhibit charge support + * 6) Get the current inhibit charge status */ if (acpi_has_method(hkey_handle, GET_START)) { if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, &ret, battery)) { @@ -9395,10 +9426,16 @@ static int tpacpi_battery_probe(int battery) return -ENODEV; } } - pr_info("battery %d registered (start %d, stop %d)", + if (acpi_has_method(hkey_handle, GET_INHIBIT)) + if (!ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, &ret, battery))) + /* Support is marked in bit 5 */ + battery_info.batteries[battery].inhibit_support = ret & BIT(5); + + pr_info("battery %d registered (start %d, stop %d, inhibit: %d)", battery, battery_info.batteries[battery].charge_start, - battery_info.batteries[battery].charge_stop); + battery_info.batteries[battery].charge_stop, + battery_info.batteries[battery].inhibit_support); return 0; } @@ -9484,6 +9521,15 @@ static ssize_t tpacpi_battery_store(int what, if (tpacpi_battery_set(THRESHOLD_STOP, battery, value)) return -EINVAL; return count; + case INHIBIT_CHARGE: + if (!battery_info.batteries[battery].inhibit_support) + return -ENODEV; + /* The only valid values are 1 and 0 */ + if (value != 0 && value != 1) + return -EINVAL; + if (tpacpi_battery_set(INHIBIT_CHARGE, battery, value)) + return -ENODEV; + return count; default: pr_crit("Wrong parameter: %d", what); return -EINVAL; @@ -9546,12 +9592,28 @@ static ssize_t charge_stop_threshold_store(struct device *dev, return tpacpi_battery_store(THRESHOLD_STOP, dev, buf, count); } +static ssize_t inhibit_charge_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return tpacpi_battery_store(INHIBIT_CHARGE, dev, buf, count); +} + +static ssize_t inhibit_charge_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + return tpacpi_battery_show(INHIBIT_CHARGE, device, buf); +} + static DEVICE_ATTR_RW(charge_start_threshold); static DEVICE_ATTR_RW(charge_stop_threshold); +static DEVICE_ATTR_RW(inhibit_charge); static struct attribute *tpacpi_battery_attrs[] = { &dev_attr_charge_start_threshold.attr, &dev_attr_charge_stop_threshold.attr, + &dev_attr_inhibit_charge.attr, NULL, };