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 /* Keep the gain and time tables unsorted to test the sorting */ 74 static const struct iio_gain_sel_pair gts_test_gains[] = { 75 GAIN_SCALE_GAIN(1, TEST_GSEL_1), 76 GAIN_SCALE_GAIN(4, TEST_GSEL_4), 77 GAIN_SCALE_GAIN(16, TEST_GSEL_16), 78 GAIN_SCALE_GAIN(32, TEST_GSEL_32), 79 GAIN_SCALE_GAIN(64, TEST_GSEL_64), 80 GAIN_SCALE_GAIN(256, TEST_GSEL_256), 81 GAIN_SCALE_GAIN(512, TEST_GSEL_512), 82 GAIN_SCALE_GAIN(1024, TEST_GSEL_1024), 83 GAIN_SCALE_GAIN(4096, TEST_GSEL_4096), 84 GAIN_SCALE_GAIN(2048, TEST_GSEL_2048), 85 #define HWGAIN_MAX 4096 86 }; 87 88 static const struct iio_itime_sel_mul gts_test_itimes[] = { 89 GAIN_SCALE_ITIME_US(100 * 1000, TEST_TSEL_100, 2), 90 GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8), 91 GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 8), 92 GAIN_SCALE_ITIME_US(50 * 1000, TEST_TSEL_50, 1), 93 GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), 94 #define TIMEGAIN_MAX 8 95 }; 96 #define TOTAL_GAIN_MAX (HWGAIN_MAX * TIMEGAIN_MAX) 97 #define IIO_GTS_TEST_DEV "iio-gts-test-dev" 98 99 static struct device *__test_init_iio_gain_scale(struct kunit *test, 100 struct iio_gts *gts, const struct iio_gain_sel_pair *g_table, 101 int num_g, const struct iio_itime_sel_mul *i_table, int num_i) 102 { 103 struct device *dev; 104 int ret; 105 106 dev = kunit_device_register(test, IIO_GTS_TEST_DEV); 107 108 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev); 109 if (IS_ERR_OR_NULL(dev)) 110 return NULL; 111 112 ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, g_table, num_g, 113 i_table, num_i, gts); 114 KUNIT_EXPECT_EQ(test, 0, ret); 115 if (ret) 116 return NULL; 117 118 return dev; 119 } 120 121 #define test_init_iio_gain_scale(test, gts) \ 122 __test_init_iio_gain_scale(test, gts, gts_test_gains, \ 123 ARRAY_SIZE(gts_test_gains), gts_test_itimes, \ 124 ARRAY_SIZE(gts_test_itimes)) 125 126 static void test_init_iio_gts_invalid(struct kunit *test) 127 { 128 struct device *dev; 129 int ret; 130 const struct iio_itime_sel_mul itimes_neg[] = { 131 GAIN_SCALE_ITIME_US(-10, TEST_TSEL_400, 8), 132 GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), 133 }; 134 const struct iio_gain_sel_pair gains_neg[] = { 135 GAIN_SCALE_GAIN(1, TEST_GSEL_1), 136 GAIN_SCALE_GAIN(2, TEST_GSEL_4), 137 GAIN_SCALE_GAIN(-2, TEST_GSEL_16), 138 }; 139 /* 55555 * 38656 = 2147534080 => overflows 32bit int */ 140 const struct iio_itime_sel_mul itimes_overflow[] = { 141 GAIN_SCALE_ITIME_US(400 * 1000, TEST_TSEL_400, 55555), 142 GAIN_SCALE_ITIME_US(200 * 1000, TEST_TSEL_200, 4), 143 }; 144 const struct iio_gain_sel_pair gains_overflow[] = { 145 GAIN_SCALE_GAIN(1, TEST_GSEL_1), 146 GAIN_SCALE_GAIN(2, TEST_GSEL_4), 147 GAIN_SCALE_GAIN(38656, TEST_GSEL_16), 148 }; 149 150 dev = kunit_device_register(test, IIO_GTS_TEST_DEV); 151 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, dev); 152 if (!dev) 153 return; 154 155 /* Ok gains, negative time */ 156 ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gts_test_gains, 157 ARRAY_SIZE(gts_test_gains), itimes_neg, 158 ARRAY_SIZE(itimes_neg), >s); 159 KUNIT_EXPECT_EQ(test, -EINVAL, ret); 160 161 /* Ok times, negative gain */ 162 ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_neg, 163 ARRAY_SIZE(gains_neg), gts_test_itimes, 164 ARRAY_SIZE(gts_test_itimes), >s); 165 KUNIT_EXPECT_EQ(test, -EINVAL, ret); 166 167 /* gain * time overflow int */ 168 ret = devm_iio_init_iio_gts(dev, TEST_SCALE_1X, 0, gains_overflow, 169 ARRAY_SIZE(gains_overflow), itimes_overflow, 170 ARRAY_SIZE(itimes_overflow), >s); 171 KUNIT_EXPECT_EQ(test, -EOVERFLOW, ret); 172 } 173 174 static void test_iio_gts_find_gain_for_scale_using_time(struct kunit *test) 175 { 176 struct device *dev; 177 int ret, gain_sel; 178 179 dev = test_init_iio_gain_scale(test, >s); 180 if (!dev) 181 return; 182 183 ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_100, 184 TEST_SCALE_8X, 0, &gain_sel); 185 /* 186 * Meas time 100 => gain by time 2x 187 * TEST_SCALE_8X matches total gain 8x 188 * => required HWGAIN 4x 189 */ 190 KUNIT_EXPECT_EQ(test, 0, ret); 191 KUNIT_EXPECT_EQ(test, TEST_GSEL_4, gain_sel); 192 193 ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_200, 0, 194 TEST_SCALE_NANO_256X, &gain_sel); 195 /* 196 * Meas time 200 => gain by time 4x 197 * TEST_SCALE_256X matches total gain 256x 198 * => required HWGAIN 256/4 => 64x 199 */ 200 KUNIT_EXPECT_EQ(test, 0, ret); 201 KUNIT_EXPECT_EQ(test, TEST_GSEL_64, gain_sel); 202 203 /* Min time, Min gain */ 204 ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_X_MIN, 205 TEST_SCALE_MIN_X, 0, &gain_sel); 206 KUNIT_EXPECT_EQ(test, 0, ret); 207 KUNIT_EXPECT_EQ(test, TEST_GSEL_1, gain_sel); 208 209 /* Max time, Max gain */ 210 ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_X_MAX, 211 0, TEST_SCALE_NANO_MAX_X, &gain_sel); 212 KUNIT_EXPECT_EQ(test, 0, ret); 213 KUNIT_EXPECT_EQ(test, TEST_GSEL_4096, gain_sel); 214 215 ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_100, 0, 216 TEST_SCALE_NANO_256X, &gain_sel); 217 /* 218 * Meas time 100 => gain by time 2x 219 * TEST_SCALE_256X matches total gain 256x 220 * => required HWGAIN 256/2 => 128x (not in gain-table - unsupported) 221 */ 222 KUNIT_EXPECT_NE(test, 0, ret); 223 224 ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_200, 0, 225 TEST_SCALE_NANO_MAX_X, &gain_sel); 226 /* We can't reach the max gain with integration time smaller than MAX */ 227 KUNIT_EXPECT_NE(test, 0, ret); 228 229 ret = iio_gts_find_gain_sel_for_scale_using_time(>s, TEST_TSEL_50, 0, 230 TEST_SCALE_NANO_MAX_X, &gain_sel); 231 /* We can't reach the max gain with integration time smaller than MAX */ 232 KUNIT_EXPECT_NE(test, 0, ret); 233 } 234 235 static void test_iio_gts_find_new_gain_sel_by_old_gain_time(struct kunit *test) 236 { 237 struct device *dev; 238 int ret, old_gain, new_gain, old_time_sel, new_time_sel; 239 240 dev = test_init_iio_gain_scale(test, >s); 241 if (!dev) 242 return; 243 244 old_gain = 32; 245 old_time_sel = TEST_TSEL_200; 246 new_time_sel = TEST_TSEL_400; 247 248 ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, 249 old_time_sel, new_time_sel, &new_gain); 250 KUNIT_EXPECT_EQ(test, 0, ret); 251 /* 252 * Doubling the integration time doubles the total gain - so old 253 * (hw)gain must be divided by two to compensate. => 32 / 2 => 16 254 */ 255 KUNIT_EXPECT_EQ(test, 16, new_gain); 256 257 old_gain = 4; 258 old_time_sel = TEST_TSEL_50; 259 new_time_sel = TEST_TSEL_200; 260 ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, 261 old_time_sel, new_time_sel, &new_gain); 262 KUNIT_EXPECT_EQ(test, 0, ret); 263 /* 264 * gain by time 1x => 4x - (hw)gain 4x => 1x 265 */ 266 KUNIT_EXPECT_EQ(test, 1, new_gain); 267 268 old_gain = 512; 269 old_time_sel = TEST_TSEL_400; 270 new_time_sel = TEST_TSEL_50; 271 ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, 272 old_time_sel, new_time_sel, &new_gain); 273 KUNIT_EXPECT_EQ(test, 0, ret); 274 /* 275 * gain by time 8x => 1x - (hw)gain 512x => 4096x) 276 */ 277 KUNIT_EXPECT_EQ(test, 4096, new_gain); 278 279 /* Unsupported gain 2x */ 280 old_gain = 4; 281 old_time_sel = TEST_TSEL_200; 282 new_time_sel = TEST_TSEL_400; 283 ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, 284 old_time_sel, new_time_sel, &new_gain); 285 KUNIT_EXPECT_NE(test, 0, ret); 286 287 /* Too small gain */ 288 old_gain = 4; 289 old_time_sel = TEST_TSEL_50; 290 new_time_sel = TEST_TSEL_400; 291 ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, 292 old_time_sel, new_time_sel, &new_gain); 293 KUNIT_EXPECT_NE(test, 0, ret); 294 295 /* Too big gain */ 296 old_gain = 1024; 297 old_time_sel = TEST_TSEL_400; 298 new_time_sel = TEST_TSEL_50; 299 ret = iio_gts_find_new_gain_sel_by_old_gain_time(>s, old_gain, 300 old_time_sel, new_time_sel, &new_gain); 301 KUNIT_EXPECT_NE(test, 0, ret); 302 303 } 304 305 static void test_iio_find_closest_gain_low(struct kunit *test) 306 { 307 struct device *dev; 308 bool in_range; 309 int ret; 310 311 const struct iio_gain_sel_pair gts_test_gains_gain_low[] = { 312 GAIN_SCALE_GAIN(4, TEST_GSEL_4), 313 GAIN_SCALE_GAIN(16, TEST_GSEL_16), 314 GAIN_SCALE_GAIN(32, TEST_GSEL_32), 315 }; 316 317 dev = test_init_iio_gain_scale(test, >s); 318 if (!dev) 319 return; 320 321 ret = iio_find_closest_gain_low(>s, 2, &in_range); 322 KUNIT_EXPECT_EQ(test, 1, ret); 323 KUNIT_EXPECT_EQ(test, true, in_range); 324 325 ret = iio_find_closest_gain_low(>s, 1, &in_range); 326 KUNIT_EXPECT_EQ(test, 1, ret); 327 KUNIT_EXPECT_EQ(test, true, in_range); 328 329 ret = iio_find_closest_gain_low(>s, 4095, &in_range); 330 KUNIT_EXPECT_EQ(test, 2048, ret); 331 KUNIT_EXPECT_EQ(test, true, in_range); 332 333 ret = iio_find_closest_gain_low(>s, 4097, &in_range); 334 KUNIT_EXPECT_EQ(test, 4096, ret); 335 KUNIT_EXPECT_EQ(test, false, in_range); 336 337 kunit_device_unregister(test, dev); 338 339 dev = __test_init_iio_gain_scale(test, >s, gts_test_gains_gain_low, 340 ARRAY_SIZE(gts_test_gains_gain_low), 341 gts_test_itimes, ARRAY_SIZE(gts_test_itimes)); 342 if (!dev) 343 return; 344 345 ret = iio_find_closest_gain_low(>s, 3, &in_range); 346 KUNIT_EXPECT_EQ(test, -EINVAL, ret); 347 KUNIT_EXPECT_EQ(test, false, in_range); 348 } 349 350 static void test_iio_gts_total_gain_to_scale(struct kunit *test) 351 { 352 struct device *dev; 353 int ret, scale_int, scale_nano; 354 355 dev = test_init_iio_gain_scale(test, >s); 356 if (!dev) 357 return; 358 359 ret = iio_gts_total_gain_to_scale(>s, 1, &scale_int, &scale_nano); 360 KUNIT_EXPECT_EQ(test, 0, ret); 361 KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int); 362 KUNIT_EXPECT_EQ(test, 0, scale_nano); 363 364 ret = iio_gts_total_gain_to_scale(>s, 1, &scale_int, &scale_nano); 365 KUNIT_EXPECT_EQ(test, 0, ret); 366 KUNIT_EXPECT_EQ(test, TEST_SCALE_1X, scale_int); 367 KUNIT_EXPECT_EQ(test, 0, scale_nano); 368 369 ret = iio_gts_total_gain_to_scale(>s, 4096 * 8, &scale_int, 370 &scale_nano); 371 KUNIT_EXPECT_EQ(test, 0, ret); 372 KUNIT_EXPECT_EQ(test, 0, scale_int); 373 KUNIT_EXPECT_EQ(test, TEST_SCALE_NANO_4096X8, scale_nano); 374 } 375 376 static void test_iio_gts_chk_times(struct kunit *test, const int *vals) 377 { 378 static const int expected[] = {0, 50000, 0, 100000, 0, 200000, 0, 400000}; 379 int i; 380 381 for (i = 0; i < ARRAY_SIZE(expected); i++) 382 KUNIT_EXPECT_EQ(test, expected[i], vals[i]); 383 } 384 385 static void test_iio_gts_chk_scales_all(struct kunit *test, struct iio_gts *gts, 386 const int *vals, int len) 387 { 388 static const int gains[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 389 1024, 2048, 4096, 4096 * 2, 4096 * 4, 390 4096 * 8}; 391 int expected[ARRAY_SIZE(gains) * 2]; 392 int i, ret; 393 int exp_len = ARRAY_SIZE(gains) * 2; 394 395 KUNIT_EXPECT_EQ(test, exp_len, len); 396 if (len != exp_len) 397 return; 398 399 for (i = 0; i < ARRAY_SIZE(gains); i++) { 400 ret = iio_gts_total_gain_to_scale(gts, gains[i], 401 &expected[2 * i], 402 &expected[2 * i + 1]); 403 KUNIT_EXPECT_EQ(test, 0, ret); 404 if (ret) 405 return; 406 } 407 408 for (i = 0; i < ARRAY_SIZE(expected); i++) 409 KUNIT_EXPECT_EQ(test, expected[i], vals[i]); 410 } 411 412 static void test_iio_gts_chk_scales_t200(struct kunit *test, struct iio_gts *gts, 413 const int *vals, int len) 414 { 415 /* The gain caused by time 200 is 4x */ 416 static const int gains[] = { 417 1 * 4, 418 4 * 4, 419 16 * 4, 420 32 * 4, 421 64 * 4, 422 256 * 4, 423 512 * 4, 424 1024 * 4, 425 2048 * 4, 426 4096 * 4 427 }; 428 int expected[ARRAY_SIZE(gains) * 2]; 429 int i, ret; 430 431 KUNIT_EXPECT_EQ(test, 2 * ARRAY_SIZE(gains), len); 432 if (len < 2 * ARRAY_SIZE(gains)) 433 return; 434 435 for (i = 0; i < ARRAY_SIZE(gains); i++) { 436 ret = iio_gts_total_gain_to_scale(gts, gains[i], 437 &expected[2 * i], 438 &expected[2 * i + 1]); 439 KUNIT_EXPECT_EQ(test, 0, ret); 440 if (ret) 441 return; 442 } 443 444 for (i = 0; i < ARRAY_SIZE(expected); i++) 445 KUNIT_EXPECT_EQ(test, expected[i], vals[i]); 446 } 447 448 static void test_iio_gts_avail_test(struct kunit *test) 449 { 450 struct device *dev; 451 int ret; 452 int type, len; 453 const int *vals; 454 455 dev = test_init_iio_gain_scale(test, >s); 456 if (!dev) 457 return; 458 459 /* test table building for times and iio_gts_avail_times() */ 460 ret = iio_gts_avail_times(>s, &vals, &type, &len); 461 KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); 462 if (ret) 463 return; 464 465 KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_MICRO, type); 466 KUNIT_EXPECT_EQ(test, 8, len); 467 if (len < 8) 468 return; 469 470 test_iio_gts_chk_times(test, vals); 471 472 /* Test table building for all scales and iio_gts_all_avail_scales() */ 473 ret = iio_gts_all_avail_scales(>s, &vals, &type, &len); 474 KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); 475 if (ret) 476 return; 477 478 KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type); 479 480 test_iio_gts_chk_scales_all(test, >s, vals, len); 481 482 /* 483 * Test table building for scales/time and 484 * iio_gts_avail_scales_for_time() 485 */ 486 ret = iio_gts_avail_scales_for_time(>s, 200000, &vals, &type, &len); 487 KUNIT_EXPECT_EQ(test, IIO_AVAIL_LIST, ret); 488 if (ret) 489 return; 490 491 KUNIT_EXPECT_EQ(test, IIO_VAL_INT_PLUS_NANO, type); 492 test_iio_gts_chk_scales_t200(test, >s, vals, len); 493 } 494 495 static struct kunit_case iio_gts_test_cases[] = { 496 KUNIT_CASE(test_init_iio_gts_invalid), 497 KUNIT_CASE(test_iio_gts_find_gain_for_scale_using_time), 498 KUNIT_CASE(test_iio_gts_find_new_gain_sel_by_old_gain_time), 499 KUNIT_CASE(test_iio_find_closest_gain_low), 500 KUNIT_CASE(test_iio_gts_total_gain_to_scale), 501 KUNIT_CASE(test_iio_gts_avail_test), 502 {} 503 }; 504 505 static struct kunit_suite iio_gts_test_suite = { 506 .name = "iio-gain-time-scale", 507 .test_cases = iio_gts_test_cases, 508 }; 509 510 kunit_test_suite(iio_gts_test_suite); 511 512 MODULE_LICENSE("GPL"); 513 MODULE_AUTHOR("Matti Vaittinen <mazziesaccount@gmail.com>"); 514 MODULE_DESCRIPTION("Test IIO light sensor gain-time-scale helpers"); 515 MODULE_IMPORT_NS(IIO_GTS_HELPER); 516