diff options
Diffstat (limited to 'common/i2c_controller.c')
-rw-r--r-- | common/i2c_controller.c | 218 |
1 files changed, 0 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) { |