From patchwork Thu Feb 20 07:34:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 212799 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.3 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_SANE_1 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9F3BCC11D02 for ; Thu, 20 Feb 2020 07:34:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 837042467E for ; Thu, 20 Feb 2020 07:34:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726759AbgBTHef (ORCPT ); Thu, 20 Feb 2020 02:34:35 -0500 Received: from mail-lj1-f193.google.com ([209.85.208.193]:34680 "EHLO mail-lj1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726443AbgBTHee (ORCPT ); Thu, 20 Feb 2020 02:34:34 -0500 Received: by mail-lj1-f193.google.com with SMTP id x7so3152888ljc.1; Wed, 19 Feb 2020 23:34:33 -0800 (PST) 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:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=wXda0LyWckmOxCnu3svogcv/3s7lvsQvOxCdmqlN0xY=; b=D7Uc2RPGA0cbVeLQZ+eGd835uL/rqhCKrAUA2bfj1XMUFIHsNqYn0MZzYBNbYN5LY7 8Mr4JlTH494RuJjgJoDwTE6kLi2JYaBKQfFkSVyLayeclUOc89sjB41dZa+75gWcbq/r qGpMJoPxnLwXGznavzjv/jAXEvF06v+TGca9BPj7CdwAHxVsL46BrCjGCNjcF1h2eEEm cVf3eEFQ4ifiT6O0OOklGSqNNQTh5BShGemSVS6Talp4IRdC9byFFOx01ce2CFy7qtoE ZZSdCGYW/EjoJsGNWcwlGCfgd/S/fOmwZV6RERvDB7rX+XVjbbYwk2se1qk3MQ3jacKE YSsg== X-Gm-Message-State: APjAAAXu/PP9g78itDHibHQ/7oaYKDCe6KFfTUXW4MZKl4OMJlg3H0eB qcYhG0Mov6APmyJilhsK/ug= X-Google-Smtp-Source: APXvYqz/C8xvZsGRp6+GrWlhC0fklQ19iCSL9tLVLoErEIBwsW7OcMSutpzrdaGhC6S9CU54nYAa9A== X-Received: by 2002:a2e:6817:: with SMTP id c23mr17518667lja.263.1582184072548; Wed, 19 Feb 2020 23:34:32 -0800 (PST) Received: from localhost.localdomain ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id e8sm1316105ljb.45.2020.02.19.23.34.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Feb 2020 23:34:31 -0800 (PST) Date: Thu, 20 Feb 2020 09:34:19 +0200 From: Matti Vaittinen To: matti.vaittinen@fi.rohmeurope.com, mazziesaccount@gmail.com Cc: Sebastian Reichel , Rob Herring , Mark Rutland , Greg Kroah-Hartman , "Rafael J. Wysocki" , Liam Girdwood , Mark Brown , "GitAuthor: Matti Vaittinen" , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Markus Laine , Mikko Mutanen Subject: [RFC PATCH v3 1/8] dt-bindings: battry: add new battery parameters Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.12.1 (2019-06-15) Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Add: - trickle-charge-current-microamp: Some chargers have 3 charging stages. First one when battery is almost empty is often called as trickle-charge. Last state when battery has been "woken up" is usually called as fast-charge. In addition to this some chargers have a 'middle state' which ROHM BD99954 data-sheet describes as pre-charge. Some batteries can benefit from this 3-phase charging [citation needed]. Introduce trickle-charge-current-microamp so that batteries can give charging current limit for all three states. - precharge-upper-limit-microvolt: When battery voltage has reached certain limit we change from trickle-charge to next charging state (pre-charge for BD99954). Allow battery to specify this limit. - re-charge-voltage-microvolt: Allow giving a battery specific voltage limit for chargers which can automatically re-start charging when battery has discharghed down to this limit. - over-voltage-threshold-microvolt Allow specifying voltage threshold after which the battery is assumed to be faulty. Signed-off-by: Matti Vaittinen --- Documentation/devicetree/bindings/power/supply/battery.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/battery.txt b/Documentation/devicetree/bindings/power/supply/battery.txt index 5c913d4cf36c..1ad05dd59213 100644 --- a/Documentation/devicetree/bindings/power/supply/battery.txt +++ b/Documentation/devicetree/bindings/power/supply/battery.txt @@ -11,15 +11,21 @@ different type. This prevents unpredictable, potentially harmful, behavior should a replacement that changes the battery type occur without a corresponding update to the dtb. +Please note that not all charger drivers respect all of the properties. + Required Properties: - compatible: Must be "simple-battery" Optional Properties: + - over-voltage-threshold-microvolt: battery over-voltage limit + - re-charge-voltage-microvolt: limit to automatically start charging again - voltage-min-design-microvolt: drained battery voltage - voltage-max-design-microvolt: fully charged battery voltage - energy-full-design-microwatt-hours: battery design energy - charge-full-design-microamp-hours: battery design capacity + - trickle-charge-current-microamp: current for trickle-charge phase - precharge-current-microamp: current for pre-charge phase + - precharge-upper-limit-microvolt: limit when to change to constant charging - charge-term-current-microamp: current for charge termination phase - constant-charge-current-max-microamp: maximum constant input current - constant-charge-voltage-max-microvolt: maximum constant input voltage From patchwork Thu Feb 20 07:35:37 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 212798 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.3 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C0A9CC11D00 for ; Thu, 20 Feb 2020 07:35:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8D0CA24681 for ; Thu, 20 Feb 2020 07:35:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726679AbgBTHft (ORCPT ); Thu, 20 Feb 2020 02:35:49 -0500 Received: from mail-lf1-f67.google.com ([209.85.167.67]:45302 "EHLO mail-lf1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726443AbgBTHfs (ORCPT ); Thu, 20 Feb 2020 02:35:48 -0500 Received: by mail-lf1-f67.google.com with SMTP id z5so2230126lfd.12; Wed, 19 Feb 2020 23:35:46 -0800 (PST) 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:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=OxS2NJiiysFFBK2NxbOtBNkRQD3aocx0PLSD5ksFpQo=; b=cl52r1Nomc+rngzKY4xzAzOfjQRgN6laEuYHvBF2rXL6xxzo/LFpK0ACw714ZPLtd/ eeQYpdSA+6160MXyjdkjIAhv2+c50gvxf5/D7/FHKoUrZekP6LWa0t2oDC0Rr5/G99PG MLTfl1P6K7lqTxzGqvWMseVO4PkthDGGd4NKRs6p0ATytvUOw1pOvFNEBz6w/W595ATe NffBbYdOCMczNvqaAi0OESQy53k9/clNXG05MA3uPIeW3VtSAQVjUtNBosB7VNbdjcp/ nXNaKYmDK3zyCBflF/TcXXiusLLUAvqz71oPtFnYbqrPI2rkf+YsBrcNjJ05fM8YTZ7y s1KA== X-Gm-Message-State: APjAAAX59dX/v3o6lzUaM4IIfxQWjFV/MQ3+4t+uDE/hC5dpA3UXnwb8 MamXGuSf3XNJGa8jWxzVBJ6lhoqJ X-Google-Smtp-Source: APXvYqyI0ERRO273xIto5lSMD60j10LJUxvakrv+tTuLWg9Fqvs10r75D3V7P7p24/7W4IPjYci08g== X-Received: by 2002:a05:6512:1107:: with SMTP id l7mr3494065lfg.108.1582184145555; Wed, 19 Feb 2020 23:35:45 -0800 (PST) Received: from localhost.localdomain ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id i20sm1267471lfl.79.2020.02.19.23.35.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Feb 2020 23:35:45 -0800 (PST) Date: Thu, 20 Feb 2020 09:35:37 +0200 From: Matti Vaittinen To: matti.vaittinen@fi.rohmeurope.com, mazziesaccount@gmail.com Cc: Sebastian Reichel , Rob Herring , Mark Rutland , Greg Kroah-Hartman , "Rafael J. Wysocki" , Liam Girdwood , Mark Brown , "GitAuthor: Matti Vaittinen" , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Markus Laine , Mikko Mutanen Subject: [RFC PATCH v3 3/8] drivers: base: add linear ranges helpers Message-ID: <1f6cb9fb9dbc429dc48110f18ad3a8c0c40196c6.1582182989.git.matti.vaittinen@fi.rohmeurope.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.12.1 (2019-06-15) Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Many devices have control registers which control some measurable property. Often a register contains control field so that change in this field causes linear change in the controlled property. It is not a rare case that user wants to give 'meaningfull' control values and driver needs to convert them to register field values. Even more often user wants to 'see' the currently set value - again in meaningfull units - and driver needs to convert the values it reads from register to these meaningfull units. Examples of this include: - regulators, voltage/current configurations - power, voltage/current configurations - clk(?) NCOs and maybe others I can't think of right now. Provide a linear_range helper which can do conversion from user value to register value 'selector'. The idea here is stolen from regulator framework and patches refactoring the regulator helpers to use this are following. Signed-off-by: Matti Vaittinen --- drivers/base/Kconfig | 3 + drivers/base/Makefile | 1 + drivers/base/linear_ranges.c | 246 +++++++++++++++++++++++++++++++++++ include/linux/linear_range.h | 48 +++++++ 4 files changed, 298 insertions(+) create mode 100644 drivers/base/linear_ranges.c create mode 100644 include/linux/linear_range.h diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index c3b3b5c0b0da..c52aae709331 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -209,4 +209,7 @@ config GENERIC_ARCH_TOPOLOGY appropriate scaling, sysfs interface for reading capacity values at runtime. +config LINEAR_RANGES + tristate + endmenu diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 157452080f3d..dbb6c4f7ef07 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_PINCTRL) += pinctrl.o obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += arch_topology.o +obj-$(CONFIG_LINEAR_RANGES) += linear_ranges.o obj-y += test/ diff --git a/drivers/base/linear_ranges.c b/drivers/base/linear_ranges.c new file mode 100644 index 000000000000..5fa3b96bf2b8 --- /dev/null +++ b/drivers/base/linear_ranges.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linear_ranges.c -- helpers to map values in a linear range to range index + * + * Original idea borrowed from regulator framework + * + * It might be useful if we could support also inversely proportional ranges? + * Copyright 2020 ROHM Semiconductors + */ + +#include +#include +#include +#include + +/** + * linear_range_values_in_range - return the amount of values in a range + * + * @r: pointer to linear range where values are counted + * + * Compute the amount of values in range pointed by @r. Note, values can + * be all equal - range with selectors 0,...,2 with step 0 still contains + * 3 values even though they are all equal. + * + * Returns the amount of values in range pointed by @r + */ +unsigned int linear_range_values_in_range(const struct linear_range *r) +{ + if (!r) + return 0; + return r->max_sel - r->min_sel + 1; +} +EXPORT_SYMBOL(linear_range_values_in_range); + +/** + * linear_range_values_in_range_array - return the amount of values in ranges + * + * @r: pointer to array of linear ranges where values are counted + * @ranges: amount of ranges we include in computation. + * + * Compute the amount of values in ranges pointed by @r. Note, values can + * be all equal - range with selectors 0,...,2 with step 0 still contains + * 3 values even though they are all equal. + * + * Returns the amount of values in first @ranges ranges pointed by @r + */ +unsigned int linear_range_values_in_range_array(const struct linear_range *r, + int ranges) +{ + int i, values_in_range = 0; + + for (i = 0; i < ranges; i++) { + int values; + + values = linear_range_values_in_range(&r[i]); + if (!values) + return values; + + values_in_range += values; + } + return values_in_range; +} +EXPORT_SYMBOL(linear_range_values_in_range_array); + +/** + * linear_range_get_max_value - return the largest value in a range + * + * @r: pointer to linear range where value is looked from + * + * Returns the largest value in the given range + */ +unsigned int linear_range_get_max_value(const struct linear_range *r) +{ + return r->min + (r->max_sel - r->min_sel) * r->step; +} +EXPORT_SYMBOL(linear_range_get_max_value); + +/** + * linear_range_get_value - fetch a value from given range + * + * @r: pointer to linear range where value is looked from + * @selector: selector for which the value is searched + * @val: address where found value is updated + * + * Search given ranges for value which matches given selector. + * + * Returns 0 on success, -EINVAL given selector is not found from any of the + * ranges. + */ +int linear_range_get_value(const struct linear_range *r, unsigned int selector, + unsigned int *val) +{ + if (r->min_sel > selector || r->max_sel < selector) + return -EINVAL; + + *val = r->min + (selector - r->min_sel) * r->step; + + return 0; +} +EXPORT_SYMBOL(linear_range_get_value); + +/** + * linear_range_get_value_array - fetch a value from array of ranges + * + * @r: pointer to array of linear ranges where value is looked from + * @ranges: amount of ranges in an array + * @selector: selector for which the value is searched + * @val: address where found value is updated + * + * Search through an array of ranges for value which matches given selector. + * + * Returns 0 on success, -EINVAL given selector is not found from any of the + * ranges. + */ +int linear_range_get_value_array(const struct linear_range *r, int ranges, + unsigned int selector, unsigned int *val) +{ + int i; + + for (i = 0; i < ranges; i++) + if (r[i].min_sel <= selector && r[i].max_sel >= selector) + return linear_range_get_value(&r[i], selector, val); + + return -EINVAL; +} +EXPORT_SYMBOL(linear_range_get_value_array); + +/** + * linear_range_get_selector_low - return linear range selector for value + * + * @r: pointer to linear range where selector is looked from + * @val: value for which the selcetor is searched + * @selector: address where found selector value is updated + * @found: flag to indicate that given value was in the range + * + * Return selector which which range value is closest match for given + * input value. Value is matching if it is equal or smaller than given + * value. If given value is in the range, then @found is set true. + * + * Returns 0 on success, -EINVAL if range is invalid or does not contain + * value smaller or equal to given value + */ +int linear_range_get_selector_low(const struct linear_range *r, + unsigned int val, unsigned int *selector, + bool *found) +{ + *found = false; + + if (r->min > val) + return -EINVAL; + + if (linear_range_get_max_value(r) >= val) + *found = true; + + if (!r->step) + *selector = r->min_sel; + else + *selector = (val - r->min) / r->step + r->min_sel; + + return 0; +} +EXPORT_SYMBOL(linear_range_get_selector_low); + +/** + * linear_range_get_selector_low_array - return linear range selector for value + * + * @r: pointer to array of linear ranges where selector is looked from + * @ranges: amount of ranges to scan from array + * @val: value for which the selcetor is searched + * @selector: address where found selector value is updated + * @found: flag to indicate that given value was in the range + * + * Return Scan array of ranges for selector which which range value matches + * given input value. Value is matching if it is equal or smaller than given + * value. If given value is found to be in a range scannins is stopped and + * @found is set true. If a range with values smaller than given value is found + * but the range max is being smaller than given value, then the ranges + * biggest selector is updated to @selector but scanning ranges is continued + * and @found is set to false. + * + * Returns 0 on success, -EINVAL if range array is invalid or does not contain + * range with a value smaller or equal to given value + */ +int linear_range_get_selector_low_array(const struct linear_range *r, + int ranges, unsigned int val, + unsigned int *selector, bool *found) +{ + int i; + int ret = -EINVAL; + + for (i = 0; i < ranges; i++) { + int tmpret; + + tmpret = linear_range_get_selector_low(&r[i], val, selector, + found); + + if (!tmpret) + ret = 0; + + if (*found) + break; + } + + return ret; +} +EXPORT_SYMBOL(linear_range_get_selector_low_array); + +/** + * linear_range_get_selector_high - return linear range selector for value + * + * @r: pointer to linear range where selector is looked from + * @val: value for which the selcetor is searched + * @selector: address where found selector value is updated + * @found: flag to indicate that given value was in the range + * + * Return selector which which range value is closest match for given + * input value. Value is matching if it is equal or higher than given + * value. If given value is in the range, then @found is set true. + * + * Returns 0 on success, -EINVAL if range is invalid or does not contain + * value greater or equal to given value + */ +int linear_range_get_selector_high(const struct linear_range *r, + unsigned int val, unsigned int *selector, + bool *found) +{ + *found = false; + + if (linear_range_get_max_value(r) < val) + return -EINVAL; + + if (r->min <= val) { + *found = true; + } else { + *selector = r->min_sel; + return 0; + } + + if (!r->step) + *selector = r->max_sel; + else + *selector = DIV_ROUND_UP(val - r->min, r->step) + r->min_sel; + + return 0; +} +EXPORT_SYMBOL(linear_range_get_selector_high); diff --git a/include/linux/linear_range.h b/include/linux/linear_range.h new file mode 100644 index 000000000000..534ca59a308a --- /dev/null +++ b/include/linux/linear_range.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* Copyright (C) 2020 ROHM Semiconductors */ + +#ifndef LINEAR_RANGE_H +#define LINEAR_RANGE_H + +#include + +/** + * struct linear_range - table of selector - value pairs + * + * Define a lookup-table for range of values. Intended to help when looking + * for a register value matching certaing physical measure (like voltage). + * Usable when increment of one in register always results a constant increment + * of the physical measure (like voltage). + * + * @min: Lowest value in range + * @min_sel: Lowest selector for range + * @max_sel: Highest selector for range + * @step: Value step size + */ +struct linear_range { + unsigned int min; + unsigned int min_sel; + unsigned int max_sel; + unsigned int step; +}; + +unsigned int linear_range_values_in_range(const struct linear_range *r); +unsigned int linear_range_values_in_range_array(const struct linear_range *r, + int ranges); +unsigned int linear_range_get_max_value(const struct linear_range *r); + +int linear_range_get_value(const struct linear_range *r, unsigned int selector, + unsigned int *val); +int linear_range_get_value_array(const struct linear_range *r, int ranges, + unsigned int selector, unsigned int *val); +int linear_range_get_selector_low(const struct linear_range *r, + unsigned int val, unsigned int *selector, + bool *found); +int linear_range_get_selector_high(const struct linear_range *r, + unsigned int val, unsigned int *selector, + bool *found); +int linear_range_get_selector_low_array(const struct linear_range *r, + int ranges, unsigned int val, + unsigned int *selector, bool *found); + +#endif From patchwork Thu Feb 20 07:36:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 212797 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.3 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_SANE_1 autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5FC44C11D07 for ; Thu, 20 Feb 2020 07:36:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3AE942465D for ; Thu, 20 Feb 2020 07:36:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726788AbgBTHgy (ORCPT ); Thu, 20 Feb 2020 02:36:54 -0500 Received: from mail-lf1-f68.google.com ([209.85.167.68]:39677 "EHLO mail-lf1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726756AbgBTHgy (ORCPT ); Thu, 20 Feb 2020 02:36:54 -0500 Received: by mail-lf1-f68.google.com with SMTP id t23so2262343lfk.6; Wed, 19 Feb 2020 23:36:52 -0800 (PST) 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:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=whNPw+eezGy5wSUPae3plMsR1ZOgHxy5/jyWH2SY3UQ=; b=hgOYKC6I1yTwDA081p28PUFIA03ainp/xWl7W6KExxWfzEgbnC01LatRvBpvxSFkAr 5fwlX9tjr21i8bj1zs7FxlLRQbt+I3kToZogQkM3ihp9e9OAdcO9JSV13JWgaT7AwVaU KXIUcYRKSeI29SWMuw2j9Jpyg4NVP24SCU5j+Msm4a2Ss4I7wDGzsoRFsL13PYPQW9Pc hwaB7WXXqvXPvbVRMiZzgMtciml5bdL225fzJywWibDkGPPxZ888z+4I6gOmBaAfYjm2 9ZjKkvmrJ9xzU1I4VNSmFGbRslzqpOzgRA2m9iSTgXMJaqf90i5jAiwRZiLc9YJtHddQ fqNA== X-Gm-Message-State: APjAAAWV7EhrSgLA0Az2OC+GchQOIy0wEvOYuNiX4SyjVc9vDyO2Mjni KcdPSDWdIOz7eDrOkpHpAZg= X-Google-Smtp-Source: APXvYqyVBPSPld821HEtfQx9FlQM/oA3qAt8gjCCG6v0cO9fp/rziqu5HTDUo96Z04c2GR5lyHRL/Q== X-Received: by 2002:ac2:515b:: with SMTP id q27mr15203470lfd.119.1582184211290; Wed, 19 Feb 2020 23:36:51 -0800 (PST) Received: from localhost.localdomain ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id k23sm1173926ljj.85.2020.02.19.23.36.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Feb 2020 23:36:50 -0800 (PST) Date: Thu, 20 Feb 2020 09:36:38 +0200 From: Matti Vaittinen To: matti.vaittinen@fi.rohmeurope.com, mazziesaccount@gmail.com Cc: Sebastian Reichel , Rob Herring , Mark Rutland , Greg Kroah-Hartman , "Rafael J. Wysocki" , Liam Girdwood , Mark Brown , "GitAuthor: Matti Vaittinen" , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Markus Laine , Mikko Mutanen Subject: [RFC PATCH v3 5/8] regulator: use linear_ranges helper Message-ID: References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.12.1 (2019-06-15) Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Change the regulator helpers to use common linear_ranges code. Signed-off-by: Matti Vaittinen --- drivers/regulator/Kconfig | 1 + drivers/regulator/helpers.c | 124 ++++++++++++++----------------- include/linux/regulator/driver.h | 25 +------ 3 files changed, 59 insertions(+), 91 deletions(-) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 74eb5af7295f..6715eee43304 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig REGULATOR bool "Voltage and Current Regulator Support" + select LINEAR_RANGES help Generic Voltage and Current Regulator support. diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 2c15df0484e5..49f257c37dda 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -129,10 +129,11 @@ int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) unsigned int r_val; int range; unsigned int val; - int ret, i; - unsigned int voltages_in_range = 0; + int ret; + unsigned int voltages = 0; + const struct linear_range *r = rdev->desc->linear_ranges; - if (!rdev->desc->linear_ranges) + if (!r) return -EINVAL; ret = regmap_read(rdev->regmap, rdev->desc->vsel_reg, &val); @@ -150,11 +151,9 @@ int regulator_get_voltage_sel_pickable_regmap(struct regulator_dev *rdev) if (range < 0) return -EINVAL; - for (i = 0; i < range; i++) - voltages_in_range += (rdev->desc->linear_ranges[i].max_sel - - rdev->desc->linear_ranges[i].min_sel) + 1; + voltages = linear_range_values_in_range_array(r, range); - return val + voltages_in_range; + return val + voltages; } EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_pickable_regmap); @@ -177,8 +176,11 @@ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, unsigned int voltages_in_range = 0; for (i = 0; i < rdev->desc->n_linear_ranges; i++) { - voltages_in_range = (rdev->desc->linear_ranges[i].max_sel - - rdev->desc->linear_ranges[i].min_sel) + 1; + const struct linear_range *r; + + r = &rdev->desc->linear_ranges[i]; + voltages_in_range = linear_range_values_in_range(r); + if (sel < voltages_in_range) break; sel -= voltages_in_range; @@ -405,6 +407,8 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev, { const struct linear_range *range; int ret = -EINVAL; + unsigned int sel; + bool found; int voltage, i; if (!rdev->desc->n_linear_ranges) { @@ -413,35 +417,19 @@ int regulator_map_voltage_linear_range(struct regulator_dev *rdev, } for (i = 0; i < rdev->desc->n_linear_ranges; i++) { - int linear_max_uV; - range = &rdev->desc->linear_ranges[i]; - linear_max_uV = range->min_uV + - (range->max_sel - range->min_sel) * range->uV_step; - if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) + ret = linear_range_get_selector_high(range, min_uV, &sel, + &found); + if (ret) continue; - - if (min_uV <= range->min_uV) - min_uV = range->min_uV; - - /* range->uV_step == 0 means fixed voltage range */ - if (range->uV_step == 0) { - ret = 0; - } else { - ret = DIV_ROUND_UP(min_uV - range->min_uV, - range->uV_step); - if (ret < 0) - return ret; - } - - ret += range->min_sel; + ret = sel; /* * Map back into a voltage to verify we're still in bounds. * If we are not, then continue checking rest of the ranges. */ - voltage = rdev->desc->ops->list_voltage(rdev, ret); + voltage = rdev->desc->ops->list_voltage(rdev, sel); if (voltage >= min_uV && voltage <= max_uV) break; } @@ -478,30 +466,25 @@ int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev, for (i = 0; i < rdev->desc->n_linear_ranges; i++) { int linear_max_uV; + bool found; + unsigned int sel; range = &rdev->desc->linear_ranges[i]; - linear_max_uV = range->min_uV + - (range->max_sel - range->min_sel) * range->uV_step; + linear_max_uV = linear_range_get_max_value(range); - if (!(min_uV <= linear_max_uV && max_uV >= range->min_uV)) { - selector += (range->max_sel - range->min_sel + 1); + if (!(min_uV <= linear_max_uV && max_uV >= range->min)) { + selector += linear_range_values_in_range(range); continue; } - if (min_uV <= range->min_uV) - min_uV = range->min_uV; - - /* range->uV_step == 0 means fixed voltage range */ - if (range->uV_step == 0) { - ret = 0; - } else { - ret = DIV_ROUND_UP(min_uV - range->min_uV, - range->uV_step); - if (ret < 0) - return ret; + ret = linear_range_get_selector_high(range, min_uV, &sel, + &found); + if (ret) { + selector += linear_range_values_in_range(range); + continue; } - ret += selector; + ret = selector + sel; voltage = rdev->desc->ops->list_voltage(rdev, ret); @@ -511,7 +494,7 @@ int regulator_map_voltage_pickable_linear_range(struct regulator_dev *rdev, * exit but retry until we have checked all ranges. */ if (voltage < min_uV || voltage > max_uV) - selector += (range->max_sel - range->min_sel + 1); + selector += linear_range_values_in_range(range); else break; } @@ -569,18 +552,28 @@ int regulator_list_voltage_pickable_linear_range(struct regulator_dev *rdev, } for (i = 0; i < rdev->desc->n_linear_ranges; i++) { - unsigned int sels_in_range; + unsigned int sel_indexes; range = &rdev->desc->linear_ranges[i]; - sels_in_range = range->max_sel - range->min_sel; + sel_indexes = linear_range_values_in_range(range) - 1; - if (all_sels + sels_in_range >= selector) { + if (all_sels + sel_indexes >= selector) { selector -= all_sels; - return range->min_uV + (range->uV_step * selector); + /* + * As we see here, pickable ranges work only as + * long as the first selector for each pickable + * range is 0, and the each subsequent range for + * this 'pick' follow immediately at next unused + * selector (Eg. there is no gaps between ranges). + * I think this is fine but it probably should be + * documented. OTOH, whole pickable range stuff + * might benefit from some documentation + */ + return range->min + (range->step * selector); } - all_sels += (sels_in_range + 1); + all_sels += (sel_indexes + 1); } return -EINVAL; @@ -602,27 +595,18 @@ EXPORT_SYMBOL_GPL(regulator_list_voltage_pickable_linear_range); int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc, unsigned int selector) { - const struct linear_range *range; - int i; - - if (!desc->n_linear_ranges) { - BUG_ON(!desc->n_linear_ranges); - return -EINVAL; - } - - for (i = 0; i < desc->n_linear_ranges; i++) { - range = &desc->linear_ranges[i]; - - if (!(selector >= range->min_sel && - selector <= range->max_sel)) - continue; + unsigned int val; + int ret; - selector -= range->min_sel; + BUG_ON(!desc->n_linear_ranges); - return range->min_uV + (range->uV_step * selector); - } + ret = linear_range_get_value_array(desc->linear_ranges, + desc->n_linear_ranges, selector, + &val); + if (ret) + return ret; - return -EINVAL; + return val; } EXPORT_SYMBOL_GPL(regulator_desc_list_voltage_linear_range); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 8419a4321775..7a3982da8868 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -13,6 +13,7 @@ #define __LINUX_REGULATOR_DRIVER_H_ #include +#include #include #include #include @@ -39,31 +40,13 @@ enum regulator_status { REGULATOR_STATUS_UNDEFINED, }; -/** - * struct linear_range - specify linear voltage ranges - * - * Specify a range of voltages for regulator_map_linear_range() and - * regulator_list_linear_range(). - * - * @min_uV: Lowest voltage in range - * @min_sel: Lowest selector for range - * @max_sel: Highest selector for range - * @uV_step: Step size - */ -struct linear_range { - unsigned int min_uV; - unsigned int min_sel; - unsigned int max_sel; - unsigned int uV_step; -}; - -/* Initialize struct linear_range */ +/* Initialize struct linear_range for regulators */ #define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV) \ { \ - .min_uV = _min_uV, \ + .min = _min_uV, \ .min_sel = _min_sel, \ .max_sel = _max_sel, \ - .uV_step = _step_uV, \ + .step = _step_uV, \ } /** From patchwork Thu Feb 20 07:37:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vaittinen, Matti" X-Patchwork-Id: 212796 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.3 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 00292C11D02 for ; Thu, 20 Feb 2020 07:38:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D76F224689 for ; Thu, 20 Feb 2020 07:38:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726771AbgBTHiB (ORCPT ); Thu, 20 Feb 2020 02:38:01 -0500 Received: from mail-lj1-f196.google.com ([209.85.208.196]:36867 "EHLO mail-lj1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726669AbgBTHiB (ORCPT ); Thu, 20 Feb 2020 02:38:01 -0500 Received: by mail-lj1-f196.google.com with SMTP id q23so3147380ljm.4; Wed, 19 Feb 2020 23:37:59 -0800 (PST) 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:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=uigwYHxU5jqQSo9ZHCSgPRPA1LdoPZqY742MGPvWnH0=; b=Fj9wQJkofm2W/at8w3cgXX5XxhLKSou/oxFlTfk/1yCjRYnkfJuGhOwgjNushH2YqH QrzQwChyc76kDaisfK0k8KPQhpN3SjZXWwzidZSu3u02THbUB/FmRXl2HLq6JegMY5Mv t/71y0Wf3Hn2NXF5Bb2Y8DJ+5LUJZbFTm8/BKcFPRlllLupVXtiNd0UEASqMOd0gSdZH czu0F9eEZJW0qjDdFcSlY29V5jntXrspYyDlvS+L0BeBxl5yN9Uujdj102SmFhWzjLnO sCL1XzNNlnFWIdjp6zNJ9fhp+8lRtvLkrcA9/NIF1zhk99bMvtG0wU8ZcKwrsV0UZS3o KdkA== X-Gm-Message-State: APjAAAVx/h397FnzV+1QG6Kks3iWXYGeh1NILS9nxjEMRfF7TX5Xdsx5 a9SbnTlARpEUwADoXISl35M= X-Google-Smtp-Source: APXvYqzT9iEmd6Ly86CVJZq2SpbZg+Zk9JLg/U/E1RSIJmC/qmdhkvE2PqFbBNY9CdPzAb6iQyrkdA== X-Received: by 2002:a2e:9218:: with SMTP id k24mr17554469ljg.262.1582184278844; Wed, 19 Feb 2020 23:37:58 -0800 (PST) Received: from localhost.localdomain ([213.255.186.46]) by smtp.gmail.com with ESMTPSA id f9sm1182368ljp.62.2020.02.19.23.37.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Feb 2020 23:37:58 -0800 (PST) Date: Thu, 20 Feb 2020 09:37:51 +0200 From: Matti Vaittinen To: matti.vaittinen@fi.rohmeurope.com, mazziesaccount@gmail.com Cc: Sebastian Reichel , Rob Herring , Mark Rutland , Greg Kroah-Hartman , "Rafael J. Wysocki" , Liam Girdwood , Mark Brown , "GitAuthor: Matti Vaittinen" , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Markus Laine , Mikko Mutanen Subject: [RFC PATCH v3 7/8] power: supply: add battery parameters Message-ID: <1bc9241259c89c9429f6a162758f5607a1dbca72.1582182989.git.matti.vaittinen@fi.rohmeurope.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.12.1 (2019-06-15) Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Add parsing of new device-tree battery bindings. - trickle-charge-current-microamp - precharge-upper-limit-microvolt - re-charge-voltage-microvolt - over-voltage-threshold-microvolt Signed-off-by: Matti Vaittinen --- drivers/power/supply/power_supply_core.c | 8 ++++++++ include/linux/power_supply.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 5c36c430ce8b..a8589b6e28f1 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -617,10 +617,18 @@ int power_supply_get_battery_info(struct power_supply *psy, &info->voltage_min_design_uv); of_property_read_u32(battery_np, "voltage-max-design-microvolt", &info->voltage_max_design_uv); + of_property_read_u32(battery_np, "trickle-charge-current-microamp", + &info->tricklecharge_current_ua); of_property_read_u32(battery_np, "precharge-current-microamp", &info->precharge_current_ua); + of_property_read_u32(battery_np, "precharge-upper-limit-microvolt", + &info->precharge_voltage_max_uv); of_property_read_u32(battery_np, "charge-term-current-microamp", &info->charge_term_current_ua); + of_property_read_u32(battery_np, "re-charge-voltage-microvolt", + &info->charge_restart_voltage_uv); + of_property_read_u32(battery_np, "over-voltage-threshold-microvolt", + &info->overvoltage_limit_uv); of_property_read_u32(battery_np, "constant-charge-current-max-microamp", &info->constant_charge_current_max_ua); of_property_read_u32(battery_np, "constant-charge-voltage-max-microvolt", diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 28413f737e7d..44c727f30669 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -341,8 +341,12 @@ struct power_supply_battery_info { int charge_full_design_uah; /* microAmp-hours */ int voltage_min_design_uv; /* microVolts */ int voltage_max_design_uv; /* microVolts */ + int tricklecharge_current_ua; /* microAmps */ int precharge_current_ua; /* microAmps */ + int precharge_voltage_max_uv; /* microVolts */ int charge_term_current_ua; /* microAmps */ + int charge_restart_voltage_uv; /* microVolts */ + int overvoltage_limit_uv; /* microVolts */ int constant_charge_current_max_ua; /* microAmps */ int constant_charge_voltage_max_uv; /* microVolts */ int factory_internal_resistance_uohm; /* microOhms */