xref: /linux/drivers/iio/test/iio-test-rescale.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Kunit tests for IIO rescale conversions
4  *
5  * Copyright (c) 2021 Liam Beguin <liambeguin@gmail.com>
6  */
7 
8 #include <linux/gcd.h>
9 #include <linux/overflow.h>
10 
11 #include <linux/iio/afe/rescale.h>
12 #include <linux/iio/iio.h>
13 
14 #include <kunit/test.h>
15 
16 struct rescale_tc_data {
17 	const char *name;
18 
19 	const s32 numerator;
20 	const s32 denominator;
21 	const s32 offset;
22 
23 	const int schan_val;
24 	const int schan_val2;
25 	const int schan_off;
26 	const int schan_scale_type;
27 
28 	const char *expected;
29 	const char *expected_off;
30 };
31 
32 static const struct rescale_tc_data scale_cases[] = {
33 	/*
34 	 * Typical use cases
35 	 */
36 	{
37 		.name = "typical IIO_VAL_INT, positive",
38 		.numerator = 1000000,
39 		.denominator = 8060,
40 		.schan_scale_type = IIO_VAL_INT,
41 		.schan_val = 42,
42 		.expected = "5210.918114143",
43 	},
44 	{
45 		.name = "typical IIO_VAL_INT, negative",
46 		.numerator = -1000000,
47 		.denominator = 8060,
48 		.schan_scale_type = IIO_VAL_INT,
49 		.schan_val = 42,
50 		.expected = "-5210.918114143",
51 	},
52 	{
53 		.name = "typical IIO_VAL_FRACTIONAL, positive",
54 		.numerator = 1000000,
55 		.denominator = 8060,
56 		.schan_scale_type = IIO_VAL_FRACTIONAL,
57 		.schan_val = 42,
58 		.schan_val2 = 20,
59 		.expected = "260.545905707",
60 	},
61 	{
62 		.name = "typical IIO_VAL_FRACTIONAL, negative",
63 		.numerator = -1000000,
64 		.denominator = 8060,
65 		.schan_scale_type = IIO_VAL_FRACTIONAL,
66 		.schan_val = 42,
67 		.schan_val2 = 20,
68 		.expected = "-260.545905707",
69 	},
70 	{
71 		.name = "typical IIO_VAL_FRACTIONAL_LOG2, positive",
72 		.numerator = 42,
73 		.denominator = 53,
74 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
75 		.schan_val = 4096,
76 		.schan_val2 = 16,
77 		.expected = "0.049528301",
78 	},
79 	{
80 		.name = "typical IIO_VAL_FRACTIONAL_LOG2, negative",
81 		.numerator = -42,
82 		.denominator = 53,
83 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
84 		.schan_val = 4096,
85 		.schan_val2 = 16,
86 		.expected = "-0.049528301",
87 	},
88 	{
89 		.name = "typical IIO_VAL_INT_PLUS_NANO, positive",
90 		.numerator = 1000000,
91 		.denominator = 8060,
92 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
93 		.schan_val = 10,
94 		.schan_val2 = 123456,
95 		.expected = "1240.710106203",
96 	},
97 	{
98 		.name = "typical IIO_VAL_INT_PLUS_NANO, negative",
99 		.numerator = -1000000,
100 		.denominator = 8060,
101 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
102 		.schan_val = 10,
103 		.schan_val2 = 123456,
104 		.expected = "-1240.710106203",
105 	},
106 	{
107 		.name = "typical IIO_VAL_INT_PLUS_MICRO, positive",
108 		.numerator = 1000000,
109 		.denominator = 8060,
110 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
111 		.schan_val = 10,
112 		.schan_val2 = 1234,
113 		.expected = "1240.84789",
114 	},
115 	{
116 		.name = "typical IIO_VAL_INT_PLUS_MICRO, negative",
117 		.numerator = -1000000,
118 		.denominator = 8060,
119 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
120 		.schan_val = 10,
121 		.schan_val2 = 1234,
122 		.expected = "-1240.84789",
123 	},
124 	/*
125 	 * Use cases with small scales involving divisions
126 	 */
127 	{
128 		.name = "small IIO_VAL_FRACTIONAL, 261/509 scaled by 90/1373754273",
129 		.numerator = 261,
130 		.denominator = 509,
131 		.schan_scale_type = IIO_VAL_FRACTIONAL,
132 		.schan_val = 90,
133 		.schan_val2 = 1373754273,
134 		.expected = "0.000000033594",
135 	},
136 	{
137 		.name = "small IIO_VAL_FRACTIONAL, 90/1373754273 scaled by 261/509",
138 		.numerator = 90,
139 		.denominator = 1373754273,
140 		.schan_scale_type = IIO_VAL_FRACTIONAL,
141 		.schan_val = 261,
142 		.schan_val2 = 509,
143 		.expected = "0.000000033594",
144 	},
145 	{
146 		.name = "small IIO_VAL_FRACTIONAL, 760/1373754273 scaled by 427/2727",
147 		.numerator = 760,
148 		.denominator = 1373754273,
149 		.schan_scale_type = IIO_VAL_FRACTIONAL,
150 		.schan_val = 427,
151 		.schan_val2 = 2727,
152 		.expected = "0.000000086626",
153 	},
154 	{
155 		.name = "small IIO_VAL_FRACTIONAL, 761/1373754273 scaled by 427/2727",
156 		.numerator = 761,
157 		.denominator = 1373754273,
158 		.schan_scale_type = IIO_VAL_FRACTIONAL,
159 		.schan_val = 427,
160 		.schan_val2 = 2727,
161 		.expected = "0.000000086740",
162 	},
163 	{
164 		.name = "small IIO_VAL_FRACTIONAL, 5/32768 scaled by 3/10000",
165 		.numerator = 5,
166 		.denominator = 32768,
167 		.schan_scale_type = IIO_VAL_FRACTIONAL,
168 		.schan_val = 3,
169 		.schan_val2 = 10000,
170 		.expected = "0.0000000457763671875",
171 	},
172 	{
173 		.name = "small IIO_VAL_FRACTIONAL, 0 < scale < 1",
174 		.numerator = 6,
175 		.denominator = 6,
176 		.schan_scale_type = IIO_VAL_FRACTIONAL,
177 		.schan_val = 1,
178 		.schan_val2 = 3,
179 		.expected = "0.3333333333333333",
180 	},
181 	{
182 		.name = "small IIO_VAL_FRACTIONAL, -1 < scale < 0",
183 		.numerator = -6,
184 		.denominator = 6,
185 		.schan_scale_type = IIO_VAL_FRACTIONAL,
186 		.schan_val = 1,
187 		.schan_val2 = 3,
188 		.expected = "-0.3333333333333333",
189 	},
190 	{
191 		.name = "small IIO_VAL_FRACTIONAL, 0 < scale < 2",
192 		.numerator = 8,
193 		.denominator = 2,
194 		.schan_scale_type = IIO_VAL_FRACTIONAL,
195 		.schan_val = 1,
196 		.schan_val2 = 3,
197 		.expected = "1.3333333333333333",
198 	},
199 	{
200 		.name = "small IIO_VAL_FRACTIONAL, -2 < scale < 0",
201 		.numerator = -8,
202 		.denominator = 2,
203 		.schan_scale_type = IIO_VAL_FRACTIONAL,
204 		.schan_val = 1,
205 		.schan_val2 = 3,
206 		.expected = "-1.3333333333333333",
207 	},
208 	{
209 		.name = "small IIO_VAL_FRACTIONAL_LOG2, 760/32768 scaled by 15/22",
210 		.numerator = 760,
211 		.denominator = 32768,
212 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
213 		.schan_val = 15,
214 		.schan_val2 = 22,
215 		.expected = "0.000000082946",
216 	},
217 	{
218 		.name = "small IIO_VAL_FRACTIONAL_LOG2, 761/32768 scaled by 15/22",
219 		.numerator = 761,
220 		.denominator = 32768,
221 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
222 		.schan_val = 15,
223 		.schan_val2 = 22,
224 		.expected = "0.000000083055",
225 	},
226 	{
227 		.name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 1",
228 		.numerator = 16,
229 		.denominator = 3,
230 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
231 		.schan_val = 1,
232 		.schan_val2 = 4,
233 		.expected = "0.3333333333333333",
234 	},
235 	{
236 		.name = "small IIO_VAL_FRACTIONAL_LOG2, -1 < scale < 0",
237 		.numerator = -16,
238 		.denominator = 3,
239 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
240 		.schan_val = 1,
241 		.schan_val2 = 4,
242 		.expected = "-0.3333333333333333",
243 	},
244 	{
245 		.name = "small IIO_VAL_FRACTIONAL_LOG2, 0 < scale < 2",
246 		.numerator = 8,
247 		.denominator = 3,
248 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
249 		.schan_val = 1,
250 		.schan_val2 = 1,
251 		.expected = "1.3333333333333333",
252 	},
253 	{
254 		.name = "small IIO_VAL_FRACTIONAL_LOG2, -2 < scale < 0",
255 		.numerator = -8,
256 		.denominator = 3,
257 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
258 		.schan_val = 1,
259 		.schan_val2 = 1,
260 		.expected = "-1.3333333333333333",
261 	},
262 	{
263 		.name = "small IIO_VAL_INT_PLUS_MICRO, positive",
264 		.numerator = 1,
265 		.denominator = 2,
266 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
267 		.schan_val = 5,
268 		.schan_val2 = 1234,
269 		.expected = "2.500617",
270 	},
271 	{
272 		.name = "small IIO_VAL_INT_PLUS_MICRO, negative",
273 		.numerator = -1,
274 		.denominator = 2,
275 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
276 		.schan_val = 5,
277 		.schan_val2 = 1234,
278 		.expected = "-2.500617",
279 	},
280 	/*
281 	 * INT_PLUS_{MICRO,NANO} positive/negative corner cases
282 	 */
283 	{
284 		.name = "negative IIO_VAL_INT_PLUS_NANO, negative schan",
285 		.numerator = 1000000,
286 		.denominator = 8060,
287 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
288 		.schan_val = -10,
289 		.schan_val2 = 123456,
290 		.expected = "-1240.710106203",
291 	},
292 	{
293 		.name = "negative IIO_VAL_INT_PLUS_NANO, both negative",
294 		.numerator = -1000000,
295 		.denominator = 8060,
296 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
297 		.schan_val = -10,
298 		.schan_val2 = 123456,
299 		.expected = "1240.710106203",
300 	},
301 	{
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,
306 		.schan_val = -10,
307 		.schan_val2 = 123456,
308 		.expected = "-1240.710106203",
309 	},
310 	{
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,
315 		.schan_val = -10,
316 		.schan_val2 = -123456,
317 		.expected = "-1240.710106203",
318 	},
319 	{
320 		.name = "negative IIO_VAL_INT_PLUS_NANO, negative, *val = 0",
321 		.numerator = 1,
322 		.denominator = -10,
323 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
324 		.schan_val = 0,
325 		.schan_val2 = 123456789,
326 		.expected = "-0.012345678",
327 	},
328 	/*
329 	 * INT_PLUS_{MICRO,NANO} decimal part overflow
330 	 */
331 	{
332 		.name = "decimal overflow IIO_VAL_INT_PLUS_NANO, positive",
333 		.numerator = 1000000,
334 		.denominator = 8060,
335 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
336 		.schan_val = 10,
337 		.schan_val2 = 123456789,
338 		.expected = "1256.01200856",
339 	},
340 	{
341 		.name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative",
342 		.numerator = -1000000,
343 		.denominator = 8060,
344 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
345 		.schan_val = 10,
346 		.schan_val2 = 123456789,
347 		.expected = "-1256.01200856",
348 	},
349 	{
350 		.name = "decimal overflow IIO_VAL_INT_PLUS_NANO, negative schan",
351 		.numerator = 1000000,
352 		.denominator = 8060,
353 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
354 		.schan_val = -10,
355 		.schan_val2 = 123456789,
356 		.expected = "-1256.01200856",
357 	},
358 	{
359 		.name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, positive",
360 		.numerator = 1000000,
361 		.denominator = 8060,
362 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
363 		.schan_val = 10,
364 		.schan_val2 = 123456789,
365 		.expected = "16557.914267",
366 	},
367 	{
368 		.name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative",
369 		.numerator = -1000000,
370 		.denominator = 8060,
371 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
372 		.schan_val = 10,
373 		.schan_val2 = 123456789,
374 		.expected = "-16557.914267",
375 	},
376 	{
377 		.name = "decimal overflow IIO_VAL_INT_PLUS_MICRO, negative schan",
378 		.numerator = 1000000,
379 		.denominator = 8060,
380 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
381 		.schan_val = -10,
382 		.schan_val2 = 123456789,
383 		.expected = "-16557.914267",
384 	},
385 	/*
386 	 * 32-bit overflow conditions
387 	 */
388 	{
389 		.name = "overflow IIO_VAL_FRACTIONAL, positive",
390 		.numerator = 2,
391 		.denominator = 20,
392 		.schan_scale_type = IIO_VAL_FRACTIONAL,
393 		.schan_val = S32_MAX,
394 		.schan_val2 = 1,
395 		.expected = "214748364.7",
396 	},
397 	{
398 		.name = "overflow IIO_VAL_FRACTIONAL, negative",
399 		.numerator = -2,
400 		.denominator = 20,
401 		.schan_scale_type = IIO_VAL_FRACTIONAL,
402 		.schan_val = S32_MAX,
403 		.schan_val2 = 1,
404 		.expected = "-214748364.7",
405 	},
406 	{
407 		.name = "overflow IIO_VAL_FRACTIONAL_LOG2, positive",
408 		.numerator = S32_MAX,
409 		.denominator = 4096,
410 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
411 		.schan_val = 4096,
412 		.schan_val2 = 16,
413 		.expected = "32767.99998474121",
414 	},
415 	{
416 		.name = "overflow IIO_VAL_FRACTIONAL_LOG2, negative",
417 		.numerator = S32_MAX,
418 		.denominator = 4096,
419 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
420 		.schan_val = -4096,
421 		.schan_val2 = 16,
422 		.expected = "-32767.99998474121",
423 	},
424 	{
425 		.name = "overflow IIO_VAL_INT_PLUS_NANO, positive",
426 		.numerator = 2,
427 		.denominator = 20,
428 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
429 		.schan_val = 10,
430 		.schan_val2 = S32_MAX,
431 		.expected = "1.214748364",
432 	},
433 	{
434 		.name = "overflow IIO_VAL_INT_PLUS_NANO, negative",
435 		.numerator = -2,
436 		.denominator = 20,
437 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
438 		.schan_val = 10,
439 		.schan_val2 = S32_MAX,
440 		.expected = "-1.214748364",
441 	},
442 	{
443 		.name = "overflow IIO_VAL_INT_PLUS_NANO, negative schan",
444 		.numerator = 2,
445 		.denominator = 20,
446 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
447 		.schan_val = -10,
448 		.schan_val2 = S32_MAX,
449 		.expected = "-1.214748364",
450 	},
451 	{
452 		.name = "overflow IIO_VAL_INT_PLUS_MICRO, positive",
453 		.numerator = 2,
454 		.denominator = 20,
455 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
456 		.schan_val = 10,
457 		.schan_val2 = S32_MAX,
458 		.expected = "215.748364",
459 	},
460 	{
461 		.name = "overflow IIO_VAL_INT_PLUS_MICRO, negative",
462 		.numerator = -2,
463 		.denominator = 20,
464 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
465 		.schan_val = 10,
466 		.schan_val2 = S32_MAX,
467 		.expected = "-215.748364",
468 	},
469 	{
470 		.name = "overflow IIO_VAL_INT_PLUS_MICRO, negative schan",
471 		.numerator = 2,
472 		.denominator = 20,
473 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
474 		.schan_val = -10,
475 		.schan_val2 = S32_MAX,
476 		.expected = "-215.748364",
477 	},
478 };
479 
480 static const struct rescale_tc_data offset_cases[] = {
481 	/*
482 	 * Typical use cases
483 	 */
484 	{
485 		.name = "typical IIO_VAL_INT, positive",
486 		.offset = 1234,
487 		.schan_scale_type = IIO_VAL_INT,
488 		.schan_val = 123,
489 		.schan_val2 = 0,
490 		.schan_off = 14,
491 		.expected_off = "24", /* 23.872 */
492 	},
493 	{
494 		.name = "typical IIO_VAL_INT, negative",
495 		.offset = -1234,
496 		.schan_scale_type = IIO_VAL_INT,
497 		.schan_val = 12,
498 		.schan_val2 = 0,
499 		.schan_off = 14,
500 		.expected_off = "-88", /* -88.83333333333333 */
501 	},
502 	{
503 		.name = "typical IIO_VAL_FRACTIONAL, positive",
504 		.offset = 1234,
505 		.schan_scale_type = IIO_VAL_FRACTIONAL,
506 		.schan_val = 12,
507 		.schan_val2 = 34,
508 		.schan_off = 14,
509 		.expected_off = "3510", /* 3510.333333333333 */
510 	},
511 	{
512 		.name = "typical IIO_VAL_FRACTIONAL, negative",
513 		.offset = -1234,
514 		.schan_scale_type = IIO_VAL_FRACTIONAL,
515 		.schan_val = 12,
516 		.schan_val2 = 34,
517 		.schan_off = 14,
518 		.expected_off = "-3482", /* -3482.333333333333 */
519 	},
520 	{
521 		.name = "typical IIO_VAL_FRACTIONAL_LOG2, positive",
522 		.offset = 1234,
523 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
524 		.schan_val = 12,
525 		.schan_val2 = 16,
526 		.schan_off = 14,
527 		.expected_off = "6739299", /* 6739299.333333333 */
528 	},
529 	{
530 		.name = "typical IIO_VAL_FRACTIONAL_LOG2, negative",
531 		.offset = -1234,
532 		.schan_scale_type = IIO_VAL_FRACTIONAL_LOG2,
533 		.schan_val = 12,
534 		.schan_val2 = 16,
535 		.schan_off = 14,
536 		.expected_off = "-6739271", /* -6739271.333333333 */
537 	},
538 	{
539 		.name = "typical IIO_VAL_INT_PLUS_NANO, positive",
540 		.offset = 1234,
541 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
542 		.schan_val = 10,
543 		.schan_val2 = 123456789,
544 		.schan_off = 14,
545 		.expected_off = "135", /* 135.8951219647469 */
546 	},
547 	{
548 		.name = "typical IIO_VAL_INT_PLUS_NANO, negative",
549 		.offset = -1234,
550 		.schan_scale_type = IIO_VAL_INT_PLUS_NANO,
551 		.schan_val = 10,
552 		.schan_val2 = 123456789,
553 		.schan_off = 14,
554 		.expected_off = "-107", /* -107.89512196474689 */
555 	},
556 	{
557 		.name = "typical IIO_VAL_INT_PLUS_MICRO, positive",
558 		.offset = 1234,
559 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
560 		.schan_val = 10,
561 		.schan_val2 = 123456789,
562 		.schan_off = 14,
563 		.expected_off = "23", /* 23.246438560723952 */
564 	},
565 	{
566 		.name = "typical IIO_VAL_INT_PLUS_MICRO, negative",
567 		.offset = -12345,
568 		.schan_scale_type = IIO_VAL_INT_PLUS_MICRO,
569 		.schan_val = 10,
570 		.schan_val2 = 123456789,
571 		.schan_off = 14,
572 		.expected_off = "-78", /* -78.50185091745313 */
573 	},
574 };
575 
case_to_desc(const struct rescale_tc_data * t,char * desc)576 static void case_to_desc(const struct rescale_tc_data *t, char *desc)
577 {
578 	strcpy(desc, t->name);
579 }
580 
581 KUNIT_ARRAY_PARAM(iio_rescale_scale, scale_cases, case_to_desc);
582 KUNIT_ARRAY_PARAM(iio_rescale_offset, offset_cases, case_to_desc);
583 
584 /**
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
589  *
590  * Returns 0 on success, or a negative error code if the string cound not be
591  * parsed.
592  */
iio_str_to_nano(const char * str,s64 * nano)593 static int iio_str_to_nano(const char *str, s64 *nano)
594 {
595 	int tmp, tmp2;
596 	int ret = 0;
597 
598 	/*
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.
601 	 */
602 	ret = iio_str_to_fixpoint(str, 100000000, &tmp, &tmp2);
603 	if (ret < 0)
604 		return ret;
605 
606 	if (tmp < 0)
607 		tmp2 *= -1;
608 
609 	*nano = (s64)tmp * 1000000000UL + tmp2;
610 
611 	return ret;
612 }
613 
614 /**
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
619  *
620  * Returns a negative error code if the strings cound not be parsed, or the
621  * relative error in parts-per-million.
622  */
iio_test_relative_error_ppm(const char * real_str,const char * exp_str)623 static int iio_test_relative_error_ppm(const char *real_str, const char *exp_str)
624 {
625 	s64 real, exp, err;
626 	int ret;
627 
628 	ret = iio_str_to_nano(real_str, &real);
629 	if (ret < 0)
630 		return ret;
631 
632 	ret = iio_str_to_nano(exp_str, &exp);
633 	if (ret < 0)
634 		return ret;
635 
636 	if (!exp) {
637 		pr_err("Expected value is null, relative error is undefined\n");
638 		return -EINVAL;
639 	}
640 
641 	err = 1000000UL * abs(exp - real);
642 
643 	return (int)div64_u64(err, abs(exp));
644 }
645 
iio_rescale_test_scale(struct kunit * test)646 static void iio_rescale_test_scale(struct kunit *test)
647 {
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;
651 	int values[2];
652 	int rel_ppm;
653 	int ret;
654 
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;
660 
661 	ret = rescale_process_scale(&rescale, t->schan_scale_type,
662 				    &values[0], &values[1]);
663 
664 	ret = iio_format_value(buff, ret, 2, values);
665 	KUNIT_EXPECT_EQ(test, (int)strlen(buff), ret);
666 
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");
669 
670 	KUNIT_EXPECT_EQ_MSG(test, rel_ppm, 0,
671 			    "\t    real=%s"
672 			    "\texpected=%s\n",
673 			    buff, t->expected);
674 }
675 
iio_rescale_test_offset(struct kunit * test)676 static void iio_rescale_test_offset(struct kunit *test)
677 {
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;
681 	int values[2];
682 	int ret;
683 
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;
689 
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]);
693 
694 	ret = iio_format_value(buff_off, ret, 2, values);
695 	KUNIT_EXPECT_EQ(test, (int)strlen(buff_off), ret);
696 
697 	KUNIT_EXPECT_STREQ(test, strim(buff_off), t->expected_off);
698 }
699 
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),
703 	{}
704 };
705 
706 static struct kunit_suite iio_rescale_test_suite = {
707 	.name = "iio-rescale",
708 	.test_cases = iio_rescale_test_cases,
709 };
710 kunit_test_suite(iio_rescale_test_suite);
711 
712 MODULE_AUTHOR("Liam Beguin <liambeguin@gmail.com>");
713 MODULE_DESCRIPTION("Test IIO rescale conversion functions");
714 MODULE_LICENSE("GPL v2");
715 MODULE_IMPORT_NS(IIO_RESCALE);
716