From patchwork Thu Nov 22 10:11:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Enric Balletbo i Serra X-Patchwork-Id: 10693851 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 BACBB13BF for ; Thu, 22 Nov 2018 10:11:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A97752CA35 for ; Thu, 22 Nov 2018 10:11:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9CFDA2CA57; Thu, 22 Nov 2018 10:11:30 +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,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY 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 DEF1E2CA35 for ; Thu, 22 Nov 2018 10:11:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2393900AbeKVUuO (ORCPT ); Thu, 22 Nov 2018 15:50:14 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:53704 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390457AbeKVUuO (ORCPT ); Thu, 22 Nov 2018 15:50:14 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id C44752753E0 From: Enric Balletbo i Serra To: linux-pm@vger.kernel.org, sre@kernel.org Cc: Sameer Nanda , gwendal@chromium.org, linux-kernel@vger.kernel.org, groeck@chromium.org, Adam.Thomson.Opensource@diasemi.com, kernel@collabora.com, bleung@chromium.org, "Rafael J. Wysocki" , Len Brown , Pavel Machek Subject: [PATCH v2 1/2] power: supply: add input voltage limit property. Date: Thu, 22 Nov 2018 11:11:18 +0100 Message-Id: <20181122101119.29194-1-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.19.1 MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP We have a problem with USBPD chargers which under certain conditions can result in system overheating if the voltage provided by the USBPD port is too high. While the preferred means to control this would be through devicetree or ACPI settings, this is not always possible, and we need to have a means to set a voltage limit. This patch exposes a new property, similar to input current limit, to re-configure the maximum voltage from the external supply at runtime based on system-level knowledge or user input. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Guenter Roeck Acked-by: Adam Thomson --- Changes in v2: - Document the new property in ABI/testing/sysfs-class-power. - Add the Reviewed-by Guenter Roeck tag. Documentation/ABI/testing/sysfs-class-power | 11 +++++++++++ Documentation/power/power_supply_class.txt | 2 ++ drivers/power/supply/power_supply_sysfs.c | 1 + include/linux/power_supply.h | 1 + 4 files changed, 15 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index 5e23e22dce1b..4fb24b0a28df 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -335,6 +335,17 @@ Description: Access: Read, Write Valid values: Represented in microamps +What: /sys/class/power_supply//input_voltage_limit +Date: Nov 2018 +Contact: linux-pm@vger.kernel.org +Description: + Details the incoming VBUS voltage limit currently set in the + supply. Normally this is configured based on the type of + connection made. + + Access: Read, Write + Valid values: Represented in microvolts + What: /sys/class/power_supply//online, Date: May 2007 Contact: linux-pm@vger.kernel.org diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt index 300d37896e51..7b4be615b4f8 100644 --- a/Documentation/power/power_supply_class.txt +++ b/Documentation/power/power_supply_class.txt @@ -137,6 +137,8 @@ power supply object. INPUT_CURRENT_LIMIT - input current limit programmed by charger. Indicates the current drawn from a charging source. +INPUT_VOLTAGE_LIMIT - input voltage limit programmed by charger. Indicates +the voltage limit from a charging source. CHARGE_CONTROL_LIMIT - current charge control limit setting CHARGE_CONTROL_LIMIT_MAX - maximum charge control limit setting diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index dce24f596160..5848742ebb59 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -275,6 +275,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(charge_control_limit), POWER_SUPPLY_ATTR(charge_control_limit_max), POWER_SUPPLY_ATTR(input_current_limit), + POWER_SUPPLY_ATTR(input_voltage_limit), POWER_SUPPLY_ATTR(energy_full_design), POWER_SUPPLY_ATTR(energy_empty_design), POWER_SUPPLY_ATTR(energy_full), diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index f80769175c56..608ba88e32ee 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -122,6 +122,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, POWER_SUPPLY_PROP_ENERGY_FULL, From patchwork Thu Nov 22 10:11:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Enric Balletbo i Serra X-Patchwork-Id: 10693853 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 6FF5C13BF for ; Thu, 22 Nov 2018 10:11:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5CD5B2CA35 for ; Thu, 22 Nov 2018 10:11:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 514082CA57; Thu, 22 Nov 2018 10:11:35 +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,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI,UNPARSEABLE_RELAY 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 C5AF42CA35 for ; Thu, 22 Nov 2018 10:11:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2393925AbeKVUuS (ORCPT ); Thu, 22 Nov 2018 15:50:18 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:53720 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390496AbeKVUuO (ORCPT ); Thu, 22 Nov 2018 15:50:14 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id AC3CE27E761 From: Enric Balletbo i Serra To: linux-pm@vger.kernel.org, sre@kernel.org Cc: Sameer Nanda , gwendal@chromium.org, linux-kernel@vger.kernel.org, groeck@chromium.org, Adam.Thomson.Opensource@diasemi.com, kernel@collabora.com, bleung@chromium.org Subject: [PATCH v2 2/2] power: supply: cros: allow to set input voltage and current limit. Date: Thu, 22 Nov 2018 11:11:19 +0100 Message-Id: <20181122101119.29194-2-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.19.1 In-Reply-To: <20181122101119.29194-1-enric.balletbo@collabora.com> References: <20181122101119.29194-1-enric.balletbo@collabora.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch allows reading and writing the input voltage and current limit through the POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT and POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT sysfs properties. This allows userspace to see current values and to re-configure these values at runtime based on system-level knowledge or user input. By default there is no limit, this is reported as a -1 when reading from userspace. Writing a value will set the current or voltage limit in uA or uV, and writing any negative value will remove that limit. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Guenter Roeck --- Changes in v2: - Fix the upper limit that can be set. - Remove unnecessary else. drivers/power/supply/cros_usbpd-charger.c | 116 ++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c index 7e9c3984ef6a..3a9ea94c3de3 100644 --- a/drivers/power/supply/cros_usbpd-charger.c +++ b/drivers/power/supply/cros_usbpd-charger.c @@ -53,6 +53,8 @@ struct charger_data { }; static enum power_supply_property cros_usbpd_charger_props[] = { + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_CURRENT_MAX, @@ -80,6 +82,10 @@ static enum power_supply_usb_type cros_usbpd_charger_usb_types[] = { POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID }; +/* Input voltage/current limit in mV/mA. Default to none. */ +static u16 input_voltage_limit = EC_POWER_LIMIT_NONE; +static u16 input_current_limit = EC_POWER_LIMIT_NONE; + static bool cros_usbpd_charger_port_is_dedicated(struct port_data *port) { return port->port_number >= port->charger->num_usbpd_ports; @@ -324,6 +330,26 @@ static int cros_usbpd_charger_get_port_status(struct port_data *port, return ret; } +static int cros_usbpd_charger_set_ext_power_limit(struct charger_data *charger, + u16 current_lim, + u16 voltage_lim) +{ + struct ec_params_external_power_limit_v1 req; + int ret; + + req.current_lim = current_lim; + req.voltage_lim = voltage_lim; + + ret = cros_usbpd_charger_ec_command(charger, 0, + EC_CMD_EXTERNAL_POWER_LIMIT, + &req, sizeof(req), NULL, 0); + if (ret < 0) + dev_err(charger->dev, + "Unable to set the 'External Power Limit': %d\n", ret); + + return ret; +} + static void cros_usbpd_charger_power_changed(struct power_supply *psy) { struct port_data *port = power_supply_get_drvdata(psy); @@ -396,6 +422,18 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_USB_TYPE: val->intval = port->psy_usb_type; break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + if (input_current_limit == EC_POWER_LIMIT_NONE) + val->intval = -1; + else + val->intval = input_current_limit * 1000; + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + if (input_voltage_limit == EC_POWER_LIMIT_NONE) + val->intval = -1; + else + val->intval = input_voltage_limit * 1000; + break; case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = port->model_name; break; @@ -409,6 +447,81 @@ static int cros_usbpd_charger_get_prop(struct power_supply *psy, return 0; } +static int cros_usbpd_charger_set_prop(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct port_data *port = power_supply_get_drvdata(psy); + struct charger_data *charger = port->charger; + struct device *dev = charger->dev; + u16 intval; + int ret; + + /* U16_MAX in mV/mA is the maximum supported value */ + if (val->intval >= U16_MAX * 1000) + return -EINVAL; + /* A negative number is used to clear the limit */ + if (val->intval < 0) + intval = EC_POWER_LIMIT_NONE; + else /* Convert from uA/uV to mA/mV */ + intval = val->intval / 1000; + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = cros_usbpd_charger_set_ext_power_limit(charger, intval, + input_voltage_limit); + if (ret < 0) + break; + + input_current_limit = intval; + if (input_current_limit == EC_POWER_LIMIT_NONE) + dev_info(dev, + "External Current Limit cleared for all ports\n"); + else + dev_info(dev, + "External Current Limit set to %dmA for all ports\n", + input_current_limit); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = cros_usbpd_charger_set_ext_power_limit(charger, + input_current_limit, + intval); + if (ret < 0) + break; + + input_voltage_limit = intval; + if (input_voltage_limit == EC_POWER_LIMIT_NONE) + dev_info(dev, + "External Voltage Limit cleared for all ports\n"); + else + dev_info(dev, + "External Voltage Limit set to %dmV for all ports\n", + input_voltage_limit); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int cros_usbpd_charger_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = 1; + break; + default: + ret = 0; + } + + return ret; +} + static int cros_usbpd_charger_ec_event(struct notifier_block *nb, unsigned long queued_during_suspend, void *_notify) @@ -525,6 +638,9 @@ static int cros_usbpd_charger_probe(struct platform_device *pd) psy_desc = &port->psy_desc; psy_desc->get_property = cros_usbpd_charger_get_prop; + psy_desc->set_property = cros_usbpd_charger_set_prop; + psy_desc->property_is_writeable = + cros_usbpd_charger_property_is_writeable; psy_desc->external_power_changed = cros_usbpd_charger_power_changed; psy_cfg.drv_data = port;