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: 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 | |