![]() |
|
|||
0001 // SPDX-License-Identifier: GPL-2.0 0002 /* 0003 * helpers to map values in a linear range to range index 0004 * 0005 * Original idea borrowed from regulator framework 0006 * 0007 * It might be useful if we could support also inversely proportional ranges? 0008 * Copyright 2020 ROHM Semiconductors 0009 */ 0010 0011 #include <linux/errno.h> 0012 #include <linux/export.h> 0013 #include <linux/kernel.h> 0014 #include <linux/linear_range.h> 0015 #include <linux/module.h> 0016 0017 /** 0018 * linear_range_values_in_range - return the amount of values in a range 0019 * @r: pointer to linear range where values are counted 0020 * 0021 * Compute the amount of values in range pointed by @r. Note, values can 0022 * be all equal - range with selectors 0,...,2 with step 0 still contains 0023 * 3 values even though they are all equal. 0024 * 0025 * Return: the amount of values in range pointed by @r 0026 */ 0027 unsigned int linear_range_values_in_range(const struct linear_range *r) 0028 { 0029 if (!r) 0030 return 0; 0031 return r->max_sel - r->min_sel + 1; 0032 } 0033 EXPORT_SYMBOL_GPL(linear_range_values_in_range); 0034 0035 /** 0036 * linear_range_values_in_range_array - return the amount of values in ranges 0037 * @r: pointer to array of linear ranges where values are counted 0038 * @ranges: amount of ranges we include in computation. 0039 * 0040 * Compute the amount of values in ranges pointed by @r. Note, values can 0041 * be all equal - range with selectors 0,...,2 with step 0 still contains 0042 * 3 values even though they are all equal. 0043 * 0044 * Return: the amount of values in first @ranges ranges pointed by @r 0045 */ 0046 unsigned int linear_range_values_in_range_array(const struct linear_range *r, 0047 int ranges) 0048 { 0049 int i, values_in_range = 0; 0050 0051 for (i = 0; i < ranges; i++) { 0052 int values; 0053 0054 values = linear_range_values_in_range(&r[i]); 0055 if (!values) 0056 return values; 0057 0058 values_in_range += values; 0059 } 0060 return values_in_range; 0061 } 0062 EXPORT_SYMBOL_GPL(linear_range_values_in_range_array); 0063 0064 /** 0065 * linear_range_get_max_value - return the largest value in a range 0066 * @r: pointer to linear range where value is looked from 0067 * 0068 * Return: the largest value in the given range 0069 */ 0070 unsigned int linear_range_get_max_value(const struct linear_range *r) 0071 { 0072 return r->min + (r->max_sel - r->min_sel) * r->step; 0073 } 0074 EXPORT_SYMBOL_GPL(linear_range_get_max_value); 0075 0076 /** 0077 * linear_range_get_value - fetch a value from given range 0078 * @r: pointer to linear range where value is looked from 0079 * @selector: selector for which the value is searched 0080 * @val: address where found value is updated 0081 * 0082 * Search given ranges for value which matches given selector. 0083 * 0084 * Return: 0 on success, -EINVAL given selector is not found from any of the 0085 * ranges. 0086 */ 0087 int linear_range_get_value(const struct linear_range *r, unsigned int selector, 0088 unsigned int *val) 0089 { 0090 if (r->min_sel > selector || r->max_sel < selector) 0091 return -EINVAL; 0092 0093 *val = r->min + (selector - r->min_sel) * r->step; 0094 0095 return 0; 0096 } 0097 EXPORT_SYMBOL_GPL(linear_range_get_value); 0098 0099 /** 0100 * linear_range_get_value_array - fetch a value from array of ranges 0101 * @r: pointer to array of linear ranges where value is looked from 0102 * @ranges: amount of ranges in an array 0103 * @selector: selector for which the value is searched 0104 * @val: address where found value is updated 0105 * 0106 * Search through an array of ranges for value which matches given selector. 0107 * 0108 * Return: 0 on success, -EINVAL given selector is not found from any of the 0109 * ranges. 0110 */ 0111 int linear_range_get_value_array(const struct linear_range *r, int ranges, 0112 unsigned int selector, unsigned int *val) 0113 { 0114 int i; 0115 0116 for (i = 0; i < ranges; i++) 0117 if (r[i].min_sel <= selector && r[i].max_sel >= selector) 0118 return linear_range_get_value(&r[i], selector, val); 0119 0120 return -EINVAL; 0121 } 0122 EXPORT_SYMBOL_GPL(linear_range_get_value_array); 0123 0124 /** 0125 * linear_range_get_selector_low - return linear range selector for value 0126 * @r: pointer to linear range where selector is looked from 0127 * @val: value for which the selector is searched 0128 * @selector: address where found selector value is updated 0129 * @found: flag to indicate that given value was in the range 0130 * 0131 * Return selector for which range value is closest match for given 0132 * input value. Value is matching if it is equal or smaller than given 0133 * value. If given value is in the range, then @found is set true. 0134 * 0135 * Return: 0 on success, -EINVAL if range is invalid or does not contain 0136 * value smaller or equal to given value 0137 */ 0138 int linear_range_get_selector_low(const struct linear_range *r, 0139 unsigned int val, unsigned int *selector, 0140 bool *found) 0141 { 0142 *found = false; 0143 0144 if (r->min > val) 0145 return -EINVAL; 0146 0147 if (linear_range_get_max_value(r) < val) { 0148 *selector = r->max_sel; 0149 return 0; 0150 } 0151 0152 *found = true; 0153 0154 if (r->step == 0) 0155 *selector = r->min_sel; 0156 else 0157 *selector = (val - r->min) / r->step + r->min_sel; 0158 0159 return 0; 0160 } 0161 EXPORT_SYMBOL_GPL(linear_range_get_selector_low); 0162 0163 /** 0164 * linear_range_get_selector_low_array - return linear range selector for value 0165 * @r: pointer to array of linear ranges where selector is looked from 0166 * @ranges: amount of ranges to scan from array 0167 * @val: value for which the selector is searched 0168 * @selector: address where found selector value is updated 0169 * @found: flag to indicate that given value was in the range 0170 * 0171 * Scan array of ranges for selector for which range value matches given 0172 * input value. Value is matching if it is equal or smaller than given 0173 * value. If given value is found to be in a range scanning is stopped and 0174 * @found is set true. If a range with values smaller than given value is found 0175 * but the range max is being smaller than given value, then the range's 0176 * biggest selector is updated to @selector but scanning ranges is continued 0177 * and @found is set to false. 0178 * 0179 * Return: 0 on success, -EINVAL if range array is invalid or does not contain 0180 * range with a value smaller or equal to given value 0181 */ 0182 int linear_range_get_selector_low_array(const struct linear_range *r, 0183 int ranges, unsigned int val, 0184 unsigned int *selector, bool *found) 0185 { 0186 int i; 0187 int ret = -EINVAL; 0188 0189 for (i = 0; i < ranges; i++) { 0190 int tmpret; 0191 0192 tmpret = linear_range_get_selector_low(&r[i], val, selector, 0193 found); 0194 if (!tmpret) 0195 ret = 0; 0196 0197 if (*found) 0198 break; 0199 } 0200 0201 return ret; 0202 } 0203 EXPORT_SYMBOL_GPL(linear_range_get_selector_low_array); 0204 0205 /** 0206 * linear_range_get_selector_high - return linear range selector for value 0207 * @r: pointer to linear range where selector is looked from 0208 * @val: value for which the selector is searched 0209 * @selector: address where found selector value is updated 0210 * @found: flag to indicate that given value was in the range 0211 * 0212 * Return selector for which range value is closest match for given 0213 * input value. Value is matching if it is equal or higher than given 0214 * value. If given value is in the range, then @found is set true. 0215 * 0216 * Return: 0 on success, -EINVAL if range is invalid or does not contain 0217 * value greater or equal to given value 0218 */ 0219 int linear_range_get_selector_high(const struct linear_range *r, 0220 unsigned int val, unsigned int *selector, 0221 bool *found) 0222 { 0223 *found = false; 0224 0225 if (linear_range_get_max_value(r) < val) 0226 return -EINVAL; 0227 0228 if (r->min > val) { 0229 *selector = r->min_sel; 0230 return 0; 0231 } 0232 0233 *found = true; 0234 0235 if (r->step == 0) 0236 *selector = r->max_sel; 0237 else 0238 *selector = DIV_ROUND_UP(val - r->min, r->step) + r->min_sel; 0239 0240 return 0; 0241 } 0242 EXPORT_SYMBOL_GPL(linear_range_get_selector_high); 0243 0244 /** 0245 * linear_range_get_selector_within - return linear range selector for value 0246 * @r: pointer to linear range where selector is looked from 0247 * @val: value for which the selector is searched 0248 * @selector: address where found selector value is updated 0249 * 0250 * Return selector for which range value is closest match for given 0251 * input value. Value is matching if it is equal or lower than given 0252 * value. But return maximum selector if given value is higher than 0253 * maximum value. 0254 */ 0255 void linear_range_get_selector_within(const struct linear_range *r, 0256 unsigned int val, unsigned int *selector) 0257 { 0258 if (r->min > val) { 0259 *selector = r->min_sel; 0260 return; 0261 } 0262 0263 if (linear_range_get_max_value(r) < val) { 0264 *selector = r->max_sel; 0265 return; 0266 } 0267 0268 if (r->step == 0) 0269 *selector = r->min_sel; 0270 else 0271 *selector = (val - r->min) / r->step + r->min_sel; 0272 } 0273 EXPORT_SYMBOL_GPL(linear_range_get_selector_within); 0274 0275 MODULE_DESCRIPTION("linear-ranges helper"); 0276 MODULE_LICENSE("GPL");
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |