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
39 if (scale > full || !scale) in iio_gts_get_gain()
40 return -EINVAL; in iio_gts_get_gain()
42 if (U64_MAX - full < scale) { in iio_gts_get_gain()
44 if (full - scale < scale) in iio_gts_get_gain()
47 full -= scale; in iio_gts_get_gain()
51 while (full > scale * (u64)tmp) in iio_gts_get_gain()
58 * gain_get_scale_fraction - get the gain or time based on scale and known one
60 * @max: Maximum linearized scale. As an example, when scale is created
61 * in magnitude of NANOs and max scale is 64.1 - The linearized
62 * scale is 64 100 000 000.
63 * @scale: Linearized scale to compute the gain/time for.
68 * Compute either gain or time based on scale and either the gain or time
73 static int gain_get_scale_fraction(const u64 max, u64 scale, int known, in gain_get_scale_fraction() argument
78 tot_gain = iio_gts_get_gain(max, scale); in gain_get_scale_fraction()
86 return -EINVAL; in gain_get_scale_fraction()
97 return -EOVERFLOW; in iio_gts_delinearize()
100 return -EINVAL; in iio_gts_delinearize()
114 * Expect scale to be (mostly) NANO or MICRO. Divide divider instead of in iio_gts_linearize()
118 return -EINVAL; in iio_gts_linearize()
127 * iio_gts_total_gain_to_scale - convert gain to scale
128 * @gts: Gain time scale descriptor
130 * @scale_int: Pointer to integral part of the scale (typically val1)
131 * @scale_nano: Pointer to fractional part of the scale (nano or ppb)
133 * Convert the total gain value to scale. NOTE: This does not separate gain
134 * generated by HW-gain or integration time. It is up to caller to decide what
135 * part of the total gain is due to integration time and what due to HW-gain.
144 tmp = gts->max_scale; in iio_gts_total_gain_to_scale()
153 * iio_gts_purge_avail_scale_table - free-up the available scale tables
154 * @gts: Gain time scale descriptor
162 if (gts->per_time_avail_scale_tables) { in iio_gts_purge_avail_scale_table()
163 for (i = 0; i < gts->num_itime; i++) in iio_gts_purge_avail_scale_table()
164 kfree(gts->per_time_avail_scale_tables[i]); in iio_gts_purge_avail_scale_table()
166 kfree(gts->per_time_avail_scale_tables); in iio_gts_purge_avail_scale_table()
167 gts->per_time_avail_scale_tables = NULL; in iio_gts_purge_avail_scale_table()
170 kfree(gts->avail_all_scales_table); in iio_gts_purge_avail_scale_table()
171 gts->avail_all_scales_table = NULL; in iio_gts_purge_avail_scale_table()
173 gts->num_avail_all_scales = 0; in iio_gts_purge_avail_scale_table()
178 return *(int *)a - *(int *)b; in iio_gts_gain_cmp()
187 for (i = 0; i < gts->num_itime; i++) { in gain_to_scaletables()
192 sort(gains[i], gts->num_hwgain, sizeof(int), iio_gts_gain_cmp, in gain_to_scaletables()
196 for (j = 0; j < gts->num_hwgain; j++) { in gain_to_scaletables()
205 gain_bytes = array_size(gts->num_hwgain, sizeof(int)); in gain_to_scaletables()
206 all_gains = kcalloc(gts->num_itime, gain_bytes, GFP_KERNEL); in gain_to_scaletables()
208 return -ENOMEM; in gain_to_scaletables()
217 time_idx = gts->num_itime - 1; in gain_to_scaletables()
219 new_idx = gts->num_hwgain; in gain_to_scaletables()
221 while (time_idx--) { in gain_to_scaletables()
222 for (j = 0; j < gts->num_hwgain; j++) { in gain_to_scaletables()
226 if (candidate > all_gains[new_idx - 1]) { in gain_to_scaletables()
240 (new_idx - chk) * sizeof(int)); in gain_to_scaletables()
246 gts->avail_all_scales_table = kcalloc(new_idx, 2 * sizeof(int), in gain_to_scaletables()
248 if (!gts->avail_all_scales_table) { in gain_to_scaletables()
249 ret = -ENOMEM; in gain_to_scaletables()
252 gts->num_avail_all_scales = new_idx; in gain_to_scaletables()
254 for (i = 0; i < gts->num_avail_all_scales; i++) { in gain_to_scaletables()
256 &gts->avail_all_scales_table[i * 2], in gain_to_scaletables()
257 &gts->avail_all_scales_table[i * 2 + 1]); in gain_to_scaletables()
260 kfree(gts->avail_all_scales_table); in gain_to_scaletables()
261 gts->num_avail_all_scales = 0; in gain_to_scaletables()
273 * iio_gts_build_avail_scale_table - create tables of available scales
274 * @gts: Gain time scale descriptor
291 int **per_time_gains, **per_time_scales, i, j, ret = -ENOMEM; in iio_gts_build_avail_scale_table()
293 per_time_gains = kcalloc(gts->num_itime, sizeof(*per_time_gains), GFP_KERNEL); in iio_gts_build_avail_scale_table()
297 per_time_scales = kcalloc(gts->num_itime, sizeof(*per_time_scales), GFP_KERNEL); in iio_gts_build_avail_scale_table()
301 for (i = 0; i < gts->num_itime; i++) { in iio_gts_build_avail_scale_table()
302 per_time_scales[i] = kcalloc(gts->num_hwgain, 2 * sizeof(int), in iio_gts_build_avail_scale_table()
307 per_time_gains[i] = kcalloc(gts->num_hwgain, sizeof(int), in iio_gts_build_avail_scale_table()
314 for (j = 0; j < gts->num_hwgain; j++) in iio_gts_build_avail_scale_table()
315 per_time_gains[i][j] = gts->hwgain_table[j].gain * in iio_gts_build_avail_scale_table()
316 gts->itime_table[i].mul; in iio_gts_build_avail_scale_table()
324 gts->per_time_avail_scale_tables = per_time_scales; in iio_gts_build_avail_scale_table()
329 for (i--; i; i--) { in iio_gts_build_avail_scale_table()
352 * iio_gts_build_avail_time_table - build table of available integration times
353 * @gts: Gain time scale descriptor
356 * to users using the read_avail-callback.
367 if (!gts->num_itime) in iio_gts_build_avail_time_table()
370 times = kcalloc(gts->num_itime, sizeof(int), GFP_KERNEL); in iio_gts_build_avail_time_table()
372 return -ENOMEM; in iio_gts_build_avail_time_table()
375 for (i = gts->num_itime - 1; i >= 0; i--) { in iio_gts_build_avail_time_table()
376 int new = gts->itime_table[i].time_us; in iio_gts_build_avail_time_table()
386 (idx - j) * sizeof(int)); in iio_gts_build_avail_time_table()
397 * This is just to survive a unlikely corner-case where times in in iio_gts_build_avail_time_table()
399 * trust the gts->num_itime. in iio_gts_build_avail_time_table()
401 gts->num_avail_time_tables = idx; in iio_gts_build_avail_time_table()
405 gts->avail_time_tables = int_micro_times; in iio_gts_build_avail_time_table()
409 return -ENOMEM; in iio_gts_build_avail_time_table()
415 * iio_gts_purge_avail_time_table - free-up the available integration time table
416 * @gts: Gain time scale descriptor
422 if (gts->num_avail_time_tables) { in iio_gts_purge_avail_time_table()
423 kfree(gts->avail_time_tables); in iio_gts_purge_avail_time_table()
424 gts->avail_time_tables = NULL; in iio_gts_purge_avail_time_table()
425 gts->num_avail_time_tables = 0; in iio_gts_purge_avail_time_table()
430 * iio_gts_build_avail_tables - create tables of available scales and int times
431 * @gts: Gain time scale descriptor
470 * iio_gts_purge_avail_tables - free-up the availability tables
471 * @gts: Gain time scale descriptor
474 * integration time and scale tables.
488 * devm_iio_gts_build_avail_tables - manged add availability tables
490 * @gts: Gain time scale descriptor
525 if (t->sel < 0 || t->time_us < 0 || t->mul <= 0) in sanity_check_time()
526 return -EINVAL; in sanity_check_time()
533 if (g->sel < 0 || g->gain <= 0) in sanity_check_gain()
534 return -EINVAL; in sanity_check_gain()
543 if (!gts->num_hwgain && !gts->num_itime) in iio_gts_sanity_check()
544 return -EINVAL; in iio_gts_sanity_check()
546 for (t = 0; t < gts->num_itime; t++) { in iio_gts_sanity_check()
547 ret = sanity_check_time(&gts->itime_table[t]); in iio_gts_sanity_check()
552 for (g = 0; g < gts->num_hwgain; g++) { in iio_gts_sanity_check()
553 ret = sanity_check_gain(&gts->hwgain_table[g]); in iio_gts_sanity_check()
558 for (g = 0; g < gts->num_hwgain; g++) { in iio_gts_sanity_check()
559 for (t = 0; t < gts->num_itime; t++) { in iio_gts_sanity_check()
562 gain = gts->hwgain_table[g].gain; in iio_gts_sanity_check()
563 mul = gts->itime_table[t].mul; in iio_gts_sanity_check()
566 return -EOVERFLOW; in iio_gts_sanity_check()
583 &gts->max_scale); in iio_init_iio_gts()
587 gts->hwgain_table = gain_tbl; in iio_init_iio_gts()
588 gts->num_hwgain = num_gain; in iio_init_iio_gts()
589 gts->itime_table = tim_tbl; in iio_init_iio_gts()
590 gts->num_itime = num_times; in iio_init_iio_gts()
596 * devm_iio_init_iio_gts - Initialize the gain-time-scale helper
599 * @max_scale_int: integer part of the maximum scale value
600 * @max_scale_nano: fraction part of the maximum scale value
612 * Initialize the gain-time-scale helper for use. Note, gains, times, selectors
636 * iio_gts_all_avail_scales - helper for listing all available scales
637 * @gts: Gain time scale descriptor
639 * @type: Type of returned scale values
647 if (!gts->num_avail_all_scales) in iio_gts_all_avail_scales()
648 return -EINVAL; in iio_gts_all_avail_scales()
650 *vals = gts->avail_all_scales_table; in iio_gts_all_avail_scales()
652 *length = gts->num_avail_all_scales * 2; in iio_gts_all_avail_scales()
659 * iio_gts_avail_scales_for_time - list scales for integration time
660 * @gts: Gain time scale descriptor
663 * @type: Type of returned scale values
666 * Drivers which do not allow scale setting to change integration time can
677 for (i = 0; i < gts->num_itime; i++) in iio_gts_avail_scales_for_time()
678 if (gts->itime_table[i].time_us == time) in iio_gts_avail_scales_for_time()
681 if (i == gts->num_itime) in iio_gts_avail_scales_for_time()
682 return -EINVAL; in iio_gts_avail_scales_for_time()
684 *vals = gts->per_time_avail_scale_tables[i]; in iio_gts_avail_scales_for_time()
686 *length = gts->num_hwgain * 2; in iio_gts_avail_scales_for_time()
693 * iio_gts_avail_times - helper for listing available integration times
694 * @gts: Gain time scale descriptor
696 * @type: Type of returned scale values
704 if (!gts->num_avail_time_tables) in iio_gts_avail_times()
705 return -EINVAL; in iio_gts_avail_times()
707 *vals = gts->avail_time_tables; in iio_gts_avail_times()
709 *length = gts->num_avail_time_tables * 2; in iio_gts_avail_times()
716 * iio_gts_find_sel_by_gain - find selector corresponding to a HW-gain
717 * @gts: Gain time scale descriptor
718 * @gain: HW-gain for which matching selector is searched for
720 * Return: a selector matching given HW-gain or -EINVAL if selector was
727 for (i = 0; i < gts->num_hwgain; i++) in iio_gts_find_sel_by_gain()
728 if (gts->hwgain_table[i].gain == gain) in iio_gts_find_sel_by_gain()
729 return gts->hwgain_table[i].sel; in iio_gts_find_sel_by_gain()
731 return -EINVAL; in iio_gts_find_sel_by_gain()
736 * iio_gts_find_gain_by_sel - find HW-gain corresponding to a selector
737 * @gts: Gain time scale descriptor
738 * @sel: selector for which matching HW-gain is searched for
740 * Return: a HW-gain matching given selector or -EINVAL if HW-gain was not
747 for (i = 0; i < gts->num_hwgain; i++) in iio_gts_find_gain_by_sel()
748 if (gts->hwgain_table[i].sel == sel) in iio_gts_find_gain_by_sel()
749 return gts->hwgain_table[i].gain; in iio_gts_find_gain_by_sel()
751 return -EINVAL; in iio_gts_find_gain_by_sel()
756 * iio_gts_get_min_gain - find smallest valid HW-gain
757 * @gts: Gain time scale descriptor
759 * Return: The smallest HW-gain -EINVAL if no HW-gains were in the tables.
763 int i, min = -EINVAL; in iio_gts_get_min_gain()
765 for (i = 0; i < gts->num_hwgain; i++) { in iio_gts_get_min_gain()
766 int gain = gts->hwgain_table[i].gain; in iio_gts_get_min_gain()
768 if (min == -EINVAL) in iio_gts_get_min_gain()
779 * iio_find_closest_gain_low - Find the closest lower matching gain
780 * @gts: Gain time scale descriptor
781 * @gain: HW-gain for which the closest match is searched
791 * Return: The closest matching supported gain or -EINVAL if @gain
797 int best = -1; in iio_find_closest_gain_low()
801 for (i = 0; i < gts->num_hwgain; i++) { in iio_find_closest_gain_low()
802 if (gain == gts->hwgain_table[i].gain) { in iio_find_closest_gain_low()
807 if (gain > gts->hwgain_table[i].gain) { in iio_find_closest_gain_low()
809 diff = gain - gts->hwgain_table[i].gain; in iio_find_closest_gain_low()
812 int tmp = gain - gts->hwgain_table[i].gain; in iio_find_closest_gain_low()
821 * We found valid HW-gain which is greater than in iio_find_closest_gain_low()
823 * will have found an in-range gain in iio_find_closest_gain_low()
832 return -EINVAL; in iio_find_closest_gain_low()
835 return gts->hwgain_table[best].gain; in iio_find_closest_gain_low()
846 return -EINVAL; in iio_gts_get_int_time_gain_multiplier_by_sel()
848 return time->mul; in iio_gts_get_int_time_gain_multiplier_by_sel()
852 * iio_gts_find_gain_for_scale_using_time - Find gain by time and scale
853 * @gts: Gain time scale descriptor
856 * @scale_int: Integral part of the scale (typically val1)
857 * @scale_nano: Fractional part of the scale (nano or ppb)
861 * corresponds given scale and integration time. Sensors which fill the
864 * Return: 0 on success. -EINVAL if gain matching the parameters is not
884 ret = gain_get_scale_fraction(gts->max_scale, scale_linear, mul, gain); in iio_gts_find_gain_for_scale_using_time()
889 return -EINVAL; in iio_gts_find_gain_for_scale_using_time()
895 * iio_gts_find_gain_sel_for_scale_using_time - Fetch gain selector.
896 * @gts: Gain time scale descriptor
899 * @scale_int: Integral part of the scale (typically val1)
900 * @scale_nano: Fractional part of the scale (nano or ppb)
931 return -EINVAL; in iio_gts_get_total_gain()
933 if (!gts->num_itime) in iio_gts_get_total_gain()
938 return -EINVAL; in iio_gts_get_total_gain()
940 return gain * itime->mul; in iio_gts_get_total_gain()
944 u64 *scale) in iio_gts_get_scale_linear() argument
953 tmp = gts->max_scale; in iio_gts_get_scale_linear()
957 *scale = tmp; in iio_gts_get_scale_linear()
963 * iio_gts_get_scale - get scale based on integration time and HW-gain
964 * @gts: Gain time scale descriptor
965 * @gain: HW-gain for which the scale is computed
966 * @time: Integration time for which the scale is computed
967 * @scale_int: Integral part of the scale (typically val1)
968 * @scale_nano: Fractional part of the scale (nano or ppb)
970 * Compute scale matching the integration time and HW-gain given as parameter.
989 * iio_gts_find_new_gain_sel_by_old_gain_time - compensate for time change
990 * @gts: Gain time scale descriptor
996 * We may want to mitigate the scale change caused by setting a new integration
998 * new gain value to maintain the scale with new integration time.
1001 * non-zero value is returned, the @new_gain will be set to a negative or
1006 * gain required to maintain the scale would not be an integer. In this case,
1015 u64 scale; in iio_gts_find_new_gain_sel_by_old_gain_time() local
1018 *new_gain = -1; in iio_gts_find_new_gain_sel_by_old_gain_time()
1022 return -EINVAL; in iio_gts_find_new_gain_sel_by_old_gain_time()
1026 return -EINVAL; in iio_gts_find_new_gain_sel_by_old_gain_time()
1028 ret = iio_gts_get_scale_linear(gts, old_gain, itime_old->time_us, in iio_gts_find_new_gain_sel_by_old_gain_time()
1029 &scale); in iio_gts_find_new_gain_sel_by_old_gain_time()
1033 ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul, in iio_gts_find_new_gain_sel_by_old_gain_time()
1039 return -EINVAL; in iio_gts_find_new_gain_sel_by_old_gain_time()
1046 * iio_gts_find_new_gain_by_old_gain_time - compensate for time change
1047 * @gts: Gain time scale descriptor
1053 * We may want to mitigate the scale change caused by setting a new integration
1055 * new gain value to maintain the scale with new integration time.
1058 * non-zero value is returned, the @new_gain will be set to a negative or
1063 * gain required to maintain the scale would not be an integer. In this case,
1072 u64 scale; in iio_gts_find_new_gain_by_old_gain_time() local
1075 *new_gain = -1; in iio_gts_find_new_gain_by_old_gain_time()
1079 return -EINVAL; in iio_gts_find_new_gain_by_old_gain_time()
1081 ret = iio_gts_get_scale_linear(gts, old_gain, old_time, &scale); in iio_gts_find_new_gain_by_old_gain_time()
1085 ret = gain_get_scale_fraction(gts->max_scale, scale, itime_new->mul, in iio_gts_find_new_gain_by_old_gain_time()
1091 return -EINVAL; in iio_gts_find_new_gain_by_old_gain_time()
1099 MODULE_DESCRIPTION("IIO light sensor gain-time-scale helpers");