1 // SPDX-License-Identifier: GPL-2.0-only
3 * Kunit tests for IIO rescale conversions
9 #include <linux/overflow.h>
11 #include <linux/iio/afe/rescale.h>
12 #include <linux/iio/iio.h>
14 #include <kunit/test.h>
16 struct rescale_tc_data {
20 const s32 denominator;
26 const int schan_scale_type;
29 const char *expected_off;
32 static const struct rescale_tc_data scale_cases[] = {
37 .name = "typical IIO_VAL_INT, positive",
40 .schan_scale_type = IIO_VAL_INT,
42 .expected = "5210.918114143",
45 .name = "typical IIO_VAL_INT, negative",
46 .numerator = -1000000,
48 .schan_scale_type = IIO_VAL_INT,
50 .expected = "-5210.918114143",
53 .name = "typical IIO_VAL_FRACTIONAL, positive",
56 .schan_scale_type = IIO_VAL_FRACTIONAL,
59 .expected = "260.545905707",
62 .name = "typical IIO_VAL_FRACTIONAL, negative",
63 .numerator = -1000000,
65 .schan_scale_type = IIO_VAL_FRACTIONAL,
68 .expected = "-260.545905707",
71 .name = "typical IIO_VAL_FRACTIONAL_LOG2, positive",
74 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
77 .expected = "0.049528301",
80 .name = "typical IIO_VAL_FRACTIONAL_LOG2, negative",
83 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
86 .expected = "-0.049528301",
89 .name = "typical IIO_VAL_INT_PLUS_NANO, positive",
92 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
95 .expected = "1240.710106203",
98 .name = "typical IIO_VAL_INT_PLUS_NANO, negative",
99 .numerator = -1000000,
101 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
103 .schan_val2 = 123456,
104 .expected = "-1240.710106203",
107 .name = "typical IIO_VAL_INT_PLUS_MICRO, positive",
108 .numerator = 1000000,
110 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
113 .expected = "1240.84789",
116 .name = "typical IIO_VAL_INT_PLUS_MICRO, negative",
117 .numerator = -1000000,
119 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
122 .expected = "-1240.84789",
125 * Use cases with small scales involving divisions
128 .name = "small IIO_VAL_FRACTIONAL, 261/509 scaled by 90/1373754273",
131 .schan_scale_type = IIO_VAL_FRACTIONAL,
133 .schan_val2 = 1373754273,
134 .expected = "0.000000033594",
137 .name = "small IIO_VAL_FRACTIONAL, 90/1373754273 scaled by 261/509",
139 .denominator = 1373754273,
140 .schan_scale_type = IIO_VAL_FRACTIONAL,
143 .expected = "0.000000033594",
146 .name = "small IIO_VAL_FRACTIONAL, 760/1373754273 scaled by 427/2727",
148 .denominator = 1373754273,
149 .schan_scale_type = IIO_VAL_FRACTIONAL,
152 .expected = "0.000000086626",
155 .name = "small IIO_VAL_FRACTIONAL, 761/1373754273 scaled by 427/2727",
157 .denominator = 1373754273,
158 .schan_scale_type = IIO_VAL_FRACTIONAL,
161 .expected = "0.000000086740",
164 .name = "small IIO_VAL_FRACTIONAL, 5/32768 scaled by 3/10000",
166 .denominator = 32768,
167 .schan_scale_type = IIO_VAL_FRACTIONAL,
170 .expected = "0.0000000457763671875",
173 .name = "small IIO_VAL_FRACTIONAL, 0 < scale < 1",
176 .schan_scale_type = IIO_VAL_FRACTIONAL,
179 .expected = "0.3333333333333333",
182 .name = "small IIO_VAL_FRACTIONAL, -1 < scale < 0",
185 .schan_scale_type = IIO_VAL_FRACTIONAL,
188 .expected = "-0.3333333333333333",
191 .name = "small IIO_VAL_FRACTIONAL, 0 < scale < 2",
194 .schan_scale_type = IIO_VAL_FRACTIONAL,
197 .expected = "1.3333333333333333",
200 .name = "small IIO_VAL_FRACTIONAL, -2 < scale < 0",
203 .schan_scale_type = IIO_VAL_FRACTIONAL,
206 .expected = "-1.3333333333333333",
209 .name = "small IIO_VAL_FRACTIONAL_LOG2, 760/32768 scaled by 15/22",
211 .denominator = 32768,
212 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
215 .expected = "0.000000082946",
218 .name = "small IIO_VAL_FRACTIONAL_LOG2, 761/32768 scaled by 15/22",
220 .denominator = 32768,
221 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
224 .expected = "0.000000083055",
227 .name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 1",
230 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
233 .expected = "0.3333333333333333",
236 .name = "small IIO_VAL_FRACTIONAL_LOG2, -1 < scale < 0",
239 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
242 .expected = "-0.3333333333333333",
245 .name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 2",
248 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
251 .expected = "1.3333333333333333",
254 .name = "small IIO_VAL_FRACTIONAL_LOG2, -2 < scale < 0",
257 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
260 .expected = "-1.3333333333333333",
263 .name = "small IIO_VAL_INT_PLUS_MICRO, positive",
266 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
269 .expected = "2.500617",
272 .name = "small IIO_VAL_INT_PLUS_MICRO, negative",
275 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
278 .expected = "-2.500617",
281 * INT_PLUS_{MICRO,NANO} positive/negative corner cases
284 .name = "negative IIO_VAL_INT_PLUS_NANO, negative schan",
285 .numerator = 1000000,
287 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
289 .schan_val2 = 123456,
290 .expected = "-1240.710106203",
293 .name = "negative IIO_VAL_INT_PLUS_NANO, both negative",
294 .numerator = -1000000,
296 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
298 .schan_val2 = 123456,
299 .expected = "1240.710106203",
302 .name = "negative IIO_VAL_INT_PLUS_NANO, 3 negative",
303 .numerator = -1000000,
304 .denominator = -8060,
305 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
307 .schan_val2 = 123456,
308 .expected = "-1240.710106203",
311 .name = "negative IIO_VAL_INT_PLUS_NANO, 4 negative",
312 .numerator = -1000000,
313 .denominator = -8060,
314 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
316 .schan_val2 = -123456,
317 .expected = "-1240.710106203",
320 .name = "negative IIO_VAL_INT_PLUS_NANO, negative, *val = 0",
323 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
325 .schan_val2 = 123456789,
326 .expected = "-0.012345678",
329 * INT_PLUS_{MICRO,NANO} decimal part overflow
332 .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, positive",
333 .numerator = 1000000,
335 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
337 .schan_val2 = 123456789,
338 .expected = "1256.01200856",
341 .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative",
342 .numerator = -1000000,
344 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
346 .schan_val2 = 123456789,
347 .expected = "-1256.01200856",
350 .name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative schan",
351 .numerator = 1000000,
353 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
355 .schan_val2 = 123456789,
356 .expected = "-1256.01200856",
359 .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, positive",
360 .numerator = 1000000,
362 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
364 .schan_val2 = 123456789,
365 .expected = "16557.914267",
368 .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative",
369 .numerator = -1000000,
371 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
373 .schan_val2 = 123456789,
374 .expected = "-16557.914267",
377 .name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative schan",
378 .numerator = 1000000,
380 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
382 .schan_val2 = 123456789,
383 .expected = "-16557.914267",
386 * 32-bit overflow conditions
389 .name = "overflow IIO_VAL_FRACTIONAL, positive",
392 .schan_scale_type = IIO_VAL_FRACTIONAL,
393 .schan_val = S32_MAX,
395 .expected = "214748364.7",
398 .name = "overflow IIO_VAL_FRACTIONAL, negative",
401 .schan_scale_type = IIO_VAL_FRACTIONAL,
402 .schan_val = S32_MAX,
404 .expected = "-214748364.7",
407 .name = "overflow IIO_VAL_FRACTIONAL_LOG2, positive",
408 .numerator = S32_MAX,
410 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
413 .expected = "32767.99998474121",
416 .name = "overflow IIO_VAL_FRACTIONAL_LOG2, negative",
417 .numerator = S32_MAX,
419 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
422 .expected = "-32767.99998474121",
425 .name = "overflow IIO_VAL_INT_PLUS_NANO, positive",
428 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
430 .schan_val2 = S32_MAX,
431 .expected = "1.214748364",
434 .name = "overflow IIO_VAL_INT_PLUS_NANO, negative",
437 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
439 .schan_val2 = S32_MAX,
440 .expected = "-1.214748364",
443 .name = "overflow IIO_VAL_INT_PLUS_NANO, negative schan",
446 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
448 .schan_val2 = S32_MAX,
449 .expected = "-1.214748364",
452 .name = "overflow IIO_VAL_INT_PLUS_MICRO, positive",
455 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
457 .schan_val2 = S32_MAX,
458 .expected = "215.748364",
461 .name = "overflow IIO_VAL_INT_PLUS_MICRO, negative",
464 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
466 .schan_val2 = S32_MAX,
467 .expected = "-215.748364",
470 .name = "overflow IIO_VAL_INT_PLUS_MICRO, negative schan",
473 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
475 .schan_val2 = S32_MAX,
476 .expected = "-215.748364",
480 static const struct rescale_tc_data offset_cases[] = {
485 .name = "typical IIO_VAL_INT, positive",
487 .schan_scale_type = IIO_VAL_INT,
491 .expected_off = "24", /* 23.872 */
494 .name = "typical IIO_VAL_INT, negative",
496 .schan_scale_type = IIO_VAL_INT,
500 .expected_off = "-88", /* -88.83333333333333 */
503 .name = "typical IIO_VAL_FRACTIONAL, positive",
505 .schan_scale_type = IIO_VAL_FRACTIONAL,
509 .expected_off = "3510", /* 3510.333333333333 */
512 .name = "typical IIO_VAL_FRACTIONAL, negative",
514 .schan_scale_type = IIO_VAL_FRACTIONAL,
518 .expected_off = "-3482", /* -3482.333333333333 */
521 .name = "typical IIO_VAL_FRACTIONAL_LOG2, positive",
523 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
527 .expected_off = "6739299", /* 6739299.333333333 */
530 .name = "typical IIO_VAL_FRACTIONAL_LOG2, negative",
532 .schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
536 .expected_off = "-6739271", /* -6739271.333333333 */
539 .name = "typical IIO_VAL_INT_PLUS_NANO, positive",
541 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
543 .schan_val2 = 123456789,
545 .expected_off = "135", /* 135.8951219647469 */
548 .name = "typical IIO_VAL_INT_PLUS_NANO, negative",
550 .schan_scale_type = IIO_VAL_INT_PLUS_NANO,
552 .schan_val2 = 123456789,
554 .expected_off = "-107", /* -107.89512196474689 */
557 .name = "typical IIO_VAL_INT_PLUS_MICRO, positive",
559 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
561 .schan_val2 = 123456789,
563 .expected_off = "23", /* 23.246438560723952 */
566 .name = "typical IIO_VAL_INT_PLUS_MICRO, negative",
568 .schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
570 .schan_val2 = 123456789,
572 .expected_off = "-78", /* -78.50185091745313 */
576 static void case_to_desc(const struct rescale_tc_data *t, char *desc)
578 strcpy(desc, t->name);
581 KUNIT_ARRAY_PARAM(iio_rescale_scale, scale_cases, case_to_desc);
582 KUNIT_ARRAY_PARAM(iio_rescale_offset, offset_cases, case_to_desc);
585 * iio_str_to_nano() - Parse a fixed-point string to get an
586 * IIO_VAL_INT_PLUS_NANO value
587 * @str: The string to parse
588 * @nano: The number as an integer
590 * Returns 0 on success, or a negative error code if the string cound not be
593 static int iio_str_to_nano(const char *str, s64 *nano)
599 * iio_str_to_fixpoint() uses 10^8 here instead of 10^9 as fract_mult is
600 * the multiplier for the first decimal place.
602 ret = iio_str_to_fixpoint(str, 100000000, &tmp, &tmp2);
609 *nano = (s64)tmp * 1000000000UL + tmp2;
615 * iio_test_relative_error_ppm() - Compute relative error (in parts-per-million)
616 * between two fixed-point strings
617 * @real_str: The real value as a string
618 * @exp_str: The expected value as a string
620 * Returns a negative error code if the strings cound not be parsed, or the
621 * relative error in parts-per-million.
623 static int iio_test_relative_error_ppm(const char *real_str, const char *exp_str)
628 ret = iio_str_to_nano(real_str, &real);
632 ret = iio_str_to_nano(exp_str, &exp);
637 pr_err("Expected value is null, relative error is undefined\n");
641 err = 1000000UL * abs(exp - real);
643 return (int)div64_u64(err, abs(exp));
646 static void iio_rescale_test_scale(struct kunit *test)
648 struct rescale_tc_data *t = (struct rescale_tc_data *)test->param_value;
649 char *buff = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
650 struct rescale rescale;
655 rescale.numerator = t->numerator;
656 rescale.denominator = t->denominator;
657 rescale.offset = t->offset;
658 values[0] = t->schan_val;
659 values[1] = t->schan_val2;
661 ret = rescale_process_scale(&rescale, t->schan_scale_type,
662 &values[0], &values[1]);
664 ret = iio_format_value(buff, ret, 2, values);
665 KUNIT_EXPECT_EQ(test, (int)strlen(buff), ret);
667 rel_ppm = iio_test_relative_error_ppm(buff, t->expected);
668 KUNIT_EXPECT_GE_MSG(test, rel_ppm, 0, "failed to compute ppm\n");
670 KUNIT_EXPECT_EQ_MSG(test, rel_ppm, 0,
676 static void iio_rescale_test_offset(struct kunit *test)
678 struct rescale_tc_data *t = (struct rescale_tc_data *)test->param_value;
679 char *buff_off = kunit_kmalloc(test, PAGE_SIZE, GFP_KERNEL);
680 struct rescale rescale;
684 rescale.numerator = t->numerator;
685 rescale.denominator = t->denominator;
686 rescale.offset = t->offset;
687 values[0] = t->schan_val;
688 values[1] = t->schan_val2;
690 ret = rescale_process_offset(&rescale, t->schan_scale_type,
691 t->schan_val, t->schan_val2, t->schan_off,
692 &values[0], &values[1]);
694 ret = iio_format_value(buff_off, ret, 2, values);
695 KUNIT_EXPECT_EQ(test, (int)strlen(buff_off), ret);
697 KUNIT_EXPECT_STREQ(test, strim(buff_off), t->expected_off);
700 static struct kunit_case iio_rescale_test_cases[] = {
701 KUNIT_CASE_PARAM(iio_rescale_test_scale, iio_rescale_scale_gen_params),
702 KUNIT_CASE_PARAM(iio_rescale_test_offset, iio_rescale_offset_gen_params),
706 static struct kunit_suite iio_rescale_test_suite = {
707 .name = "iio-rescale",
708 .test_cases = iio_rescale_test_cases,
710 kunit_test_suite(iio_rescale_test_suite);
713 MODULE_DESCRIPTION("Test IIO rescale conversion functions");
714 MODULE_LICENSE("GPL v2");
715 MODULE_IMPORT_NS(IIO_RESCALE);