summaryrefslogtreecommitdiff
path: root/test/i2c_bitbang.c
diff options
context:
space:
mode:
authorTing Shen <phoenixshen@google.com>2019-10-23 20:02:10 +0800
committerCommit Bot <commit-bot@chromium.org>2019-12-16 08:06:04 +0000
commit7b61704fd1a09c5aae26f163e096d9695e479f21 (patch)
tree2692c9bdf01c6a73625b46c3bc5092bbb9ffaf06 /test/i2c_bitbang.c
parent7c89289e32ba60dca6d00aca6827b6ebe82f87ba (diff)
downloadchrome-ec-7b61704fd1a09c5aae26f163e096d9695e479f21.tar.gz
i2c: add support for i2c bit-banging
Krane/Jacuzzi need a 100KHz SMBus port for battery, in addition to the existing two i2c ports. This CL adds a bit-bang driver that supports i2c/smbus bit-banging through a set of pre-defined gpio pins. BUG=b:138161741,b:138415463 TEST=On a reworked jacuzzi (battery i2c connected to other gpios), 1) `battery` shows reasonable output (this verifies i2c_readN, i2c_read_string) 2) `i2cscan` works for port 3 (bitbang port) 3) `cutoff` (verifies i2c_writeN) 4) `i2ctest` stress test BRANCH=master Change-Id: I78020e5c51707c3d9f0fd54f2c299e2f29cabe2f Signed-off-by: Ting Shen <phoenixshen@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1765110 Reviewed-by: Alexandru M Stan <amstan@chromium.org> Commit-Queue: Ting Shen <phoenixshen@chromium.org> Tested-by: Ting Shen <phoenixshen@chromium.org>
Diffstat (limited to 'test/i2c_bitbang.c')
-rw-r--r--test/i2c_bitbang.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/test/i2c_bitbang.c b/test/i2c_bitbang.c
new file mode 100644
index 0000000000..6440e9b363
--- /dev/null
+++ b/test/i2c_bitbang.c
@@ -0,0 +1,192 @@
+/* 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(void)
+{
+ test_reset();
+
+ RUN_TEST(test_i2c_start_stop);
+ RUN_TEST(test_i2c_repeated_start);
+ RUN_TEST(test_i2c_write);
+
+ test_print_result();
+}