| /* Copyright 2019 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "common.h" |
| #include "console.h" |
| #include "i2c.h" |
| #include "i2c_bitbang.h" |
| #include "test_util.h" |
| #include "util.h" |
| |
| const struct i2c_port_t i2c_bitbang_ports[] = { |
| {"", 0, 100, GPIO_I2C_SCL, GPIO_I2C_SDA} |
| }; |
| const unsigned int i2c_bitbang_ports_used = 1; |
| |
| struct pin_state { |
| int scl, sda; |
| } history[64]; |
| |
| int history_count; |
| |
| void reset_state(void) |
| { |
| history[0] = (struct pin_state) {1, 1}; |
| history_count = 1; |
| bitbang_set_started(0); |
| } |
| |
| void gpio_set_level(enum gpio_signal signal, int level) |
| { |
| struct pin_state new = history[history_count - 1]; |
| |
| /* reject if stack is full */ |
| if (history_count >= ARRAY_SIZE(history)) |
| return; |
| |
| if (signal == GPIO_I2C_SDA) |
| new.sda = level; |
| else if (signal == GPIO_I2C_SCL) |
| new.scl = level; |
| |
| if (new.scl != history[history_count - 1].scl || |
| new.sda != history[history_count - 1].sda) |
| history[history_count++] = new; |
| } |
| |
| int gpio_get_level(enum gpio_signal signal) |
| { |
| if (signal == GPIO_I2C_SDA) |
| return history[history_count - 1].sda; |
| else if (signal == GPIO_I2C_SCL) |
| return history[history_count - 1].scl; |
| |
| return 0; |
| } |
| |
| static int test_i2c_start_stop(void) |
| { |
| struct pin_state expected[] = { |
| /* start */ |
| {1, 1}, |
| {1, 0}, |
| {0, 0}, |
| /* stop */ |
| {1, 0}, |
| {1, 1}, |
| }; |
| int i; |
| |
| reset_state(); |
| |
| bitbang_start_cond(&i2c_bitbang_ports[0]); |
| bitbang_stop_cond(&i2c_bitbang_ports[0]); |
| |
| TEST_EQ((int)ARRAY_SIZE(expected), history_count, "%d"); |
| |
| for (i = 0; i < ARRAY_SIZE(expected); i++) { |
| TEST_EQ(expected[i].scl, history[i].scl, "%d"); |
| TEST_EQ(expected[i].sda, history[i].sda, "%d"); |
| } |
| |
| return EC_SUCCESS; |
| } |
| |
| static int test_i2c_repeated_start(void) |
| { |
| struct pin_state expected[] = { |
| /* start */ |
| {1, 1}, |
| {1, 0}, |
| {0, 0}, |
| /* repeated start */ |
| {0, 1}, |
| {1, 1}, |
| {1, 0}, |
| {0, 0}, |
| }; |
| int i; |
| |
| reset_state(); |
| |
| bitbang_start_cond(&i2c_bitbang_ports[0]); |
| bitbang_start_cond(&i2c_bitbang_ports[0]); |
| |
| TEST_EQ((int)ARRAY_SIZE(expected), history_count, "%d"); |
| |
| for (i = 0; i < ARRAY_SIZE(expected); i++) { |
| TEST_EQ(expected[i].scl, history[i].scl, "%d"); |
| TEST_EQ(expected[i].sda, history[i].sda, "%d"); |
| } |
| |
| return EC_SUCCESS; |
| } |
| |
| static int test_i2c_write(void) |
| { |
| struct pin_state expected[] = { |
| /* start */ |
| {1, 1}, |
| {1, 0}, |
| {0, 0}, |
| /* bit 7: 0 */ |
| {1, 0}, |
| {0, 0}, |
| /* bit 6: 1 */ |
| {0, 1}, |
| {1, 1}, |
| {0, 1}, |
| /* bit 5: 0 */ |
| {0, 0}, |
| {1, 0}, |
| {0, 0}, |
| /* bit 4: 1 */ |
| {0, 1}, |
| {1, 1}, |
| {0, 1}, |
| /* bit 3: 0 */ |
| {0, 0}, |
| {1, 0}, |
| {0, 0}, |
| /* bit 2: 1 */ |
| {0, 1}, |
| {1, 1}, |
| {0, 1}, |
| /* bit 1: 1 */ |
| {1, 1}, |
| {0, 1}, |
| /* bit 0: 0 */ |
| {0, 0}, |
| {1, 0}, |
| {0, 0}, |
| /* read bit */ |
| {0, 1}, |
| {1, 1}, |
| {0, 1}, |
| /* stop */ |
| {0, 0}, |
| {1, 0}, |
| {1, 1}, |
| }; |
| int i, ret; |
| |
| reset_state(); |
| |
| bitbang_start_cond(&i2c_bitbang_ports[0]); |
| ret = bitbang_write_byte(&i2c_bitbang_ports[0], 0x56); |
| |
| /* expected to fail because no slave answering the nack bit */ |
| TEST_EQ(EC_ERROR_BUSY, ret, "%d"); |
| |
| TEST_EQ((int)ARRAY_SIZE(expected), history_count, "%d"); |
| |
| for (i = 0; i < ARRAY_SIZE(expected); i++) { |
| TEST_EQ(expected[i].scl, history[i].scl, "%d"); |
| TEST_EQ(expected[i].sda, history[i].sda, "%d"); |
| } |
| |
| return EC_SUCCESS; |
| } |
| |
| void run_test(int argc, char **argv) |
| { |
| test_reset(); |
| |
| RUN_TEST(test_i2c_start_stop); |
| RUN_TEST(test_i2c_repeated_start); |
| RUN_TEST(test_i2c_write); |
| |
| test_print_result(); |
| } |