From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
To: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Cc: Mark Rutland <mark.rutland@arm.com>,
Andrei Stefanescu <andrei.stefanescu@microchip.com>,
Heiko Stuebner <heiko@sntech.de>,
"Rafael J. Wysocki" <rafael@kernel.org>,
Tony Lindgren <tony@atomide.com>,
Linus Walleij <linus.walleij@linaro.org>,
Brendan Higgins <brendanhiggins@google.com>,
Liam Girdwood <lgirdwood@gmail.com>,
Andreas Kemnade <andreas@kemnade.info>,
"Angelo G. Del Regno" <kholk11@gmail.com>,
Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>,
linux-samsung-soc@vger.kernel.org, linux-omap@vger.kernel.org,
Axel Lin <axel.lin@ingics.com>,
Gregory CLEMENT <gregory.clement@bootlin.com>,
Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>,
Krzysztof Kozlowski <krzk@kernel.org>,
Markus Reichl <m.reichl@fivetechno.de>,
Bartosz Golaszewski <bgolaszewski@baylibre.com>,
Chen-Yu Tsai <wens@csie.org>, Andy Gross <agross@kernel.org>,
markus.laine@fi.rohmeurope.com,
Adam Thomson <Adam.Thomson.Opensource@diasemi.com>,
devicetree@vger.kernel.org,
Charles Keepax <ckeepax@opensource.cirrus.com>,
mazziesaccount@gmail.com, linux-arm-msm@vger.kernel.org,
Richard Fitzgerald <rf@opensource.cirrus.com>,
Mark Brown <broonie@kernel.org>,
linux-mediatek@lists.infradead.org,
Matthias Brugger <matthias.bgg@gmail.com>,
Thomas Gleixner <tglx@linutronix.de>,
Bjorn Andersson <bjorn.andersson@linaro.org>,
linux-arm-kernel@lists.infradead.org,
Support Opensource <support.opensource@diasemi.com>,
Baolin Wang <baolin.wang@linaro.org>,
Sangbeom Kim <sbkim73@samsung.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-pm@vger.kernel.org, Randy Dunlap <rdunlap@infradead.org>,
Sebastian Reichel <sre@kernel.org>,
linux-kernel@vger.kernel.org, mikko.mutanen@fi.rohmeurope.com,
Vinod Koul <vkoul@kernel.org>, Rob Herring <robh+dt@kernel.org>,
patches@opensource.cirrus.com
Subject: Re: [PATCH v8 03/10] lib: add linear ranges helpers
Date: Fri, 3 Apr 2020 12:37:11 +0300 [thread overview]
Message-ID: <20200403093711.GJ1922688@smile.fi.intel.com> (raw)
In-Reply-To: <05ef7d49f1e2a895ac6688bfdd444d2cbba53e6e.1585902279.git.matti.vaittinen@fi.rohmeurope.com>
On Fri, Apr 03, 2020 at 11:45:47AM +0300, Matti Vaittinen wrote:
> 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 'meaningful' 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
> meaningful units - and driver needs to convert the values it reads
> from register to these meaningful 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.
>
> Current implementation does not support inversely proportional ranges
> but it might be useful if we could support also inversely proportional
> ranges?
>
FWIW,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
> Reviewed-by: Mark Brown <broonie@kernel.org>
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> ---
>
> Changes since v7:
> - Cleanups suggested by Andy, no functional changes
>
> include/linux/linear_range.h | 48 +++++++
> lib/Kconfig | 3 +
> lib/Makefile | 1 +
> lib/linear_ranges.c | 241 +++++++++++++++++++++++++++++++++++
> 4 files changed, 293 insertions(+)
> create mode 100644 include/linux/linear_range.h
> create mode 100644 lib/linear_ranges.c
>
> diff --git a/include/linux/linear_range.h b/include/linux/linear_range.h
> new file mode 100644
> index 000000000000..17b5943727d5
> --- /dev/null
> +++ b/include/linux/linear_range.h
> @@ -0,0 +1,48 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2020 ROHM Semiconductors */
> +
> +#ifndef LINEAR_RANGE_H
> +#define LINEAR_RANGE_H
> +
> +#include <linux/types.h>
> +
> +/**
> + * 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
> diff --git a/lib/Kconfig b/lib/Kconfig
> index bc7e56370129..411ab2d2d800 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -19,6 +19,9 @@ config RAID6_PQ_BENCHMARK
> Benchmark all available RAID6 PQ functions on init and choose the
> fastest one.
>
> +config LINEAR_RANGES
> + tristate
> +
> config PACKING
> bool "Generic bitfield packing and unpacking"
> default n
> diff --git a/lib/Makefile b/lib/Makefile
> index 611872c06926..18c3d313872e 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -122,6 +122,7 @@ obj-$(CONFIG_DEBUG_LIST) += list_debug.o
> obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o
>
> obj-$(CONFIG_BITREVERSE) += bitrev.o
> +obj-$(CONFIG_LINEAR_RANGES) += linear_ranges.o
> obj-$(CONFIG_PACKING) += packing.o
> obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
> obj-$(CONFIG_CRC16) += crc16.o
> diff --git a/lib/linear_ranges.c b/lib/linear_ranges.c
> new file mode 100644
> index 000000000000..d1336c75ccd7
> --- /dev/null
> +++ b/lib/linear_ranges.c
> @@ -0,0 +1,241 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * 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 <linux/errno.h>
> +#include <linux/export.h>
> +#include <linux/kernel.h>
> +#include <linux/linear_range.h>
> +
> +/**
> + * 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.
> + *
> + * Return: 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_GPL(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.
> + *
> + * Return: 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_GPL(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
> + *
> + * Return: 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_GPL(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.
> + *
> + * Return: 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_GPL(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.
> + *
> + * Return: 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_GPL(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 selector 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.
> + *
> + * Return: 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) {
> + *selector = r->max_sel;
> + return 0;
> + }
> +
> + *found = true;
> +
> + if (r->step == 0)
> + *selector = r->min_sel;
> + else
> + *selector = (val - r->min) / r->step + r->min_sel;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(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 selector is searched
> + * @selector: address where found selector value is updated
> + * @found: flag to indicate that given value was in the range
> + *
> + * 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 scanning 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.
> + *
> + * Return: 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_GPL(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 selector 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.
> + *
> + * Return: 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) {
> + *selector = r->min_sel;
> + return 0;
> + }
> +
> + *found = true;
> +
> + if (r->step == 0)
> + *selector = r->max_sel;
> + else
> + *selector = DIV_ROUND_UP(val - r->min, r->step) + r->min_sel;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(linear_range_get_selector_high);
> --
> 2.21.0
>
>
> --
> Matti Vaittinen, Linux device drivers
> ROHM Semiconductors, Finland SWDC
> Kiviharjunlenkki 1E
> 90220 OULU
> FINLAND
>
> ~~~ "I don't think so," said Rene Descartes. Just then he vanished ~~~
> Simon says - in Latin please.
> ~~~ "non cogito me" dixit Rene Descarte, deinde evanescavit ~~~
> Thanks to Simon Glass for the translation =]
--
With Best Regards,
Andy Shevchenko
_______________________________________________
Linux-mediatek mailing list
Linux-mediatek@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-mediatek
next prev parent reply other threads:[~2020-04-03 9:37 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-03 8:36 [PATCH v8 00/10] Support ROHM BD99954 charger IC Matti Vaittinen
2020-04-03 8:41 ` [PATCH v8 01/10] dt-bindings: battery: add new battery parameters Matti Vaittinen
2020-04-05 3:28 ` Sebastian Reichel
2020-04-03 8:45 ` [PATCH v8 02/10] dt_bindings: ROHM BD99954 Charger Matti Vaittinen
2020-04-05 3:30 ` Sebastian Reichel
2020-04-03 8:45 ` [PATCH v8 03/10] lib: add linear ranges helpers Matti Vaittinen
2020-04-03 9:37 ` Andy Shevchenko [this message]
2020-04-03 8:46 ` [PATCH v8 04/10] lib/test_linear_ranges: add a test for the 'linear_ranges' Matti Vaittinen
2020-04-03 8:46 ` [PATCH v8 05/10] power: supply: bd70528: rename linear_range to avoid collision Matti Vaittinen
2020-04-05 3:33 ` Sebastian Reichel
2020-04-06 9:21 ` Vaittinen, Matti
2020-04-03 8:46 ` [PATCH v8 06/10] regulator: use linear_ranges helper Matti Vaittinen
2020-04-03 8:47 ` [PATCH v8 07/10] power: supply: bd70528: use linear ranges Matti Vaittinen
2020-04-05 3:37 ` Sebastian Reichel
2020-04-03 8:47 ` [PATCH v8 08/10] power: supply: add battery parameters Matti Vaittinen
2020-04-05 3:35 ` Sebastian Reichel
2020-04-03 8:48 ` [PATCH v8 09/10] power: supply: Support ROHM bd99954 charger Matti Vaittinen
2020-04-03 9:41 ` Andy Shevchenko
2020-04-05 3:22 ` Sebastian Reichel
2020-04-06 9:59 ` Vaittinen, Matti
2020-04-03 8:48 ` [PATCH v8 10/10] power: supply: Fix Kconfig help text indentiation Matti Vaittinen
2020-04-05 3:35 ` Sebastian Reichel
2020-04-03 10:07 ` [PATCH v8 00/10] Support ROHM BD99954 charger IC Vaittinen, Matti
2020-04-03 11:02 ` andriy.shevchenko
2020-04-03 11:13 ` Vaittinen, Matti
2020-04-03 11:50 ` andriy.shevchenko
2020-04-03 11:51 ` andriy.shevchenko
2020-04-03 12:01 ` Mark Brown
2020-04-03 12:30 ` Vaittinen, Matti
2020-04-03 12:31 ` Mark Brown
2020-04-05 3:27 ` Sebastian Reichel
2020-04-06 5:22 ` Vaittinen, Matti
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200403093711.GJ1922688@smile.fi.intel.com \
--to=andriy.shevchenko@linux.intel.com \
--cc=Adam.Thomson.Opensource@diasemi.com \
--cc=agross@kernel.org \
--cc=andreas@kemnade.info \
--cc=andrei.stefanescu@microchip.com \
--cc=axel.lin@ingics.com \
--cc=b.zolnierkie@samsung.com \
--cc=baolin.wang@linaro.org \
--cc=bgolaszewski@baylibre.com \
--cc=bjorn.andersson@linaro.org \
--cc=brendanhiggins@google.com \
--cc=broonie@kernel.org \
--cc=ckeepax@opensource.cirrus.com \
--cc=devicetree@vger.kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=gregory.clement@bootlin.com \
--cc=heiko@sntech.de \
--cc=hsin-hsiung.wang@mediatek.com \
--cc=kholk11@gmail.com \
--cc=krzk@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linus.walleij@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mediatek@lists.infradead.org \
--cc=linux-omap@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-samsung-soc@vger.kernel.org \
--cc=m.reichl@fivetechno.de \
--cc=mark.rutland@arm.com \
--cc=markus.laine@fi.rohmeurope.com \
--cc=matthias.bgg@gmail.com \
--cc=matti.vaittinen@fi.rohmeurope.com \
--cc=mazziesaccount@gmail.com \
--cc=mikko.mutanen@fi.rohmeurope.com \
--cc=patches@opensource.cirrus.com \
--cc=rafael@kernel.org \
--cc=rdunlap@infradead.org \
--cc=rf@opensource.cirrus.com \
--cc=robh+dt@kernel.org \
--cc=sbkim73@samsung.com \
--cc=sre@kernel.org \
--cc=support.opensource@diasemi.com \
--cc=tglx@linutronix.de \
--cc=tony@atomide.com \
--cc=vkoul@kernel.org \
--cc=wens@csie.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).