brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · a1a7dfa Raw
277 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * helpers to map values in a linear range to range index4 *5 * Original idea borrowed from regulator framework6 *7 * It might be useful if we could support also inversely proportional ranges?8 * Copyright 2020 ROHM Semiconductors9 */10 11#include <linux/errno.h>12#include <linux/export.h>13#include <linux/kernel.h>14#include <linux/linear_range.h>15#include <linux/module.h>16 17/**18 * linear_range_values_in_range - return the amount of values in a range19 * @r:		pointer to linear range where values are counted20 *21 * Compute the amount of values in range pointed by @r. Note, values can22 * be all equal - range with selectors 0,...,2 with step 0 still contains23 * 3 values even though they are all equal.24 *25 * Return: the amount of values in range pointed by @r26 */27unsigned int linear_range_values_in_range(const struct linear_range *r)28{29	if (!r)30		return 0;31	return r->max_sel - r->min_sel + 1;32}33EXPORT_SYMBOL_GPL(linear_range_values_in_range);34 35/**36 * linear_range_values_in_range_array - return the amount of values in ranges37 * @r:		pointer to array of linear ranges where values are counted38 * @ranges:	amount of ranges we include in computation.39 *40 * Compute the amount of values in ranges pointed by @r. Note, values can41 * be all equal - range with selectors 0,...,2 with step 0 still contains42 * 3 values even though they are all equal.43 *44 * Return: the amount of values in first @ranges ranges pointed by @r45 */46unsigned int linear_range_values_in_range_array(const struct linear_range *r,47						int ranges)48{49	int i, values_in_range = 0;50 51	for (i = 0; i < ranges; i++) {52		int values;53 54		values = linear_range_values_in_range(&r[i]);55		if (!values)56			return values;57 58		values_in_range += values;59	}60	return values_in_range;61}62EXPORT_SYMBOL_GPL(linear_range_values_in_range_array);63 64/**65 * linear_range_get_max_value - return the largest value in a range66 * @r:		pointer to linear range where value is looked from67 *68 * Return: the largest value in the given range69 */70unsigned int linear_range_get_max_value(const struct linear_range *r)71{72	return r->min + (r->max_sel - r->min_sel) * r->step;73}74EXPORT_SYMBOL_GPL(linear_range_get_max_value);75 76/**77 * linear_range_get_value - fetch a value from given range78 * @r:		pointer to linear range where value is looked from79 * @selector:	selector for which the value is searched80 * @val:	address where found value is updated81 *82 * Search given ranges for value which matches given selector.83 *84 * Return: 0 on success, -EINVAL given selector is not found from any of the85 * ranges.86 */87int linear_range_get_value(const struct linear_range *r, unsigned int selector,88			   unsigned int *val)89{90	if (r->min_sel > selector || r->max_sel < selector)91		return -EINVAL;92 93	*val = r->min + (selector - r->min_sel) * r->step;94 95	return 0;96}97EXPORT_SYMBOL_GPL(linear_range_get_value);98 99/**100 * linear_range_get_value_array - fetch a value from array of ranges101 * @r:		pointer to array of linear ranges where value is looked from102 * @ranges:	amount of ranges in an array103 * @selector:	selector for which the value is searched104 * @val:	address where found value is updated105 *106 * Search through an array of ranges for value which matches given selector.107 *108 * Return: 0 on success, -EINVAL given selector is not found from any of the109 * ranges.110 */111int linear_range_get_value_array(const struct linear_range *r, int ranges,112				 unsigned int selector, unsigned int *val)113{114	int i;115 116	for (i = 0; i < ranges; i++)117		if (r[i].min_sel <= selector && r[i].max_sel >= selector)118			return linear_range_get_value(&r[i], selector, val);119 120	return -EINVAL;121}122EXPORT_SYMBOL_GPL(linear_range_get_value_array);123 124/**125 * linear_range_get_selector_low - return linear range selector for value126 * @r:		pointer to linear range where selector is looked from127 * @val:	value for which the selector is searched128 * @selector:	address where found selector value is updated129 * @found:	flag to indicate that given value was in the range130 *131 * Return selector for which range value is closest match for given132 * input value. Value is matching if it is equal or smaller than given133 * value. If given value is in the range, then @found is set true.134 *135 * Return: 0 on success, -EINVAL if range is invalid or does not contain136 * value smaller or equal to given value137 */138int linear_range_get_selector_low(const struct linear_range *r,139				  unsigned int val, unsigned int *selector,140				  bool *found)141{142	*found = false;143 144	if (r->min > val)145		return -EINVAL;146 147	if (linear_range_get_max_value(r) < val) {148		*selector = r->max_sel;149		return 0;150	}151 152	*found = true;153 154	if (r->step == 0)155		*selector = r->min_sel;156	else157		*selector = (val - r->min) / r->step + r->min_sel;158 159	return 0;160}161EXPORT_SYMBOL_GPL(linear_range_get_selector_low);162 163/**164 * linear_range_get_selector_low_array - return linear range selector for value165 * @r:		pointer to array of linear ranges where selector is looked from166 * @ranges:	amount of ranges to scan from array167 * @val:	value for which the selector is searched168 * @selector:	address where found selector value is updated169 * @found:	flag to indicate that given value was in the range170 *171 * Scan array of ranges for selector for which range value matches given172 * input value. Value is matching if it is equal or smaller than given173 * value. If given value is found to be in a range scanning is stopped and174 * @found is set true. If a range with values smaller than given value is found175 * but the range max is being smaller than given value, then the range's176 * biggest selector is updated to @selector but scanning ranges is continued177 * and @found is set to false.178 *179 * Return: 0 on success, -EINVAL if range array is invalid or does not contain180 * range with a value smaller or equal to given value181 */182int linear_range_get_selector_low_array(const struct linear_range *r,183					int ranges, unsigned int val,184					unsigned int *selector, bool *found)185{186	int i;187	int ret = -EINVAL;188 189	for (i = 0; i < ranges; i++) {190		int tmpret;191 192		tmpret = linear_range_get_selector_low(&r[i], val, selector,193						       found);194		if (!tmpret)195			ret = 0;196 197		if (*found)198			break;199	}200 201	return ret;202}203EXPORT_SYMBOL_GPL(linear_range_get_selector_low_array);204 205/**206 * linear_range_get_selector_high - return linear range selector for value207 * @r:		pointer to linear range where selector is looked from208 * @val:	value for which the selector is searched209 * @selector:	address where found selector value is updated210 * @found:	flag to indicate that given value was in the range211 *212 * Return selector for which range value is closest match for given213 * input value. Value is matching if it is equal or higher than given214 * value. If given value is in the range, then @found is set true.215 *216 * Return: 0 on success, -EINVAL if range is invalid or does not contain217 * value greater or equal to given value218 */219int linear_range_get_selector_high(const struct linear_range *r,220				   unsigned int val, unsigned int *selector,221				   bool *found)222{223	*found = false;224 225	if (linear_range_get_max_value(r) < val)226		return -EINVAL;227 228	if (r->min > val) {229		*selector = r->min_sel;230		return 0;231	}232 233	*found = true;234 235	if (r->step == 0)236		*selector = r->max_sel;237	else238		*selector = DIV_ROUND_UP(val - r->min, r->step) + r->min_sel;239 240	return 0;241}242EXPORT_SYMBOL_GPL(linear_range_get_selector_high);243 244/**245 * linear_range_get_selector_within - return linear range selector for value246 * @r:		pointer to linear range where selector is looked from247 * @val:	value for which the selector is searched248 * @selector:	address where found selector value is updated249 *250 * Return selector for which range value is closest match for given251 * input value. Value is matching if it is equal or lower than given252 * value. But return maximum selector if given value is higher than253 * maximum value.254 */255void linear_range_get_selector_within(const struct linear_range *r,256				      unsigned int val, unsigned int *selector)257{258	if (r->min > val) {259		*selector = r->min_sel;260		return;261	}262 263	if (linear_range_get_max_value(r) < val) {264		*selector = r->max_sel;265		return;266	}267 268	if (r->step == 0)269		*selector = r->min_sel;270	else271		*selector = (val - r->min) / r->step + r->min_sel;272}273EXPORT_SYMBOL_GPL(linear_range_get_selector_within);274 275MODULE_DESCRIPTION("linear-ranges helper");276MODULE_LICENSE("GPL");277