1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* gain-time-scale conversion helpers for IIO light sensors 3 * 4 * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com> 5 */ 6 7 #ifndef __IIO_GTS_HELPER__ 8 #define __IIO_GTS_HELPER__ 9 10 #include <linux/types.h> 11 12 struct device; 13 14 /** 15 * struct iio_gain_sel_pair - gain - selector values 16 * 17 * In many cases devices like light sensors allow setting signal amplification 18 * (gain) using a register interface. This structure describes amplification 19 * and corresponding selector (register value) 20 * 21 * @gain: Gain (multiplication) value. Gain must be positive, negative 22 * values are reserved for error handling. 23 * @sel: Selector (usually register value) used to indicate this gain. 24 * NOTE: Only selectors >= 0 supported. 25 */ 26 struct iio_gain_sel_pair { 27 int gain; 28 int sel; 29 }; 30 31 /** 32 * struct iio_itime_sel_mul - integration time description 33 * 34 * In many cases devices like light sensors allow setting the duration of 35 * collecting data. Typically this duration has also an impact to the magnitude 36 * of measured values (gain). This structure describes the relation of 37 * integration time and amplification as well as corresponding selector 38 * (register value). 39 * 40 * An example could be a sensor allowing 50, 100, 200 and 400 mS times. The 41 * respective multiplication values could be 50 mS => 1, 100 mS => 2, 42 * 200 mS => 4 and 400 mS => 8 assuming the impact of integration time would be 43 * linear in a way that when collecting data for 50 mS caused value X, doubling 44 * the data collection time caused value 2X etc. 45 * 46 * @time_us: Integration time in microseconds. Time values must be positive, 47 * negative values are reserved for error handling. 48 * @sel: Selector (usually register value) used to indicate this time 49 * NOTE: Only selectors >= 0 supported. 50 * @mul: Multiplication to the values caused by this time. 51 * NOTE: Only multipliers > 0 supported. 52 */ 53 struct iio_itime_sel_mul { 54 int time_us; 55 int sel; 56 int mul; 57 }; 58 59 struct iio_gts { 60 u64 max_scale; 61 const struct iio_gain_sel_pair *hwgain_table; 62 int num_hwgain; 63 const struct iio_itime_sel_mul *itime_table; 64 int num_itime; 65 int **per_time_avail_scale_tables; 66 int *avail_all_scales_table; 67 int num_avail_all_scales; 68 int *avail_time_tables; 69 int num_avail_time_tables; 70 }; 71 72 #define GAIN_SCALE_GAIN(_gain, _sel) \ 73 { \ 74 .gain = (_gain), \ 75 .sel = (_sel), \ 76 } 77 78 #define GAIN_SCALE_ITIME_US(_itime, _sel, _mul) \ 79 { \ 80 .time_us = (_itime), \ 81 .sel = (_sel), \ 82 .mul = (_mul), \ 83 } 84 85 static inline const struct iio_itime_sel_mul * 86 iio_gts_find_itime_by_time(struct iio_gts *gts, int time) 87 { 88 int i; 89 90 if (!gts->num_itime) 91 return NULL; 92 93 for (i = 0; i < gts->num_itime; i++) 94 if (gts->itime_table[i].time_us == time) 95 return >s->itime_table[i]; 96 97 return NULL; 98 } 99 100 static inline const struct iio_itime_sel_mul * 101 iio_gts_find_itime_by_sel(struct iio_gts *gts, int sel) 102 { 103 int i; 104 105 for (i = 0; i < gts->num_itime; i++) 106 if (gts->itime_table[i].sel == sel) 107 return >s->itime_table[i]; 108 109 return NULL; 110 } 111 112 int devm_iio_init_iio_gts(struct device *dev, int max_scale_int, int max_scale_nano, 113 const struct iio_gain_sel_pair *gain_tbl, int num_gain, 114 const struct iio_itime_sel_mul *tim_tbl, int num_times, 115 struct iio_gts *gts); 116 /** 117 * iio_gts_find_int_time_by_sel - find integration time matching a selector 118 * @gts: Gain time scale descriptor 119 * @sel: selector for which matching integration time is searched for 120 * 121 * Return: integration time matching given selector or -EINVAL if 122 * integration time was not found. 123 */ 124 static inline int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel) 125 { 126 const struct iio_itime_sel_mul *itime; 127 128 itime = iio_gts_find_itime_by_sel(gts, sel); 129 if (!itime) 130 return -EINVAL; 131 132 return itime->time_us; 133 } 134 135 /** 136 * iio_gts_find_sel_by_int_time - find selector matching integration time 137 * @gts: Gain time scale descriptor 138 * @time: Integration time for which matching selector is searched for 139 * 140 * Return: a selector matching given integration time or -EINVAL if 141 * selector was not found. 142 */ 143 static inline int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time) 144 { 145 const struct iio_itime_sel_mul *itime; 146 147 itime = iio_gts_find_itime_by_time(gts, time); 148 if (!itime) 149 return -EINVAL; 150 151 return itime->sel; 152 } 153 154 /** 155 * iio_gts_valid_time - check if given integration time is valid 156 * @gts: Gain time scale descriptor 157 * @time_us: Integration time to check 158 * 159 * Return: True if given time is supported by device. False if not. 160 */ 161 static inline bool iio_gts_valid_time(struct iio_gts *gts, int time_us) 162 { 163 return iio_gts_find_itime_by_time(gts, time_us) != NULL; 164 } 165 166 int iio_gts_find_sel_by_gain(struct iio_gts *gts, int gain); 167 168 /** 169 * iio_gts_valid_gain - check if given HW-gain is valid 170 * @gts: Gain time scale descriptor 171 * @gain: HW-gain to check 172 * 173 * Return: True if given time is supported by device. False if not. 174 */ 175 static inline bool iio_gts_valid_gain(struct iio_gts *gts, int gain) 176 { 177 return iio_gts_find_sel_by_gain(gts, gain) >= 0; 178 } 179 180 int iio_find_closest_gain_low(struct iio_gts *gts, int gain, bool *in_range); 181 int iio_gts_find_gain_by_sel(struct iio_gts *gts, int sel); 182 int iio_gts_get_min_gain(struct iio_gts *gts); 183 int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel); 184 int iio_gts_find_sel_by_int_time(struct iio_gts *gts, int time); 185 186 int iio_gts_total_gain_to_scale(struct iio_gts *gts, int total_gain, 187 int *scale_int, int *scale_nano); 188 int iio_gts_find_gain_sel_for_scale_using_time(struct iio_gts *gts, int time_sel, 189 int scale_int, int scale_nano, 190 int *gain_sel); 191 int iio_gts_get_scale(struct iio_gts *gts, int gain, int time, int *scale_int, 192 int *scale_nano); 193 int iio_gts_find_new_gain_sel_by_old_gain_time(struct iio_gts *gts, 194 int old_gain, int old_time_sel, 195 int new_time_sel, int *new_gain); 196 int iio_gts_find_new_gain_by_old_gain_time(struct iio_gts *gts, int old_gain, 197 int old_time, int new_time, 198 int *new_gain); 199 int iio_gts_avail_times(struct iio_gts *gts, const int **vals, int *type, 200 int *length); 201 int iio_gts_all_avail_scales(struct iio_gts *gts, const int **vals, int *type, 202 int *length); 203 int iio_gts_avail_scales_for_time(struct iio_gts *gts, int time, 204 const int **vals, int *type, int *length); 205 206 #endif 207