summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Honscheid <honscheid@google.com>2022-09-26 18:25:44 -0600
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-10-04 19:18:36 +0000
commitf079a846def4856bb955d3b038171ff44d4887bb (patch)
tree7eea3b4aeb6bedc387e54b20073832c1ad8f2487
parent23b4ab16f3f7e8f11f9198cfc35a722a2eaa3ef7 (diff)
downloadchrome-ec-f079a846def4856bb955d3b038171ff44d4887bb.tar.gz
zephyr: tests: Move non-Zephyr code out of i2c_controller.c
This CL moves 76 SLOC that is not used in Zephyr out of i2c_controller.c and in to i2c_controller_cros_ec.c. Add a guard to that file so it cannot be built with CONFIG_ZEPHYR defined. BRANCH=None BUG=b:248311206 TEST=make BOARD=brya -j LOW_COVERAGE_REASON=No new code, moving non-Zephyr code to new file Signed-off-by: Tristan Honscheid <honscheid@google.com> Change-Id: I3f71c15baf87d2e59851022d784f2257521cfef6 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3922974 Reviewed-by: Yuval Peress <peress@google.com> Code-Coverage: Zoss <zoss-cl-coverage@prod.google.com>
-rw-r--r--common/i2c_controller.c218
-rw-r--r--common/i2c_controller_cros_ec.c228
2 files changed, 228 insertions, 218 deletions
diff --git a/common/i2c_controller.c b/common/i2c_controller.c
index e2f4149b16..b51f726369 100644
--- a/common/i2c_controller.c
+++ b/common/i2c_controller.c
@@ -30,13 +30,6 @@
#include "i2c/i2c.h"
#endif /* CONFIG_ZEPHYR */
-/* Delay for bitbanging i2c corresponds roughly to 100kHz. */
-#define I2C_BITBANG_DELAY_US 5
-
-/* Number of attempts to unwedge each pin. */
-#define UNWEDGE_SCL_ATTEMPTS 10
-#define UNWEDGE_SDA_ATTEMPTS 3
-
#define CPUTS(outstr) cputs(CC_I2C, outstr)
#define CPRINTS(format, args...) cprints(CC_I2C, format, ##args)
#define CPRINTF(format, args...) cprintf(CC_I2C, format, ##args)
@@ -866,217 +859,6 @@ int i2c_write_block(const int port, const uint16_t addr_flags, int offset,
return rv;
}
-#ifndef CONFIG_ZEPHYR
-int get_sda_from_i2c_port(int port, enum gpio_signal *sda)
-{
- const struct i2c_port_t *i2c_port = get_i2c_port(port);
-
- /* Crash if the port given is not in the i2c_ports[] table. */
- ASSERT(i2c_port);
-
- /* Check if the SCL and SDA pins have been defined for this port. */
- if (i2c_port->scl == 0 && i2c_port->sda == 0)
- return EC_ERROR_INVAL;
-
- *sda = i2c_port->sda;
- return EC_SUCCESS;
-}
-
-int get_scl_from_i2c_port(int port, enum gpio_signal *scl)
-{
- const struct i2c_port_t *i2c_port = get_i2c_port(port);
-
- /* Crash if the port given is not in the i2c_ports[] table. */
- ASSERT(i2c_port);
-
- /* Check if the SCL and SDA pins have been defined for this port. */
- if (i2c_port->scl == 0 && i2c_port->sda == 0)
- return EC_ERROR_INVAL;
-
- *scl = i2c_port->scl;
- return EC_SUCCESS;
-}
-
-void i2c_raw_set_scl(int port, int level)
-{
- enum gpio_signal g;
-
- if (get_scl_from_i2c_port(port, &g) == EC_SUCCESS)
- gpio_set_level(g, level);
-}
-
-void i2c_raw_set_sda(int port, int level)
-{
- enum gpio_signal g;
-
- if (get_sda_from_i2c_port(port, &g) == EC_SUCCESS)
- gpio_set_level(g, level);
-}
-
-int i2c_raw_mode(int port, int enable)
-{
- enum gpio_signal sda, scl;
- int ret_sda, ret_scl;
-
- /* Get the SDA and SCL pins for this port. If none, then return. */
- if (get_sda_from_i2c_port(port, &sda) != EC_SUCCESS)
- return EC_ERROR_INVAL;
- if (get_scl_from_i2c_port(port, &scl) != EC_SUCCESS)
- return EC_ERROR_INVAL;
-
- if (enable) {
- int raw_gpio_mode_flags = GPIO_ODR_HIGH;
-
- /* If the CLK line is 1.8V, then ensure we set 1.8V mode */
- if ((gpio_list + scl)->flags & GPIO_SEL_1P8V)
- raw_gpio_mode_flags |= GPIO_SEL_1P8V;
-
- /*
- * To enable raw mode, take out of alternate function mode and
- * set the flags to open drain output.
- */
- ret_sda = gpio_config_pin(MODULE_I2C, sda, 0);
- ret_scl = gpio_config_pin(MODULE_I2C, scl, 0);
-
- gpio_set_flags(scl, raw_gpio_mode_flags);
- gpio_set_flags(sda, raw_gpio_mode_flags);
- } else {
- /*
- * Configure the I2C pins to exit raw mode and return
- * to normal mode.
- */
- ret_sda = gpio_config_pin(MODULE_I2C, sda, 1);
- ret_scl = gpio_config_pin(MODULE_I2C, scl, 1);
- }
-
- return ret_sda == EC_SUCCESS ? ret_scl : ret_sda;
-}
-
-/*
- * Unwedge the i2c bus for the given port.
- *
- * Some devices on our i2c busses keep power even if we get a reset. That
- * means that they could be part way through a transaction and could be
- * driving the bus in a way that makes it hard for us to talk on the bus.
- * ...or they might listen to the next transaction and interpret it in a
- * weird way.
- *
- * Note that devices could be in one of several states:
- * - If a device got interrupted in a write transaction it will be watching
- * for additional data to finish its write. It will probably be looking to
- * ack the data (drive the data line low) after it gets everything.
- * - If a device got interrupted while responding to a register read, it will
- * be watching for clocks and will drive data out when it sees clocks. At
- * the moment it might be trying to send out a 1 (so both clock and data
- * may be high) or it might be trying to send out a 0 (so it's driving data
- * low).
- *
- * We attempt to unwedge the bus by doing:
- * - If SCL is being held low, then a peripheral is clock extending. The only
- * thing we can do is try to wait until the peripheral stops clock extending.
- * - Otherwise, we will toggle the clock until the peripheral releases the SDA
- * line. Once the SDA line is released, try to send a STOP bit. Rinse and
- * repeat until either the bus is normal, or we run out of attempts.
- *
- * Note this should work for most devices, but depending on the peripheral's
- * i2c state machine, it may not be possible to unwedge the bus.
- */
-int i2c_unwedge(int port)
-{
- int i, j;
- int ret = EC_SUCCESS;
-
-#ifdef CONFIG_I2C_BUS_MAY_BE_UNPOWERED
- /*
- * Don't try to unwedge the port if we know it's unpowered; it's futile.
- */
- if (!board_is_i2c_port_powered(port)) {
- CPRINTS("Skipping i2c unwedge, bus not powered.");
- return EC_ERROR_NOT_POWERED;
- }
-#endif /* CONFIG_I2C_BUS_MAY_BE_UNPOWERED */
-
- /* Try to put port in to raw bit bang mode. */
- if (i2c_raw_mode(port, 1) != EC_SUCCESS)
- return EC_ERROR_UNKNOWN;
-
- /*
- * If clock is low, wait for a while in case of clock stretched
- * by a peripheral.
- */
- if (!i2c_raw_get_scl(port)) {
- for (i = 0;; i++) {
- if (i >= UNWEDGE_SCL_ATTEMPTS) {
- /*
- * If we get here, a peripheral is holding the
- * clock low and there is nothing we can do.
- */
- CPRINTS("I2C%d unwedge failed, "
- "SCL is held low",
- port);
- ret = EC_ERROR_UNKNOWN;
- goto unwedge_done;
- }
- udelay(I2C_BITBANG_DELAY_US);
- if (i2c_raw_get_scl(port))
- break;
- }
- }
-
- if (i2c_raw_get_sda(port))
- goto unwedge_done;
-
- CPRINTS("I2C%d unwedge called with SDA held low", port);
-
- /* Keep trying to unwedge the SDA line until we run out of attempts. */
- for (i = 0; i < UNWEDGE_SDA_ATTEMPTS; i++) {
- /* Drive the clock high. */
- i2c_raw_set_scl(port, 1);
- udelay(I2C_BITBANG_DELAY_US);
-
- /*
- * Clock through the problem by clocking out 9 bits. If
- * peripheral releases the SDA line, then we can stop clocking
- * bits and send a STOP.
- */
- for (j = 0; j < 9; j++) {
- if (i2c_raw_get_sda(port))
- break;
-
- i2c_raw_set_scl(port, 0);
- udelay(I2C_BITBANG_DELAY_US);
- i2c_raw_set_scl(port, 1);
- udelay(I2C_BITBANG_DELAY_US);
- }
-
- /* Take control of SDA line and issue a STOP command. */
- i2c_raw_set_sda(port, 0);
- udelay(I2C_BITBANG_DELAY_US);
- i2c_raw_set_sda(port, 1);
- udelay(I2C_BITBANG_DELAY_US);
-
- /* Check if the bus is unwedged. */
- if (i2c_raw_get_sda(port) && i2c_raw_get_scl(port))
- break;
- }
-
- if (!i2c_raw_get_sda(port)) {
- CPRINTS("I2C%d unwedge failed, SDA still low", port);
- ret = EC_ERROR_UNKNOWN;
- }
- if (!i2c_raw_get_scl(port)) {
- CPRINTS("I2C%d unwedge failed, SCL still low", port);
- ret = EC_ERROR_UNKNOWN;
- }
-
-unwedge_done:
- /* Take port out of raw bit bang mode. */
- i2c_raw_mode(port, 0);
-
- return ret;
-}
-#endif /* !CONFIG_ZEPHYR */
-
int i2c_freq_to_khz(enum i2c_freq freq)
{
switch (freq) {
diff --git a/common/i2c_controller_cros_ec.c b/common/i2c_controller_cros_ec.c
index e8c25e14ca..aafeb504ce 100644
--- a/common/i2c_controller_cros_ec.c
+++ b/common/i2c_controller_cros_ec.c
@@ -3,6 +3,10 @@
* found in the LICENSE file.
*/
+#include "builtin/assert.h"
+#include "system.h"
+#include "gpio.h"
+
#include "i2c_bitbang.h"
#include "i2c_private.h"
#include "i2c.h"
@@ -15,6 +19,230 @@
* (CrOS EC) builds.
*/
+#ifdef CONFIG_ZEPHYR
+#error "Don't use this source in Zephyr builds"
+#endif
+
+/* Delay for bitbanging i2c corresponds roughly to 100kHz. */
+#define I2C_BITBANG_DELAY_US 5
+
+/* Number of attempts to unwedge each pin. */
+#define UNWEDGE_SCL_ATTEMPTS 10
+#define UNWEDGE_SDA_ATTEMPTS 3
+
+#define CPUTS(outstr) cputs(CC_I2C, outstr)
+#define CPRINTS(format, args...) cprints(CC_I2C, format, ##args)
+#define CPRINTF(format, args...) cprintf(CC_I2C, format, ##args)
+
+int get_sda_from_i2c_port(int port, enum gpio_signal *sda)
+{
+ const struct i2c_port_t *i2c_port = get_i2c_port(port);
+
+ /* Crash if the port given is not in the i2c_ports[] table. */
+ ASSERT(i2c_port);
+
+ /* Check if the SCL and SDA pins have been defined for this port. */
+ if (i2c_port->scl == 0 && i2c_port->sda == 0)
+ return EC_ERROR_INVAL;
+
+ *sda = i2c_port->sda;
+ return EC_SUCCESS;
+}
+
+int get_scl_from_i2c_port(int port, enum gpio_signal *scl)
+{
+ const struct i2c_port_t *i2c_port = get_i2c_port(port);
+
+ /* Crash if the port given is not in the i2c_ports[] table. */
+ ASSERT(i2c_port);
+
+ /* Check if the SCL and SDA pins have been defined for this port. */
+ if (i2c_port->scl == 0 && i2c_port->sda == 0)
+ return EC_ERROR_INVAL;
+
+ *scl = i2c_port->scl;
+ return EC_SUCCESS;
+}
+
+void i2c_raw_set_scl(int port, int level)
+{
+ enum gpio_signal g;
+
+ if (get_scl_from_i2c_port(port, &g) == EC_SUCCESS)
+ gpio_set_level(g, level);
+}
+
+void i2c_raw_set_sda(int port, int level)
+{
+ enum gpio_signal g;
+
+ if (get_sda_from_i2c_port(port, &g) == EC_SUCCESS)
+ gpio_set_level(g, level);
+}
+
+int i2c_raw_mode(int port, int enable)
+{
+ enum gpio_signal sda, scl;
+ int ret_sda, ret_scl;
+
+ /* Get the SDA and SCL pins for this port. If none, then return. */
+ if (get_sda_from_i2c_port(port, &sda) != EC_SUCCESS)
+ return EC_ERROR_INVAL;
+ if (get_scl_from_i2c_port(port, &scl) != EC_SUCCESS)
+ return EC_ERROR_INVAL;
+
+ if (enable) {
+ int raw_gpio_mode_flags = GPIO_ODR_HIGH;
+
+ /* If the CLK line is 1.8V, then ensure we set 1.8V mode */
+ if ((gpio_list + scl)->flags & GPIO_SEL_1P8V)
+ raw_gpio_mode_flags |= GPIO_SEL_1P8V;
+
+ /*
+ * To enable raw mode, take out of alternate function mode and
+ * set the flags to open drain output.
+ */
+ ret_sda = gpio_config_pin(MODULE_I2C, sda, 0);
+ ret_scl = gpio_config_pin(MODULE_I2C, scl, 0);
+
+ gpio_set_flags(scl, raw_gpio_mode_flags);
+ gpio_set_flags(sda, raw_gpio_mode_flags);
+ } else {
+ /*
+ * Configure the I2C pins to exit raw mode and return
+ * to normal mode.
+ */
+ ret_sda = gpio_config_pin(MODULE_I2C, sda, 1);
+ ret_scl = gpio_config_pin(MODULE_I2C, scl, 1);
+ }
+
+ return ret_sda == EC_SUCCESS ? ret_scl : ret_sda;
+}
+
+/*
+ * Unwedge the i2c bus for the given port.
+ *
+ * Some devices on our i2c busses keep power even if we get a reset. That
+ * means that they could be part way through a transaction and could be
+ * driving the bus in a way that makes it hard for us to talk on the bus.
+ * ...or they might listen to the next transaction and interpret it in a
+ * weird way.
+ *
+ * Note that devices could be in one of several states:
+ * - If a device got interrupted in a write transaction it will be watching
+ * for additional data to finish its write. It will probably be looking to
+ * ack the data (drive the data line low) after it gets everything.
+ * - If a device got interrupted while responding to a register read, it will
+ * be watching for clocks and will drive data out when it sees clocks. At
+ * the moment it might be trying to send out a 1 (so both clock and data
+ * may be high) or it might be trying to send out a 0 (so it's driving data
+ * low).
+ *
+ * We attempt to unwedge the bus by doing:
+ * - If SCL is being held low, then a peripheral is clock extending. The only
+ * thing we can do is try to wait until the peripheral stops clock extending.
+ * - Otherwise, we will toggle the clock until the peripheral releases the SDA
+ * line. Once the SDA line is released, try to send a STOP bit. Rinse and
+ * repeat until either the bus is normal, or we run out of attempts.
+ *
+ * Note this should work for most devices, but depending on the peripheral's
+ * i2c state machine, it may not be possible to unwedge the bus.
+ */
+int i2c_unwedge(int port)
+{
+ int i, j;
+ int ret = EC_SUCCESS;
+
+#ifdef CONFIG_I2C_BUS_MAY_BE_UNPOWERED
+ /*
+ * Don't try to unwedge the port if we know it's unpowered; it's futile.
+ */
+ if (!board_is_i2c_port_powered(port)) {
+ CPRINTS("Skipping i2c unwedge, bus not powered.");
+ return EC_ERROR_NOT_POWERED;
+ }
+#endif /* CONFIG_I2C_BUS_MAY_BE_UNPOWERED */
+
+ /* Try to put port in to raw bit bang mode. */
+ if (i2c_raw_mode(port, 1) != EC_SUCCESS)
+ return EC_ERROR_UNKNOWN;
+
+ /*
+ * If clock is low, wait for a while in case of clock stretched
+ * by a peripheral.
+ */
+ if (!i2c_raw_get_scl(port)) {
+ for (i = 0;; i++) {
+ if (i >= UNWEDGE_SCL_ATTEMPTS) {
+ /*
+ * If we get here, a peripheral is holding the
+ * clock low and there is nothing we can do.
+ */
+ CPRINTS("I2C%d unwedge failed, "
+ "SCL is held low",
+ port);
+ ret = EC_ERROR_UNKNOWN;
+ goto unwedge_done;
+ }
+ udelay(I2C_BITBANG_DELAY_US);
+ if (i2c_raw_get_scl(port))
+ break;
+ }
+ }
+
+ if (i2c_raw_get_sda(port))
+ goto unwedge_done;
+
+ CPRINTS("I2C%d unwedge called with SDA held low", port);
+
+ /* Keep trying to unwedge the SDA line until we run out of attempts. */
+ for (i = 0; i < UNWEDGE_SDA_ATTEMPTS; i++) {
+ /* Drive the clock high. */
+ i2c_raw_set_scl(port, 1);
+ udelay(I2C_BITBANG_DELAY_US);
+
+ /*
+ * Clock through the problem by clocking out 9 bits. If
+ * peripheral releases the SDA line, then we can stop clocking
+ * bits and send a STOP.
+ */
+ for (j = 0; j < 9; j++) {
+ if (i2c_raw_get_sda(port))
+ break;
+
+ i2c_raw_set_scl(port, 0);
+ udelay(I2C_BITBANG_DELAY_US);
+ i2c_raw_set_scl(port, 1);
+ udelay(I2C_BITBANG_DELAY_US);
+ }
+
+ /* Take control of SDA line and issue a STOP command. */
+ i2c_raw_set_sda(port, 0);
+ udelay(I2C_BITBANG_DELAY_US);
+ i2c_raw_set_sda(port, 1);
+ udelay(I2C_BITBANG_DELAY_US);
+
+ /* Check if the bus is unwedged. */
+ if (i2c_raw_get_sda(port) && i2c_raw_get_scl(port))
+ break;
+ }
+
+ if (!i2c_raw_get_sda(port)) {
+ CPRINTS("I2C%d unwedge failed, SDA still low", port);
+ ret = EC_ERROR_UNKNOWN;
+ }
+ if (!i2c_raw_get_scl(port)) {
+ CPRINTS("I2C%d unwedge failed, SCL still low", port);
+ ret = EC_ERROR_UNKNOWN;
+ }
+
+unwedge_done:
+ /* Take port out of raw bit bang mode. */
+ i2c_raw_mode(port, 0);
+
+ return ret;
+}
+
#ifdef CONFIG_CMD_I2C_SCAN
static void scan_bus(int port, const char *desc)
{