GNU Linux-libre 6.9.1-gnu
[releases.git] / drivers / iio / test / iio-test-gts.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Unit tests for IIO light sensor gain-time-scale helpers
3  *
4  * Copyright (c) 2023 Matti Vaittinen <mazziesaccount@gmail.com>
5  */
6
7 #include <kunit/device.h>
8 #include <kunit/test.h>
9 #include <linux/device.h>
10 #include <linux/iio/iio-gts-helper.h>
11 #include <linux/iio/types.h>
12
13 /*
14  * Please, read the "rant" from the top of the lib/test_linear_ranges.c if
15  * you see a line of helper code which is not being tested.
16  *
17  * Then, please look at the line which is not being tested. Is this line
18  * somehow unusually complex? If answer is "no", then chances are that the
19  * "development inertia" caused by adding a test exceeds the benefits.
20  *
21  * If yes, then adding a test is probably a good idea but please stop for a
22  * moment and consider the effort of changing all the tests when code gets
23  * refactored. Eventually it neeeds to be.
24  */
25
26 #define TEST_TSEL_50            1
27 #define TEST_TSEL_X_MIN         TEST_TSEL_50
28 #define TEST_TSEL_100           0
29 #define TEST_TSEL_200           2
30 #define TEST_TSEL_400           4
31 #define TEST_TSEL_X_MAX         TEST_TSEL_400
32
33 #define TEST_GSEL_1             0x00
34 #define TEST_GSEL_X_MIN         TEST_GSEL_1
35 #define TEST_GSEL_4             0x08
36 #define TEST_GSEL_16            0x0a
37 #define TEST_GSEL_32            0x0b
38 #define TEST_GSEL_64            0x0c
39 #define TEST_GSEL_256           0x18
40 #define TEST_GSEL_512           0x19
41 #define TEST_GSEL_1024          0x1a
42 #define TEST_GSEL_2048          0x1b
43 #define TEST_GSEL_4096          0x1c
44 #define TEST_GSEL_X_MAX         TEST_GSEL_4096
45
46 #define TEST_SCALE_1X           64
47 #define TEST_SCALE_MIN_X        TEST_SCALE_1X
48 #define TEST_SCALE_2X           32
49 #define TEST_SCALE_4X           16
50 #define TEST_SCALE_8X           8
51 #define TEST_SCALE_16X          4
52 #define TEST_SCALE_32X          2
53 #define TEST_SCALE_64X          1
54
55 #define TEST_SCALE_NANO_128X    500000000
56 #define TEST_SCALE_NANO_256X    250000000
57 #define TEST_SCALE_NANO_512X    125000000
58 #define TEST_SCALE_NANO_1024X   62500000
59 #define TEST_SCALE_NANO_2048X   31250000
60 #define TEST_SCALE_NANO_4096X   15625000
61 #define TEST_SCALE_NANO_4096X2  7812500
62 #define TEST_SCALE_NANO_4096X4  3906250
63 #define TEST_SCALE_NANO_4096X8  1953125
64
65 #define TEST_SCALE_NANO_MAX_X TEST_SCALE_NANO_4096X8
66
67 /*
68  * Can't have this allocated from stack because the kunit clean-up will
69  * happen only after the test function has already gone
70  */
71 static struct iio_gts gts;
72
73 static const struct iio_gain_sel_pair gts_test_gains[] = {
74         GAIN_SCALE_GAIN(1, TEST_GSEL_1),
75         GAIN_SCALE_GAIN(4, TEST_GSEL_4),
76         GAIN_SCALE_GAIN(16, TEST_GSEL_16),
77         GAIN_SCALE_GAIN(32, TEST_GSEL_32),
78         GAIN_SCALE_GAIN(64, TEST_GSEL_64),
79         GAIN_SCALE_GAIN(256, TEST_GSEL_256),
80         GAIN_SCALE_GAIN(512, TEST_GSEL_512),
81         GAIN_SCALE_GAIN(1024, TEST_GSEL_1024),
82         GAIN_SCALE_GAIN(2048, TEST_GSEL_2048),
83         GAIN_SCALE_GAIN(4096, TEST_GSEL_4096),
84 #define HWGAIN_MAX 4096
85 };
86
87 static const struct iio_itime_sel_mul gts_test_itimes[] = {
88         GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8),
89         GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
90         GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2),
91         GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1),
92 #define TIMEGAIN_MAX 8
93 };
94 #define TOTAL_GAIN_MAX  (HWGAIN_MAX * TIMEGAIN_MAX)
95 #define IIO_GTS_TEST_DEV "iio-gts-test-dev"
96
97 static struct device *__test_init_iio_gain_scale(struct kunit *test,
98                 struct iio_gts *gts, const struct iio_gain_sel_pair *g_table,
99                 int num_g, const struct iio_itime_sel_mul *i_table, int num_i)
100 {
101         struct device *dev;
102         int ret;
103
104         dev = kunit_device_register(test, IIO_GTS_TEST_DEV);
105
106         KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev);
107         if (IS_ERR_OR_NULL(dev))
108                 return NULL;
109
110         ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, g_table, num_g,
111                                     i_table, num_i, gts);
112         KUNIT_EXPECT_EQ(test, 0, ret);
113         if (ret)
114                 return NULL;
115
116         return dev;
117 }
118
119 #define test_init_iio_gain_scale(test, gts)     \
120         __test_init_iio_gain_scale(test, gts, gts_test_gains, \
121                                    ARRAY_SIZE(gts_test_gains), gts_test_itimes, \
122                                    ARRAY_SIZE(gts_test_itimes))
123
124 static void test_init_iio_gts_invalid(struct kunit *test)
125 {
126         struct device *dev;
127         int ret;
128         const struct iio_itime_sel_mul itimes_neg[] = {
129                 GAIN_SCALE_ITIME_US(-10, TEST_TSEL_400, 8),
130                 GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
131         };
132         const struct iio_gain_sel_pair gains_neg[] = {
133                 GAIN_SCALE_GAIN(1, TEST_GSEL_1),
134                 GAIN_SCALE_GAIN(2, TEST_GSEL_4),
135                 GAIN_SCALE_GAIN(-2, TEST_GSEL_16),
136         };
137         /* 55555 * 38656 = 2147534080 => overflows 32bit int */
138         const struct iio_itime_sel_mul itimes_overflow[] = {
139                 GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 55555),
140                 GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4),
141         };
142         const struct iio_gain_sel_pair gains_overflow[] = {
143                 GAIN_SCALE_GAIN(1, TEST_GSEL_1),
144                 GAIN_SCALE_GAIN(2, TEST_GSEL_4),
145                 GAIN_SCALE_GAIN(38656, TEST_GSEL_16),
146         };
147
148         dev = kunit_device_register(test, IIO_GTS_TEST_DEV);
149         KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev);
150         if (!dev)
151                 return;
152
153         /* Ok gains, negative time */
154         ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gts_test_gains,
155                                     ARRAY_SIZE(gts_test_gains), itimes_neg,
156                                     ARRAY_SIZE(itimes_neg), &gts);
157         KUNIT_EXPECT_EQ(test, -EINVAL, ret);
158
159         /* Ok times, negative gain */
160         ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_neg,
161                                     ARRAY_SIZE(gains_neg), gts_test_itimes,
162                                     ARRAY_SIZE(gts_test_itimes), &gts);
163         KUNIT_EXPECT_EQ(test, -EINVAL, ret);
164
165         /* gain * time overflow int */
166         ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_overflow,
167                                     ARRAY_SIZE(gains_overflow), itimes_overflow,
168                                     ARRAY_SIZE(itimes_overflow), &gts);
169         KUNIT_EXPECT_EQ(test, -EOVERFLOW, ret);
170 }
171
172 static void test_iio_gts_find_gain_for_scale_using_time(struct kunit *test)
173 {
174         struct device *dev;
175         int ret, gain_sel;
176
177         dev = test_init_iio_gain_scale(test, &gts);
178         if (!dev)
179                 return;
180
181         ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_100,
182                                                 TEST_SCALE_8X, 0, &gain_sel);
183         /*
184          * Meas time 100 => gain by time 2x
185          * TEST_SCALE_8X matches total gain 8x
186          * => required HWGAIN 4x
187          */
188         KUNIT_EXPECT_EQ(test, 0, ret);
189         KUNIT_EXPECT_EQ(test, TEST_GSEL_4, gain_sel);
190
191         ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_200, 0,
192                                                 TEST_SCALE_NANO_256X, &gain_sel);
193         /*
194          * Meas time 200 => gain by time 4x
195          * TEST_SCALE_256X matches total gain 256x
196          * => required HWGAIN 256/4 => 64x
197          */
198         KUNIT_EXPECT_EQ(test, 0, ret);
199         KUNIT_EXPECT_EQ(test, TEST_GSEL_64, gain_sel);
200
201         /* Min time, Min gain */
202         ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_X_MIN,
203                                                 TEST_SCALE_MIN_X, 0, &gain_sel);
204         KUNIT_EXPECT_EQ(test, 0, ret);
205         KUNIT_EXPECT_EQ(test, TEST_GSEL_1, gain_sel);
206
207         /* Max time, Max gain */
208         ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_X_MAX,
209                                         0, TEST_SCALE_NANO_MAX_X, &gain_sel);
210         KUNIT_EXPECT_EQ(test, 0, ret);
211         KUNIT_EXPECT_EQ(test, TEST_GSEL_4096, gain_sel);
212
213         ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_100, 0,
214                                                 TEST_SCALE_NANO_256X, &gain_sel);
215         /*
216          * Meas time 100 => gain by time 2x
217          * TEST_SCALE_256X matches total gain 256x
218          * => required HWGAIN 256/2 => 128x (not in gain-table - unsupported)
219          */
220         KUNIT_EXPECT_NE(test, 0, ret);
221
222         ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_200, 0,
223                                                 TEST_SCALE_NANO_MAX_X, &gain_sel);
224         /* We can't reach the max gain with integration time smaller than MAX */
225         KUNIT_EXPECT_NE(test, 0, ret);
226
227         ret = iio_gts_find_gain_sel_for_scale_using_time(&gts, TEST_TSEL_50, 0,
228                                                 TEST_SCALE_NANO_MAX_X, &gain_sel);
229         /* We can't reach the max gain with integration time smaller than MAX */
230         KUNIT_EXPECT_NE(test, 0, ret);
231 }
232
233 static void test_iio_gts_find_new_gain_sel_by_old_gain_time(struct kunit *test)
234 {
235         struct device *dev;
236         int ret, old_gain, new_gain, old_time_sel, new_time_sel;
237
238         dev = test_init_iio_gain_scale(test, &gts);
239         if (!dev)
240                 return;
241
242         old_gain = 32;
243         old_time_sel = TEST_TSEL_200;
244         new_time_sel = TEST_TSEL_400;
245
246         ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
247                                         old_time_sel, new_time_sel, &new_gain);
248         KUNIT_EXPECT_EQ(test, 0, ret);
249         /*
250          * Doubling the integration time doubles the total gain - so old
251          * (hw)gain must be divided by two to compensate. => 32 / 2 => 16
252          */
253         KUNIT_EXPECT_EQ(test, 16, new_gain);
254
255         old_gain = 4;
256         old_time_sel = TEST_TSEL_50;
257         new_time_sel = TEST_TSEL_200;
258         ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
259                                         old_time_sel, new_time_sel, &new_gain);
260         KUNIT_EXPECT_EQ(test, 0, ret);
261         /*
262          * gain by time 1x => 4x - (hw)gain 4x => 1x
263          */
264         KUNIT_EXPECT_EQ(test, 1, new_gain);
265
266         old_gain = 512;
267         old_time_sel = TEST_TSEL_400;
268         new_time_sel = TEST_TSEL_50;
269         ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
270                                         old_time_sel, new_time_sel, &new_gain);
271         KUNIT_EXPECT_EQ(test, 0, ret);
272         /*
273          * gain by time 8x => 1x - (hw)gain 512x => 4096x)
274          */
275         KUNIT_EXPECT_EQ(test, 4096, new_gain);
276
277         /* Unsupported gain 2x */
278         old_gain = 4;
279         old_time_sel = TEST_TSEL_200;
280         new_time_sel = TEST_TSEL_400;
281         ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
282                                         old_time_sel, new_time_sel, &new_gain);
283         KUNIT_EXPECT_NE(test, 0, ret);
284
285         /* Too small gain */
286         old_gain = 4;
287         old_time_sel = TEST_TSEL_50;
288         new_time_sel = TEST_TSEL_400;
289         ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
290                                         old_time_sel, new_time_sel, &new_gain);
291         KUNIT_EXPECT_NE(test, 0, ret);
292
293         /* Too big gain */
294         old_gain = 1024;
295         old_time_sel = TEST_TSEL_400;
296         new_time_sel = TEST_TSEL_50;
297         ret = iio_gts_find_new_gain_sel_by_old_gain_time(&gts, old_gain,
298                                         old_time_sel, new_time_sel, &new_gain);
299         KUNIT_EXPECT_NE(test, 0, ret);
300
301 }
302
303 static void test_iio_find_closest_gain_low(struct kunit *test)
304 {
305         struct device *dev;
306         bool in_range;
307         int ret;
308
309         const struct iio_gain_sel_pair gts_test_gains_gain_low[] = {
310                 GAIN_SCALE_GAIN(4, TEST_GSEL_4),
311                 GAIN_SCALE_GAIN(16, TEST_GSEL_16),
312                 GAIN_SCALE_GAIN(32, TEST_GSEL_32),
313         };
314
315         dev = test_init_iio_gain_scale(test, &gts);
316         if (!dev)
317                 return;
318
319         ret = iio_find_closest_gain_low(&gts, 2, &in_range);
320         KUNIT_EXPECT_EQ(test, 1, ret);
321         KUNIT_EXPECT_EQ(test, true, in_range);
322
323         ret = iio_find_closest_gain_low(&gts, 1, &in_range);
324         KUNIT_EXPECT_EQ(test, 1, ret);
325         KUNIT_EXPECT_EQ(test, true, in_range);
326
327         ret = iio_find_closest_gain_low(&gts, 4095, &in_range);
328         KUNIT_EXPECT_EQ(test, 2048, ret);
329         KUNIT_EXPECT_EQ(test, true, in_range);
330
331         ret = iio_find_closest_gain_low(&gts, 4097, &in_range);
332         KUNIT_EXPECT_EQ(test, 4096, ret);
333         KUNIT_EXPECT_EQ(test, false, in_range);
334
335         kunit_device_unregister(test, dev);
336
337         dev = __test_init_iio_gain_scale(test, &gts, gts_test_gains_gain_low,
338                                 ARRAY_SIZE(gts_test_gains_gain_low),
339                                 gts_test_itimes, ARRAY_SIZE(gts_test_itimes));
340         if (!dev)
341                 return;
342
343         ret = iio_find_closest_gain_low(&gts, 3, &in_range);
344         KUNIT_EXPECT_EQ(test, -EINVAL, ret);
345         KUNIT_EXPECT_EQ(test, false, in_range);
346 }
347
348 static void test_iio_gts_total_gain_to_scale(struct kunit *test)
349 {
350         struct device *dev;
351         int ret, scale_int, scale_nano;
352
353         dev = test_init_iio_gain_scale(test, &gts);
354         if (!dev)
355                 return;
356
357         ret = iio_gts_total_gain_to_scale(&gts, 1, &scale_int, &scale_nano);
358         KUNIT_EXPECT_EQ(test, 0, ret);
359         KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int);
360         KUNIT_EXPECT_EQ(test, 0, scale_nano);
361
362         ret = iio_gts_total_gain_to_scale(&gts, 1, &scale_int, &scale_nano);
363         KUNIT_EXPECT_EQ(test, 0, ret);
364         KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int);
365         KUNIT_EXPECT_EQ(test, 0, scale_nano);
366
367         ret = iio_gts_total_gain_to_scale(&gts, 4096 * 8, &scale_int,
368                                           &scale_nano);
369         KUNIT_EXPECT_EQ(test, 0, ret);
370         KUNIT_EXPECT_EQ(test, 0, scale_int);
371         KUNIT_EXPECT_EQ(test, TEST_SCALE_NANO_4096X8, scale_nano);
372 }
373
374 static void test_iio_gts_chk_times(struct kunit *test, const int *vals)
375 {
376         static const int expected[] = {0, 50000, 0, 100000, 0, 200000, 0, 400000};
377         int i;
378
379         for (i = 0; i < ARRAY_SIZE(expected); i++)
380                 KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
381 }
382
383 static void test_iio_gts_chk_scales_all(struct kunit *test, struct iio_gts *gts,
384                                         const int *vals, int len)
385 {
386         static const int gains[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512,
387                                     1024, 2048, 4096, 4096 * 2, 4096 * 4,
388                                     4096 * 8};
389         int expected[ARRAY_SIZE(gains) * 2];
390         int i, ret;
391         int exp_len = ARRAY_SIZE(gains) * 2;
392
393         KUNIT_EXPECT_EQ(test, exp_len, len);
394         if (len != exp_len)
395                 return;
396
397         for (i = 0; i < ARRAY_SIZE(gains); i++) {
398                 ret = iio_gts_total_gain_to_scale(gts, gains[i],
399                                                   &expected[2 * i],
400                                                   &expected[2 * i + 1]);
401                 KUNIT_EXPECT_EQ(test, 0, ret);
402                 if (ret)
403                         return;
404         }
405
406         for (i = 0; i < ARRAY_SIZE(expected); i++)
407                 KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
408 }
409
410 static void test_iio_gts_chk_scales_t200(struct kunit *test, struct iio_gts *gts,
411                                          const int *vals, int len)
412 {
413         /* The gain caused by time 200 is 4x */
414         static const int gains[] = {
415                 1 * 4,
416                 4 * 4,
417                 16 * 4,
418                 32 * 4,
419                 64 * 4,
420                 256 * 4,
421                 512 * 4,
422                 1024 * 4,
423                 2048 * 4,
424                 4096 * 4
425         };
426         int expected[ARRAY_SIZE(gains) * 2];
427         int i, ret;
428
429         KUNIT_EXPECT_EQ(test, 2 * ARRAY_SIZE(gains), len);
430         if (len < 2 * ARRAY_SIZE(gains))
431                 return;
432
433         for (i = 0; i < ARRAY_SIZE(gains); i++) {
434                 ret = iio_gts_total_gain_to_scale(gts, gains[i],
435                                                   &expected[2 * i],
436                                                   &expected[2 * i + 1]);
437                 KUNIT_EXPECT_EQ(test, 0, ret);
438                 if (ret)
439                         return;
440         }
441
442         for (i = 0; i < ARRAY_SIZE(expected); i++)
443                 KUNIT_EXPECT_EQ(test, expected[i], vals[i]);
444 }
445
446 static void test_iio_gts_avail_test(struct kunit *test)
447 {
448         struct device *dev;
449         int ret;
450         int type, len;
451         const int *vals;
452
453         dev = test_init_iio_gain_scale(test, &gts);
454         if (!dev)
455                 return;
456
457         /* test table building for times and iio_gts_avail_times() */
458         ret = iio_gts_avail_times(&gts, &vals, &type, &len);
459         KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
460         if (ret)
461                 return;
462
463         KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_MICRO, type);
464         KUNIT_EXPECT_EQ(test, 8, len);
465         if (len < 8)
466                 return;
467
468         test_iio_gts_chk_times(test, vals);
469
470         /* Test table building for all scales and iio_gts_all_avail_scales() */
471         ret = iio_gts_all_avail_scales(&gts, &vals, &type, &len);
472         KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
473         if (ret)
474                 return;
475
476         KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type);
477
478         test_iio_gts_chk_scales_all(test, &gts, vals, len);
479
480         /*
481          * Test table building for scales/time and
482          * iio_gts_avail_scales_for_time()
483          */
484         ret = iio_gts_avail_scales_for_time(&gts, 200000, &vals, &type, &len);
485         KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret);
486         if (ret)
487                 return;
488
489         KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type);
490         test_iio_gts_chk_scales_t200(test, &gts, vals, len);
491 }
492
493 static struct kunit_case iio_gts_test_cases[] = {
494         KUNIT_CASE(test_init_iio_gts_invalid),
495         KUNIT_CASE(test_iio_gts_find_gain_for_scale_using_time),
496         KUNIT_CASE(test_iio_gts_find_new_gain_sel_by_old_gain_time),
497         KUNIT_CASE(test_iio_find_closest_gain_low),
498         KUNIT_CASE(test_iio_gts_total_gain_to_scale),
499         KUNIT_CASE(test_iio_gts_avail_test),
500         {}
501 };
502
503 static struct kunit_suite iio_gts_test_suite = {
504         .name = "iio-gain-time-scale",
505         .test_cases = iio_gts_test_cases,
506 };
507
508 kunit_test_suite(iio_gts_test_suite);
509
510 MODULE_LICENSE("GPL");
511 MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>");
512 MODULE_DESCRIPTION("Test IIO light sensor gain-time-scale helpers");
513 MODULE_IMPORT_NS(IIO_GTS_HELPER);