/* SPDX-License-Identifier: GPL-2.0-only */ #include <device/i2c_simple.h> #include <limits.h> #include <tests/test.h> /* Simulate two i2c devices, both on bus 0, each with three uint8_t regs implemented. */ typedef struct { uint8_t reg; uint8_t data; } i2c_ex_regs_t; typedef struct { unsigned int bus; uint8_t slave; i2c_ex_regs_t regs[3]; } i2c_ex_devs_t; i2c_ex_devs_t i2c_ex_devs[] = { {.bus = 0, .slave = 0xA, .regs = { {.reg = 0x0, .data = 0xB}, {.reg = 0x1, .data = 0x6}, {.reg = 0x2, .data = 0xF}, } }, {.bus = 0, .slave = 0x3, .regs = { {.reg = 0x0, .data = 0xDE}, {.reg = 0x1, .data = 0xAD}, {.reg = 0x2, .data = 0xBE}, } }, }; int __wrap_platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, int count) { int i; int reg; struct i2c_msg *tmp = segments; i2c_ex_devs_t *i2c_dev = NULL; check_expected(count); for (i = 0; i < count; i++, segments++) { check_expected_ptr(segments->buf); check_expected(segments->flags); } reg = tmp->buf[0]; /* Find object for requested device */ for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) if (i2c_ex_devs[i].slave == tmp->slave) { i2c_dev = &i2c_ex_devs[i]; break; } if (i2c_dev == NULL) return -1; /* Write commands */ if (tmp->len > 1) { i2c_dev->regs[reg].data = tmp->buf[1]; }; /* Read commands */ for (i = 0; i < count; i++, tmp++) if (tmp->flags & I2C_M_RD) { *(tmp->buf) = i2c_dev->regs[reg].data; }; return 0; } static void mock_expect_params_platform_i2c_transfer(void) { unsigned long int expected_flags[] = {0, I2C_M_RD, I2C_M_TEN, I2C_M_RECV_LEN, I2C_M_NOSTART}; /* Flags should always be only within supported range */ expect_in_set_count(__wrap_platform_i2c_transfer, segments->flags, expected_flags, -1); expect_not_value_count(__wrap_platform_i2c_transfer, segments->buf, NULL, -1); expect_in_range_count(__wrap_platform_i2c_transfer, count, 1, INT_MAX, -1); } #define MASK 0x3 #define SHIFT 0x1 static void i2c_read_field_test(void **state) { int i, j; uint8_t buf; mock_expect_params_platform_i2c_transfer(); /* Read particular bits in all registers in all devices, then compare with expected value. */ for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { i2c_read_field(i2c_ex_devs[i].bus, i2c_ex_devs[i].slave, i2c_ex_devs[i].regs[j].reg, &buf, MASK, SHIFT); assert_int_equal((i2c_ex_devs[i].regs[j].data & (MASK << SHIFT)) >> SHIFT, buf); }; /* Read whole registers */ for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { i2c_read_field(i2c_ex_devs[i].bus, i2c_ex_devs[i].slave, i2c_ex_devs[i].regs[j].reg, &buf, 0xFF, 0); assert_int_equal(i2c_ex_devs[i].regs[j].data, buf); }; } static void i2c_write_field_test(void **state) { int i, j; uint8_t buf, tmp; mock_expect_params_platform_i2c_transfer(); /* Clear particular bits in all registers in all devices, then compare with expected value. */ for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { buf = 0x0; tmp = i2c_ex_devs[i].regs[j].data; i2c_write_field(i2c_ex_devs[i].bus, i2c_ex_devs[i].slave, i2c_ex_devs[i].regs[j].reg, buf, MASK, SHIFT); assert_int_equal(i2c_ex_devs[i].regs[j].data, (tmp & ~(MASK << SHIFT)) | (buf << SHIFT)); }; /* Set all bits in all registers, this time verify using i2c_read_field() accessor. */ for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++) for (j = 0; j < ARRAY_SIZE(i2c_ex_devs[0].regs); j++) { i2c_write_field(i2c_ex_devs[i].bus, i2c_ex_devs[i].slave, i2c_ex_devs[i].regs[j].reg, 0xFF, 0xFF, 0); i2c_read_field(i2c_ex_devs[i].bus, i2c_ex_devs[i].slave, i2c_ex_devs[i].regs[j].reg, &buf, 0xFF, 0); assert_int_equal(buf, 0xFF); }; } int main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(i2c_read_field_test), cmocka_unit_test(i2c_write_field_test) }; return cmocka_run_group_tests(tests, NULL, NULL); }