diff options
Diffstat (limited to 'common/i2c_wedge.c')
-rw-r--r-- | common/i2c_wedge.c | 341 |
1 files changed, 0 insertions, 341 deletions
diff --git a/common/i2c_wedge.c b/common/i2c_wedge.c deleted file mode 100644 index 48bcac090c..0000000000 --- a/common/i2c_wedge.c +++ /dev/null @@ -1,341 +0,0 @@ -/* Copyright 2013 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. - */ - -/* - * Define CONFIG_CMD_I2CWEDGE and I2C_PORT_HOST to enable the 'i2cwedge' - * console command to allow us to bang the bus into a wedged state. For - * example, include the following lines in board/pit/board.h to enable it on - * pit: - * - * #define CONFIG_CMD_I2CWEDGE - * #define I2C_PORT_HOST I2C_PORT_CONTROLLER - * - */ - -#include "console.h" -#include "gpio.h" -#include "i2c.h" -#include "system.h" -#include "timer.h" -#include "util.h" - -/* - * The implementation is based on Wikipedia. - */ - -int i2c_bang_started; - -static void i2c_bang_delay(void) -{ - udelay(5); -} - -static void i2c_bang_start_cond(void) -{ - /* Restart if needed */ - if (i2c_bang_started) { - /* set SDA to 1 */ - i2c_raw_set_sda(I2C_PORT_HOST, 1); - i2c_bang_delay(); - - /* Clock stretching */ - i2c_raw_set_scl(I2C_PORT_HOST, 1); - while (i2c_raw_get_scl(I2C_PORT_HOST) == 0) - ; /* TODO(crosbug.com/p/26487): TIMEOUT */ - - /* Repeated start setup time, minimum 4.7us */ - i2c_bang_delay(); - } - - i2c_raw_set_sda(I2C_PORT_HOST, 1); - if (i2c_raw_get_sda(I2C_PORT_HOST) == 0) - ; /* TODO(crosbug.com/p/26487): arbitration_lost */ - - /* SCL is high, set SDA from 1 to 0. */ - i2c_raw_set_sda(I2C_PORT_HOST, 0); - i2c_bang_delay(); - i2c_raw_set_scl(I2C_PORT_HOST, 0); - i2c_bang_started = 1; - - ccputs("BITBANG: send start\n"); -} - -static void i2c_bang_stop_cond(void) -{ - /* set SDA to 0 */ - i2c_raw_set_sda(I2C_PORT_HOST, 0); - i2c_bang_delay(); - - /* Clock stretching */ - i2c_raw_set_scl(I2C_PORT_HOST, 1); - while (i2c_raw_get_scl(I2C_PORT_HOST) == 0) - ; /* TODO(crosbug.com/p/26487): TIMEOUT */ - - /* Stop bit setup time, minimum 4us */ - i2c_bang_delay(); - - /* SCL is high, set SDA from 0 to 1 */ - i2c_raw_set_sda(I2C_PORT_HOST, 1); - if (i2c_raw_get_sda(I2C_PORT_HOST) == 0) - ; /* TODO(crosbug.com/p/26487): arbitration_lost */ - - i2c_bang_delay(); - - i2c_bang_started = 0; - ccputs("BITBANG: send stop\n"); -} - -static void i2c_bang_out_bit(int bit) -{ - if (bit) - i2c_raw_set_sda(I2C_PORT_HOST, 1); - else - i2c_raw_set_sda(I2C_PORT_HOST, 0); - - i2c_bang_delay(); - - /* Clock stretching */ - i2c_raw_set_scl(I2C_PORT_HOST, 1); - while (i2c_raw_get_scl(I2C_PORT_HOST) == 0) - ; /* TODO(crosbug.com/p/26487): TIMEOUT */ - - /* - * SCL is high, now data is valid - * If SDA is high, check that nobody else is driving SDA - */ - i2c_raw_set_sda(I2C_PORT_HOST, 1); - if (bit && i2c_raw_get_sda(I2C_PORT_HOST) == 0) - ; /* TODO(crosbug.com/p/26487): arbitration_lost */ - - i2c_bang_delay(); - i2c_raw_set_scl(I2C_PORT_HOST, 0); -} - -static int i2c_bang_in_bit(void) -{ - int bit; - - /* Let the peripheral drive data */ - i2c_raw_set_sda(I2C_PORT_HOST, 1); - i2c_bang_delay(); - - /* Clock stretching */ - i2c_raw_set_scl(I2C_PORT_HOST, 1); - while (i2c_raw_get_scl(I2C_PORT_HOST) == 0) - ; /* TODO(crosbug.com/p/26487): TIMEOUT */ - - /* SCL is high, now data is valid */ - bit = i2c_raw_get_sda(I2C_PORT_HOST); - i2c_bang_delay(); - i2c_raw_set_scl(I2C_PORT_HOST, 0); - - return bit; -} - -/* Write a byte to I2C bus. Return 0 if ack by the peripheral. */ -static int i2c_bang_out_byte(int send_start, int send_stop, unsigned char byte) -{ - unsigned bit; - int nack; - int tmp = byte; - - if (send_start) - i2c_bang_start_cond(); - - for (bit = 0; bit < 8; bit++) { - i2c_bang_out_bit((byte & 0x80) != 0); - byte <<= 1; - } - - nack = i2c_bang_in_bit(); - - ccprintf(" write byte: %d ack/nack=%d\n", tmp, nack); - - if (send_stop) - i2c_bang_stop_cond(); - - return nack; -} - -static unsigned char i2c_bang_in_byte(int ack, int send_stop) -{ - unsigned char byte = 0; - int i; - for (i = 0; i < 8; ++i) - byte = (byte << 1) | i2c_bang_in_bit(); - i2c_bang_out_bit(ack != 0); - if (send_stop) - i2c_bang_stop_cond(); - return byte; -} - -static void i2c_bang_init(void) -{ - i2c_bang_started = 0; - - i2c_raw_mode(I2C_PORT_HOST, 1); -} - -static void i2c_bang_xfer(int addr, int reg) -{ - int byte; - - i2c_bang_init(); - - /* State a write command to 'addr' */ - i2c_bang_out_byte(1 /*start*/, 0 /*stop*/, addr); - /* Write 'reg' */ - i2c_bang_out_byte(0 /*start*/, 0 /*stop*/, reg); - - /* Start a read command */ - i2c_bang_out_byte(1 /*start*/, 0 /*stop*/, addr | 1); - - /* Read two bytes */ - byte = i2c_bang_in_byte(0, 0); /* ack and no stop */ - ccprintf(" read byte: %d\n", byte); - byte = i2c_bang_in_byte(1, 1); /* nack and stop */ - ccprintf(" read byte: %d\n", byte); -} - -static void i2c_bang_wedge_write(int addr, int byte, int bit_count, - int reboot) -{ - int i; - - i2c_bang_init(); - - /* State a write command to 'addr' */ - i2c_bang_out_byte(1 /*start*/, 0 /*stop*/, addr); - /* Send a few bits and stop */ - for (i = 0; i < bit_count; ++i) { - i2c_bang_out_bit((byte & 0x80) != 0); - byte <<= 1; - } - ccprintf(" wedged write after %d bits\n", bit_count); - - if (reboot) - system_reset(0); -} - -static void i2c_bang_wedge_read(int addr, int reg, int bit_count, - int reboot) -{ - int i; - - i2c_bang_init(); - - /* State a write command to 'addr' */ - i2c_bang_out_byte(1 /*start*/, 0 /*stop*/, addr); - /* Write 'reg' */ - i2c_bang_out_byte(0 /*start*/, 0 /*stop*/, reg); - - /* Start a read command */ - i2c_bang_out_byte(1 /*start*/, 0 /*stop*/, addr | 1); - - /* Read bit_count bits and stop */ - for (i = 0; i < bit_count; ++i) - i2c_bang_in_bit(); - - ccprintf(" wedged read after %d bits\n", bit_count); - - if (reboot) - system_reset(0); -} - -#define WEDGE_WRITE 1 -#define WEDGE_READ 2 -#define WEDGE_REBOOT 4 - -static int command_i2c_wedge(int argc, char **argv) -{ - int addr, reg, wedge_flag = 0, wedge_bit_count = -1; - char *e; - enum gpio_signal tmp; - - /* Verify that the I2C_PORT_HOST has SDA and SCL pins defined. */ - if (get_sda_from_i2c_port(I2C_PORT_HOST, &tmp) != EC_SUCCESS || - get_scl_from_i2c_port(I2C_PORT_HOST, &tmp) != EC_SUCCESS) { - ccprintf("Cannot wedge bus because no SCL and SDA pins are" - "defined for this port. Check i2c_ports[].\n"); - return EC_SUCCESS; - } - - if (argc < 3) { - ccputs("Usage: i2cwedge addr out_byte " - "[wedge_flag [wedge_bit_count]]\n"); - ccputs(" wedge_flag - (1: wedge out; 2: wedge in;" - " 5: wedge out+reboot; 6: wedge in+reboot)]\n"); - ccputs(" wedge_bit_count - 0 to 8\n"); - return EC_ERROR_UNKNOWN; - } - - addr = strtoi(argv[1], &e, 0); - if (*e) { - ccprintf("Invalid addr %s\n", argv[1]); - return EC_ERROR_INVAL; - } - reg = strtoi(argv[2], &e, 0); - if (*e) { - ccprintf("Invalid out_byte %s\n", argv[2]); - return EC_ERROR_INVAL; - } - if (argc > 3) { - wedge_flag = strtoi(argv[3], &e, 0); - if (*e) { - ccprintf("Invalid wedge_flag %s\n", argv[3]); - return EC_ERROR_INVAL; - } - } - if (argc > 4) { - wedge_bit_count = strtoi(argv[4], &e, 0); - if (*e || wedge_bit_count < 0 || wedge_bit_count > 8) { - ccprintf("Invalid wedge_bit_count %s.\n", argv[4]); - return EC_ERROR_INVAL; - } - } - - i2c_lock(I2C_PORT_HOST, 1); - - if (wedge_flag & WEDGE_WRITE) { - if (wedge_bit_count < 0) - wedge_bit_count = 8; - i2c_bang_wedge_write(addr, reg, wedge_bit_count, - (wedge_flag & WEDGE_REBOOT)); - } else if (wedge_flag & WEDGE_READ) { - if (wedge_bit_count < 0) - wedge_bit_count = 2; - i2c_bang_wedge_read(addr, reg, wedge_bit_count, - (wedge_flag & WEDGE_REBOOT)); - } else { - i2c_bang_xfer(addr, reg); - } - - /* Put it back into normal mode */ - i2c_raw_mode(I2C_PORT_HOST, 0); - - i2c_lock(I2C_PORT_HOST, 0); - - if (wedge_flag & (WEDGE_WRITE | WEDGE_READ)) - ccprintf("I2C bus %d is now wedged. Enjoy.\n", I2C_PORT_HOST); - else - ccprintf("Bit bang xfer complete.\n"); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(i2cwedge, command_i2c_wedge, - "i2cwedge addr out_byte " - "[wedge_flag [wedge_bit_count]]", - "Wedge host I2C bus"); - -static int command_i2c_unwedge(int argc, char **argv) -{ - i2c_unwedge(I2C_PORT_HOST); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(i2cunwedge, command_i2c_unwedge, - "", - "Unwedge host I2C bus"); - |