| /* 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); |
| } |