iio: light: Add gain-time-scale helpers
[platform/kernel/linux-starfive.git] / include / linux / iio / iio-gts-helper.h
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 &gts->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 &gts->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  * @gain:       HW-gain 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