linux-mediatek.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
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

  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).