2020-05-06 16:01:27 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
2020-04-20 14:34:16 +02:00
|
|
|
|
|
|
|
#include <device/i2c_simple.h>
|
2020-05-05 02:44:04 +02:00
|
|
|
#include <limits.h>
|
|
|
|
#include <tests/test.h>
|
2020-04-20 14:34:16 +02:00
|
|
|
|
|
|
|
/* 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[] = {
|
2022-01-10 14:36:47 +01:00
|
|
|
{
|
|
|
|
.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},
|
|
|
|
}
|
|
|
|
},
|
2020-04-20 14:34:16 +02:00
|
|
|
};
|
|
|
|
|
2022-01-10 14:36:47 +01:00
|
|
|
int platform_i2c_transfer(unsigned int bus, struct i2c_msg *segments, int count)
|
2020-04-20 14:34:16 +02:00
|
|
|
{
|
|
|
|
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 */
|
2020-06-11 00:35:08 +02:00
|
|
|
for (i = 0; i < ARRAY_SIZE(i2c_ex_devs); i++)
|
2020-04-20 14:34:16 +02:00
|
|
|
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;
|
|
|
|
};
|
2020-06-11 00:35:08 +02:00
|
|
|
|
|
|
|
return 0;
|
2020-04-20 14:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void mock_expect_params_platform_i2c_transfer(void)
|
|
|
|
{
|
2022-01-10 14:36:47 +01:00
|
|
|
unsigned long int expected_flags[] = {0, I2C_M_RD, I2C_M_TEN, I2C_M_RECV_LEN,
|
|
|
|
I2C_M_NOSTART};
|
2020-04-20 14:34:16 +02:00
|
|
|
|
|
|
|
/* Flags should always be only within supported range */
|
2022-01-10 14:36:47 +01:00
|
|
|
expect_in_set_count(platform_i2c_transfer, segments->flags, expected_flags, -1);
|
2020-04-20 14:34:16 +02:00
|
|
|
|
2022-01-10 14:36:47 +01:00
|
|
|
expect_not_value_count(platform_i2c_transfer, segments->buf, NULL, -1);
|
2020-04-20 14:34:16 +02:00
|
|
|
|
2022-01-10 14:36:47 +01:00
|
|
|
expect_in_range_count(platform_i2c_transfer, count, 1, INT_MAX, -1);
|
2020-04-20 14:34:16 +02:00
|
|
|
}
|
|
|
|
|
2022-01-10 14:36:47 +01:00
|
|
|
#define MASK 0x3
|
|
|
|
#define SHIFT 0x1
|
2020-04-20 14:34:16 +02:00
|
|
|
|
|
|
|
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++) {
|
2022-01-10 14:36:47 +01:00
|
|
|
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);
|
2020-04-20 14:34:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/* 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++) {
|
2022-01-10 14:36:47 +01:00
|
|
|
i2c_read_field(i2c_ex_devs[i].bus, i2c_ex_devs[i].slave,
|
|
|
|
i2c_ex_devs[i].regs[j].reg, &buf, 0xFF, 0);
|
2020-04-20 14:34:16 +02:00
|
|
|
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;
|
2022-01-10 14:36:47 +01:00
|
|
|
i2c_write_field(i2c_ex_devs[i].bus, i2c_ex_devs[i].slave,
|
|
|
|
i2c_ex_devs[i].regs[j].reg, buf, MASK, SHIFT);
|
2020-04-20 14:34:16 +02:00
|
|
|
assert_int_equal(i2c_ex_devs[i].regs[j].data,
|
2022-01-10 14:36:47 +01:00
|
|
|
(tmp & ~(MASK << SHIFT)) | (buf << SHIFT));
|
2020-04-20 14:34:16 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/* 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++) {
|
2022-01-10 14:36:47 +01:00
|
|
|
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);
|
2020-04-20 14:34:16 +02:00
|
|
|
assert_int_equal(buf, 0xFF);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
{
|
2022-01-10 14:36:47 +01:00
|
|
|
const struct CMUnitTest tests[] = {cmocka_unit_test(i2c_read_field_test),
|
|
|
|
cmocka_unit_test(i2c_write_field_test)};
|
2020-04-20 14:34:16 +02:00
|
|
|
|
2021-08-25 16:27:35 +02:00
|
|
|
return cb_run_group_tests(tests, NULL, NULL);
|
2020-04-20 14:34:16 +02:00
|
|
|
}
|