1 // SPDX-License-Identifier: GPL-2.0
3 * helpers to map values in a linear range to range index
5 * Original idea borrowed from regulator framework
7 * It might be useful if we could support also inversely proportional ranges?
8 * Copyright 2020 ROHM Semiconductors
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>
18 * linear_range_values_in_range - return the amount of values in a range
19 * @r: pointer to linear range where values are counted
21 * Compute the amount of values in range pointed by @r. Note, values can
22 * be all equal - range with selectors 0,...,2 with step 0 still contains
23 * 3 values even though they are all equal.
25 * Return: the amount of values in range pointed by @r
27 unsigned int linear_range_values_in_range(const struct linear_range
*r
)
31 return r
->max_sel
- r
->min_sel
+ 1;
33 EXPORT_SYMBOL_GPL(linear_range_values_in_range
);
36 * linear_range_values_in_range_array - return the amount of values in ranges
37 * @r: pointer to array of linear ranges where values are counted
38 * @ranges: amount of ranges we include in computation.
40 * Compute the amount of values in ranges pointed by @r. Note, values can
41 * be all equal - range with selectors 0,...,2 with step 0 still contains
42 * 3 values even though they are all equal.
44 * Return: the amount of values in first @ranges ranges pointed by @r
46 unsigned int linear_range_values_in_range_array(const struct linear_range
*r
,
49 int i
, values_in_range
= 0;
51 for (i
= 0; i
< ranges
; i
++) {
54 values
= linear_range_values_in_range(&r
[i
]);
58 values_in_range
+= values
;
60 return values_in_range
;
62 EXPORT_SYMBOL_GPL(linear_range_values_in_range_array
);
65 * linear_range_get_max_value - return the largest value in a range
66 * @r: pointer to linear range where value is looked from
68 * Return: the largest value in the given range
70 unsigned int linear_range_get_max_value(const struct linear_range
*r
)
72 return r
->min
+ (r
->max_sel
- r
->min_sel
) * r
->step
;
74 EXPORT_SYMBOL_GPL(linear_range_get_max_value
);
77 * linear_range_get_value - fetch a value from given range
78 * @r: pointer to linear range where value is looked from
79 * @selector: selector for which the value is searched
80 * @val: address where found value is updated
82 * Search given ranges for value which matches given selector.
84 * Return: 0 on success, -EINVAL given selector is not found from any of the
87 int linear_range_get_value(const struct linear_range
*r
, unsigned int selector
,
90 if (r
->min_sel
> selector
|| r
->max_sel
< selector
)
93 *val
= r
->min
+ (selector
- r
->min_sel
) * r
->step
;
97 EXPORT_SYMBOL_GPL(linear_range_get_value
);
100 * linear_range_get_value_array - fetch a value from array of ranges
101 * @r: pointer to array of linear ranges where value is looked from
102 * @ranges: amount of ranges in an array
103 * @selector: selector for which the value is searched
104 * @val: address where found value is updated
106 * Search through an array of ranges for value which matches given selector.
108 * Return: 0 on success, -EINVAL given selector is not found from any of the
111 int linear_range_get_value_array(const struct linear_range
*r
, int ranges
,
112 unsigned int selector
, unsigned int *val
)
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
);
122 EXPORT_SYMBOL_GPL(linear_range_get_value_array
);
125 * linear_range_get_selector_low - return linear range selector for value
126 * @r: pointer to linear range where selector is looked from
127 * @val: value for which the selector is searched
128 * @selector: address where found selector value is updated
129 * @found: flag to indicate that given value was in the range
131 * Return selector which which range value is closest match for given
132 * input value. Value is matching if it is equal or smaller than given
133 * value. If given value is in the range, then @found is set true.
135 * Return: 0 on success, -EINVAL if range is invalid or does not contain
136 * value smaller or equal to given value
138 int linear_range_get_selector_low(const struct linear_range
*r
,
139 unsigned int val
, unsigned int *selector
,
147 if (linear_range_get_max_value(r
) < val
) {
148 *selector
= r
->max_sel
;
155 *selector
= r
->min_sel
;
157 *selector
= (val
- r
->min
) / r
->step
+ r
->min_sel
;
161 EXPORT_SYMBOL_GPL(linear_range_get_selector_low
);
164 * linear_range_get_selector_low_array - return linear range selector for value
165 * @r: pointer to array of linear ranges where selector is looked from
166 * @ranges: amount of ranges to scan from array
167 * @val: value for which the selector is searched
168 * @selector: address where found selector value is updated
169 * @found: flag to indicate that given value was in the range
171 * Scan array of ranges for selector which which range value matches given
172 * input value. Value is matching if it is equal or smaller than given
173 * value. If given value is found to be in a range scanning is stopped and
174 * @found is set true. If a range with values smaller than given value is found
175 * but the range max is being smaller than given value, then the ranges
176 * biggest selector is updated to @selector but scanning ranges is continued
177 * and @found is set to false.
179 * Return: 0 on success, -EINVAL if range array is invalid or does not contain
180 * range with a value smaller or equal to given value
182 int linear_range_get_selector_low_array(const struct linear_range
*r
,
183 int ranges
, unsigned int val
,
184 unsigned int *selector
, bool *found
)
189 for (i
= 0; i
< ranges
; i
++) {
192 tmpret
= linear_range_get_selector_low(&r
[i
], val
, selector
,
203 EXPORT_SYMBOL_GPL(linear_range_get_selector_low_array
);
206 * linear_range_get_selector_high - return linear range selector for value
207 * @r: pointer to linear range where selector is looked from
208 * @val: value for which the selector is searched
209 * @selector: address where found selector value is updated
210 * @found: flag to indicate that given value was in the range
212 * Return selector which which range value is closest match for given
213 * input value. Value is matching if it is equal or higher than given
214 * value. If given value is in the range, then @found is set true.
216 * Return: 0 on success, -EINVAL if range is invalid or does not contain
217 * value greater or equal to given value
219 int linear_range_get_selector_high(const struct linear_range
*r
,
220 unsigned int val
, unsigned int *selector
,
225 if (linear_range_get_max_value(r
) < val
)
229 *selector
= r
->min_sel
;
236 *selector
= r
->max_sel
;
238 *selector
= DIV_ROUND_UP(val
- r
->min
, r
->step
) + r
->min_sel
;
242 EXPORT_SYMBOL_GPL(linear_range_get_selector_high
);
244 MODULE_DESCRIPTION("linear-ranges helper");
245 MODULE_LICENSE("GPL");