Lines Matching +full:full +full:- +full:scale
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* gain-time-scale conversion helpers for IIO light sensors
18 #include <linux/iio/iio-gts-helper.h>
22 * iio_gts_get_gain - Convert scale to total gain
24 * Internal helper for converting scale to total gain.
26 * @max: Maximum linearized scale. As an example, when scale is created
27 * in magnitude of NANOs and max scale is 64.1 - The linearized
28 * scale is 64 100 000 000.
29 * @scale: Linearized scale to compute the gain for.
31 * Return: (floored) gain corresponding to the scale. -EINVAL if scale
34 static int iio_gts_get_gain(const u64 max, const u64 scale) in iio_gts_get_gain() argument
36 u64 full = max; in iio_gts_get_gain() local
38 if (scale > full || !scale) in iio_gts_get_gain()
39 return -EINVAL; in iio_gts_get_gain()
41 return div64_u64(full, scale); in iio_gts_get_gain()
45 * gain_get_scale_fraction - get the gain or time based on scale and known one
47 * @max: Maximum linearized scale. As an example, when scale is created
48 * in magnitude of NANOs and max scale is 64.1 - The linearized
49 * scale is 64 100 000 000.
50 * @scale: Linearized scale to compute the gain/time for.
55 * Compute either gain or time based on scale and either the gain or time
60 static int gain_get_scale_fraction(const u64 max, u64 scale, int known, in gain_get_scale_fraction() argument
65 tot_gain = iio_gts_get_gain(max, scale); in gain_get_scale_fraction()
73 return -EINVAL; in gain_get_scale_fraction()
84 return -EOVERFLOW; in iio_gts_delinearize()
87 return -EINVAL; in iio_gts_delinearize()
101 * Expect scale to be (mostly) NANO or MICRO. Divide divider instead of in iio_gts_linearize()
105 return -EINVAL; in iio_gts_linearize()
114 * iio_gts_total_gain_to_scale - convert gain to scale
115 * @gts: Gain time scale descriptor
117 * @scale_int: Pointer to integral part of the scale (typically val1)
118 * @scale_nano: Pointer to fractional part of the scale (nano or ppb)
120 * Convert the total gain value to scale. NOTE: This does not separate gain
121 * generated by HW-gain or integration time. It is up to caller to decide what
122 * part of the total gain is due to integration time and what due to HW-gain.
131 tmp = gts->max_scale; in iio_gts_total_gain_to_scale()
140 * iio_gts_purge_avail_scale_table - free-up the available scale tables
141 * @gts: Gain time scale descriptor
149 if (gts->per_time_avail_scale_tables) { in iio_gts_purge_avail_scale_table()
150 for (i = 0; i < gts->num_itime; i++) in iio_gts_purge_avail_scale_table()
151 kfree(gts->per_time_avail_scale_tables[i]); in iio_gts_purge_avail_scale_table()
153 kfree(gts->per_time_avail_scale_tables); in iio_gts_purge_avail_scale_table()
154 gts->per_time_avail_scale_tables = NULL; in iio_gts_purge_avail_scale_table()
157 kfree(gts->avail_all_scales_table); in iio_gts_purge_avail_scale_table()
158 gts->avail_all_scales_table = NULL; in iio_gts_purge_avail_scale_table()
160 gts->num_avail_all_scales = 0; in iio_gts_purge_avail_scale_table()
165 return *(int *)a - *(int *)b; in iio_gts_gain_cmp()
174 for (i = 0; i < gts->num_itime; i++) { in gain_to_scaletables()
179 sort(gains[i], gts->num_hwgain, sizeof(int), iio_gts_gain_cmp, in gain_to_scaletables()
183 for (j = 0; j < gts->num_hwgain; j++) { in gain_to_scaletables()
192 gain_bytes = array_size(gts->num_hwgain, sizeof(int)); in gain_to_scaletables()
193 all_gains = kcalloc(gts->num_itime, gain_bytes, GFP_KERNEL); in gain_to_scaletables()
195 return -ENOMEM; in gain_to_scaletables()
204 time_idx = gts->num_itime - 1; in gain_to_scaletables()
206 new_idx = gts->num_hwgain; in gain_to_scaletables()
208 while (time_idx--) { in gain_to_scaletables()
209 for (j = 0; j < gts->num_hwgain; j++) { in gain_to_scaletables()
213 if (candidate > all_gains[new_idx - 1]) { in gain_to_scaletables()
227 (new_idx - chk) * sizeof(int)); in gain_to_scaletables()
233 gts->avail_all_scales_table = kcalloc(new_idx, 2 * sizeof(int), in gain_to_scaletables()
235 if (!gts->avail_all_scales_table) { in gain_to_scaletables()
236 ret = -ENOMEM; in gain_to_scaletables()
239 gts->num_avail_all_scales = new_idx; in gain_to_scaletables()
241 for (i = 0; i < gts->num_avail_all_scales; i++) { in gain_to_scaletables()
243 >s->avail_all_scales_table[i * 2], in gain_to_scaletables()
244 >s->avail_all_scales_table[i * 2 + 1]); in gain_to_scaletables()
247 kfree(gts->avail_all_scales_table); in gain_to_scaletables()
248 gts->num_avail_all_scales = 0; in gain_to_scaletables()
260 * iio_gts_build_avail_scale_table - create tables of available scales
261 * @gts: Gain time scale descriptor
278 int **per_time_gains, **per_time_scales, i, j, ret = -ENOMEM; in iio_gts_build_avail_scale_table()
280 per_time_gains = kcalloc(gts->num_itime, sizeof(*per_time_gains), GFP_KERNEL); in iio_gts_build_avail_scale_table()
284 per_time_scales = kcalloc(gts->num_itime, sizeof(*per_time_scales), GFP_KERNEL); in iio_gts_build_avail_scale_table()
288 for (i = 0; i < gts->num_itime; i++) { in iio_gts_build_avail_scale_table()
289 per_time_scales[i] = kcalloc(gts->num_hwgain, 2 * sizeof(int), in iio_gts_build_avail_scale_table()
294 per_time_gains[i] = kcalloc(gts->num_hwgain, sizeof(int), in iio_gts_build_avail_scale_table()
301 for (j = 0; j < gts->num_hwgain; j++) in iio_gts_build_avail_scale_table()
302 per_time_gains[i][j] = gts->hwgain_table[j].gain * in iio_gts_build_avail_scale_table()
303 gts->itime_table[i].mul; in iio_gts_build_avail_scale_table()
310 for (i = 0; i < gts->num_itime; i++) in iio_gts_build_avail_scale_table()
313 gts->per_time_avail_scale_tables = per_time_scales; in iio_gts_build_avail_scale_table()
318 for (i--; i >= 0; i--) { in iio_gts_build_avail_scale_table()
341 * iio_gts_build_avail_time_table - build table of available integration times
342 * @gts: Gain time scale descriptor
345 * to users using the read_avail-callback.
356 if (!gts->num_itime) in iio_gts_build_avail_time_table()
359 times = kcalloc(gts->num_itime, sizeof(int), GFP_KERNEL); in iio_gts_build_avail_time_table()
361 return -ENOMEM; in iio_gts_build_avail_time_table()
364 for (i = gts->num_itime - 1; i >= 0; i--) { in iio_gts_build_avail_time_table()
365 int new = gts->itime_table[i].time_us; in iio_gts_build_avail_time_table()
367 if (idx == 0 || times[idx - 1] < new) { in iio_gts_build_avail_time_table()
377 (idx - j) * sizeof(int)); in iio_gts_build_avail_time_table()
389 * This is just to survive a unlikely corner-case where times in in iio_gts_build_avail_time_table()
391 * trust the gts->num_itime. in iio_gts_build_avail_time_table()
393 gts->num_avail_time_tables = idx; in iio_gts_build_avail_time_table()
397 gts->avail_time_tables = int_micro_times; in iio_gts_build_avail_time_table()
401 return -ENOMEM; in iio_gts_build_avail_time_table()
407 * iio_gts_purge_avail_time_table - free-up the available integration time table
408 * @gts: Gain time scale descriptor
414 if (gts->num_avail_time_tables) { in iio_gts_purge_avail_time_table()
415 kfree(gts->avail_time_tables); in iio_gts_purge_avail_time_table()
416 gts->avail_time_tables = NULL; in iio_gts_purge_avail_time_table()
417 gts->num_avail_time_tables = 0; in iio_gts_purge_avail_time_table()
422 * iio_gts_build_avail_tables - create tables of available scales and int times
423 * @gts: Gain time scale descriptor
462 * iio_gts_purge_avail_tables - free-up the availability tables
463 * @gts: Gain time scale descriptor
466 * integration time and scale tables.
480 * devm_iio_gts_build_avail_tables - manged add availability tables
482 * @gts: Gain time scale descriptor
517 if (t->sel < 0 || t->time_us < 0 || t->mul <= 0) in sanity_check_time()
518 return -EINVAL; in sanity_check_time()
525 if (g->sel < 0 || g->gain <= 0) in sanity_check_gain()
526 return -EINVAL; in sanity_check_gain()
535 if (!gts->num_hwgain && !gts->num_itime) in iio_gts_sanity_check()
536 return -EINVAL; in iio_gts_sanity_check()
538 for (t = 0; t < gts->num_itime; t++) { in iio_gts_sanity_check()
539 ret = sanity_check_time(>s->itime_table[t]); in iio_gts_sanity_check()
544 for (g = 0; g < gts->num_hwgain; g++) { in iio_gts_sanity_check()
545 ret = sanity_check_gain(>s->hwgain_table[g]); in iio_gts_sanity_check()
550 for (g = 0; g < gts->num_hwgain; g++) { in iio_gts_sanity_check()
551 for (t = 0; t < gts->num_itime; t++) { in iio_gts_sanity_check()
554 gain = gts->hwgain_table[g].gain; in iio_gts_sanity_check()
555 mul = gts->itime_table[t].mul; in iio_gts_sanity_check()
558 return -EOVERFLOW; in iio_gts_sanity_check()
575 >s->max_scale); in iio_init_iio_gts()
579 gts->hwgain_table = gain_tbl; in iio_init_iio_gts()
580 gts->num_hwgain = num_gain; in iio_init_iio_gts()
581 gts->itime_table = tim_tbl; in iio_init_iio_gts()
582 gts->num_itime = num_times; in iio_init_iio_gts()
588 * devm_iio_init_iio_gts - Initialize the gain-time-scale helper
591 * @max_scale_int: integer part of the maximum scale value
592 * @max_scale_nano: fraction part of the maximum scale value
604 * Initialize the gain-time-scale helper for use. Note, gains, times, selectors
628 * iio_gts_all_avail_scales - helper for listing all available scales
629 * @gts: Gain time scale descriptor
631 * @type: Type of returned scale values
639 if (!gts->num_avail_all_scales) in iio_gts_all_avail_scales()
640 return -EINVAL; in iio_gts_all_avail_scales()
642 *vals = gts->avail_all_scales_table; in iio_gts_all_avail_scales()
644 *length = gts->num_avail_all_scales * 2; in iio_gts_all_avail_scales()
651 * iio_gts_avail_scales_for_time - list scales for integration time
652 * @gts: Gain time scale descriptor
655 * @type: Type of returned scale values
658 * Drivers which do not allow scale setting to change integration time can
669 for (i = 0; i < gts->num_itime; i++) in iio_gts_avail_scales_for_time()
670 if (gts->itime_table[i].time_us == time) in iio_gts_avail_scales_for_time()
673 if (i == gts->num_itime) in iio_gts_avail_scales_for_time()
674 return -EINVAL; in iio_gts_avail_scales_for_time()
676 *vals = gts->per_time_avail_scale_tables[i]; in iio_gts_avail_scales_for_time()
678 *length = gts->num_hwgain * 2; in iio_gts_avail_scales_for_time()
685 * iio_gts_avail_times - helper for listing available integration times
686 * @gts: Gain time scale descriptor
688 * @type: Type of returned scale values
696 if (!gts->num_avail_time_tables) in iio_gts_avail_times()
697 return -EINVAL; in iio_gts_avail_times()
699 *vals = gts->avail_time_tables; in iio_gts_avail_times()
701 *length = gts->num_avail_time_tables * 2; in iio_gts_avail_times()
708 * iio_gts_find_sel_by_gain - find selector corresponding to a HW-gain
709 * @gts: Gain time scale descriptor
710 * @gain: HW-gain for which matching selector is searched for
712 * Return: a selector matching given HW-gain or -EINVAL if selector was
719 for (i = 0; i < gts->num_hwgain; i++) in iio_gts_find_sel_by_gain()
720 if (gts->hwgain_table[i].gain == gain) in iio_gts_find_sel_by_gain()
721 return gts->hwgain_table[i].sel; in iio_gts_find_sel_by_gain()
723 return -EINVAL; in iio_gts_find_sel_by_gain()
728 * iio_gts_find_gain_by_sel - find HW-gain corresponding to a selector
729 * @gts: Gain time scale descriptor
730 * @sel: selector for which matching HW-gain is searched for
732 * Return: a HW-gain matching given selector or -EINVAL if HW-gain was not
739 for (i = 0; i < gts->num_hwgain; i++) in iio_gts_find_gain_by_sel()
740 if (gts->hwgain_table[i].sel == sel) in iio_gts_find_gain_by_sel()
741 return gts->hwgain_table[i].gain; in iio_gts_find_gain_by_sel()
743 return -EINVAL; in iio_gts_find_gain_by_sel()
748 * iio_gts_get_min_gain - find smallest valid HW-gain
749 * @gts: Gain time scale descriptor
751 * Return: The smallest HW-gain -EINVAL if no HW-gains were in the tables.
755 int i, min = -EINVAL; in iio_gts_get_min_gain()
757 for (i = 0; i < gts->num_hwgain; i++) { in iio_gts_get_min_gain()
758 int gain = gts->hwgain_table[i].gain; in iio_gts_get_min_gain()
760 if (min == -EINVAL) in iio_gts_get_min_gain()
771 * iio_find_closest_gain_low - Find the closest lower matching gain
772 * @gts: Gain time scale descriptor
773 * @gain: HW-gain for which the closest match is searched
783 * Return: The closest matching supported gain or -EINVAL if @gain
789 int best = -1; in iio_find_closest_gain_low()
793 for (i = 0; i < gts->num_hwgain; i++) { in iio_find_closest_gain_low()
794 if (gain == gts->hwgain_table[i].gain) { in iio_find_closest_gain_low()
799 if (gain > gts->hwgain_table[i].gain) { in iio_find_closest_gain_low()
801 diff = gain - gts->hwgain_table[i].gain; in iio_find_closest_gain_low()
804 int tmp = gain - gts->hwgain_table[i].gain; in iio_find_closest_gain_low()
813 * We found valid HW-gain which is greater than in iio_find_closest_gain_low()
815 * will have found an in-range gain in iio_find_closest_gain_low()
824 return -EINVAL; in iio_find_closest_gain_low()
827 return gts->hwgain_table[best].gain; in iio_find_closest_gain_low()
838 return -EINVAL; in iio_gts_get_int_time_gain_multiplier_by_sel()
840 return time->mul; in iio_gts_get_int_time_gain_multiplier_by_sel()
844 * iio_gts_find_gain_for_scale_using_time - Find gain by time and scale
845 * @gts: Gain time scale descriptor
848 * @scale_int: Integral part of the scale (typically val1)
849 * @scale_nano: Fractional part of the scale (nano or ppb)
853 * corresponds given scale and integration time. Sensors which fill the
856 * Return: 0 on success. -EINVAL if gain matching the parameters is not
876 ret = gain_get_scale_fraction(gts->max_scale, scale_linear, mul, gain); in iio_gts_find_gain_for_scale_using_time()
881 return -EINVAL; in iio_gts_find_gain_for_scale_using_time()
887 * iio_gts_find_gain_sel_for_scale_using_time - Fetch gain selector.
888 * @gts: Gain time scale descriptor
891 * @scale_int: Integral part of the scale (typically val1)
892 * @scale_nano: Fractional part of the scale (nano or ppb)
923 return -EINVAL; in iio_gts_get_total_gain()
925 if (!gts->num_itime) in iio_gts_get_total_gain()
930 return -EINVAL; in iio_gts_get_total_gain()
932 return gain * itime->mul; in iio_gts_get_total_gain()
936 u64 *scale) in iio_gts_get_scale_linear() argument
945 tmp = gts->max_scale; in iio_gts_get_scale_linear()
949 *scale = tmp; in iio_gts_get_scale_linear()
955 * iio_gts_get_scale - get scale based on integration time and HW-gain
956 * @gts: Gain time scale descriptor
957 * @gain: HW-gain for which the scale is computed
958 * @time: Integration time for which the scale is computed
959 * @scale_int: Integral part of the scale (typically val1)
960 * @scale_nano: Fractional part of the scale (nano or ppb)
962 * Compute scale matching the integration time and HW-gain given as parameter.
981 * iio_gts_find_new_gain_sel_by_old_gain_time - compensate for time change
982 * @gts: Gain time scale descriptor
988 * We may want to mitigate the scale change caused by setting a new integration
990 * new gain value to maintain the scale with new integration time.
993 * non-zero value is returned, the @new_gain will be set to a negative or
998 * gain required to maintain the scale would not be an integer. In this case,
1007 u64 scale; in iio_gts_find_new_gain_sel_by_old_gain_time() local
1010 *new_gain = -1; in iio_gts_find_new_gain_sel_by_old_gain_time()
1014 return -EINVAL; in iio_gts_find_new_gain_sel_by_old_gain_time()
1018 return -EINVAL; in iio_gts_find_new_gain_sel_by_old_gain_time()
1020 ret = iio_gts_get_scale_linear(gts, old_gain, itime_old->time_us, in iio_gts_find_new_gain_sel_by_old_gain_time()
1021 &scale); in iio_gts_find_new_gain_sel_by_old_gain_time()
1025 ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul, in iio_gts_find_new_gain_sel_by_old_gain_time()
1031 return -EINVAL; in iio_gts_find_new_gain_sel_by_old_gain_time()
1038 * iio_gts_find_new_gain_by_old_gain_time - compensate for time change
1039 * @gts: Gain time scale descriptor
1045 * We may want to mitigate the scale change caused by setting a new integration
1047 * new gain value to maintain the scale with new integration time.
1050 * non-zero value is returned, the @new_gain will be set to a negative or
1055 * gain required to maintain the scale would not be an integer. In this case,
1064 u64 scale; in iio_gts_find_new_gain_by_old_gain_time() local
1067 *new_gain = -1; in iio_gts_find_new_gain_by_old_gain_time()
1071 return -EINVAL; in iio_gts_find_new_gain_by_old_gain_time()
1073 ret = iio_gts_get_scale_linear(gts, old_gain, old_time, &scale); in iio_gts_find_new_gain_by_old_gain_time()
1077 ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul, in iio_gts_find_new_gain_by_old_gain_time()
1083 return -EINVAL; in iio_gts_find_new_gain_by_old_gain_time()
1091 MODULE_DESCRIPTION("IIO light sensor gain-time-scale helpers");