diff options
-rw-r--r-- | board/hammer/board.h | 2 | ||||
-rw-r--r-- | common/i2c_master.c | 33 | ||||
-rw-r--r-- | common/usb_i2c.c | 34 | ||||
-rw-r--r-- | extra/touchpad_updater/touchpad_updater.c | 15 | ||||
-rw-r--r-- | include/config.h | 12 | ||||
-rw-r--r-- | include/i2c.h | 4 |
6 files changed, 66 insertions, 34 deletions
diff --git a/board/hammer/board.h b/board/hammer/board.h index c150ac40bd..7febe92ddb 100644 --- a/board/hammer/board.h +++ b/board/hammer/board.h @@ -142,6 +142,8 @@ #undef CONFIG_USB_I2C_MAX_READ_COUNT #define CONFIG_USB_I2C_MAX_READ_COUNT (1024 - 6) /* 6 is maximum header size */ +#define CONFIG_I2C_XFER_LARGE_READ + /* No lid switch */ #undef CONFIG_LID_SWITCH diff --git a/common/i2c_master.c b/common/i2c_master.c index b2f9ec285f..c14ed03d73 100644 --- a/common/i2c_master.c +++ b/common/i2c_master.c @@ -50,6 +50,34 @@ const struct i2c_port_t *get_i2c_port(int port) return NULL; } +#ifdef CONFIG_I2C_XFER_LARGE_READ +/* + * Internal function that splits reading into multiple chip_i2c_xfer() calls + * if in_size exceeds CONFIG_I2C_CHIP_MAX_READ_SIZE. + */ +static int i2c_xfer_no_retry(int port, int slave_addr, const uint8_t *out, + int out_size, uint8_t *in, int in_size, int flags) +{ + int ret; + int out_flags = flags & I2C_XFER_START; + int in_chunk_size = MIN(in_size, CONFIG_I2C_CHIP_MAX_READ_SIZE); + + in_size -= in_chunk_size; + out_flags |= !in_size ? (flags & I2C_XFER_STOP) : 0; + ret = chip_i2c_xfer(port, slave_addr, out, out_size, in, in_chunk_size, + out_flags); + in += in_chunk_size; + while (in_size && ret == EC_SUCCESS) { + in_chunk_size = MIN(in_size, CONFIG_I2C_CHIP_MAX_READ_SIZE); + in_size -= in_chunk_size; + ret = chip_i2c_xfer(port, slave_addr, NULL, 0, in, + in_chunk_size, !in_size ? (flags & I2C_XFER_STOP) : 0); + in += in_chunk_size; + } + return ret; +} +#endif /* CONFIG_I2C_XFER_LARGE_READ */ + int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size, uint8_t *in, int in_size, int flags) { @@ -57,8 +85,13 @@ int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size, int ret = EC_SUCCESS; for (i = 0; i <= CONFIG_I2C_NACK_RETRY_COUNT; i++) { +#ifdef CONFIG_I2C_XFER_LARGE_READ + ret = i2c_xfer_no_retry(port, slave_addr, out, out_size, in, + in_size, flags); +#else ret = chip_i2c_xfer(port, slave_addr, out, out_size, in, in_size, flags); +#endif /* CONFIG_I2C_XFER_LARGE_READ */ if (ret != EC_ERROR_BUSY) break; } diff --git a/common/usb_i2c.c b/common/usb_i2c.c index de8314f8fa..5fa04e0ba1 100644 --- a/common/usb_i2c.c +++ b/common/usb_i2c.c @@ -84,12 +84,8 @@ void usb_i2c_execute(struct usb_i2c_config const *config) uint8_t slave_addr = (config->buffer[0] >> 7) & 0xfe; int write_count = (config->buffer[1] >> 0) & 0xff; int read_count = (config->buffer[1] >> 8) & 0xff; - uint8_t *payload = (uint8_t *)(config->buffer + 2); - int xfer_flag = I2C_XFER_START; int offset = 0; /* Offset for extended reading header. */ - int rv = 0; - int complete_bytes = 0; - int bytes_to_read, port; + int port; config->buffer[0] = 0; config->buffer[1] = 0; @@ -120,28 +116,12 @@ void usb_i2c_execute(struct usb_i2c_config const *config) * EC_CMD_I2C_PASSTHRU, which can protect ports and ranges. */ port = i2c_ports[portindex].port; - /* - * Because The I2C_XFER_SINGLE might limit the reading to be - * less than 255 bytes (For example, register design of - * STM32_I2C_CR2 in i2c-stm32f0.c), we hold the STOP bits for - * reading request larger than 255 bytes. - */ - do { - bytes_to_read = read_count - complete_bytes; - if (bytes_to_read > MAX_BYTES_IN_ONE_READING) - bytes_to_read = MAX_BYTES_IN_ONE_READING; - else - xfer_flag |= I2C_XFER_STOP; - rv = i2c_xfer( - port, slave_addr, - complete_bytes ? NULL : payload + offset, - complete_bytes ? 0 : write_count, - payload + complete_bytes, - bytes_to_read, xfer_flag); - complete_bytes += bytes_to_read; - xfer_flag = 0; - } while (complete_bytes < read_count && !rv); - config->buffer[0] = usb_i2c_map_error(rv); + config->buffer[0] = usb_i2c_map_error( + i2c_xfer(port, slave_addr, + (uint8_t *)(config->buffer + 2) + offset, + write_count, + (uint8_t *)(config->buffer + 2), + read_count, I2C_XFER_SINGLE)); } usb_i2c_write_packet(config, read_count + 4); } diff --git a/extra/touchpad_updater/touchpad_updater.c b/extra/touchpad_updater/touchpad_updater.c index 059ddb0933..d09b899a8d 100644 --- a/extra/touchpad_updater/touchpad_updater.c +++ b/extra/touchpad_updater/touchpad_updater.c @@ -588,13 +588,16 @@ int main(int argc, char *argv[]) */ elan_get_fw_info(); + /* Trigger an I2C transaction of expecting reading of 633 bytes. */ if (extended_i2c_exercise) { - /* - * Trigger an I2C transaction of expecting reading > 60 bytes. - * source: https://goo.gl/pSxESS - */ - elan_write_and_read(0x0002, rx_buf, 118, 0, 0); - pretty_print_buffer(rx_buf, 118); + tx_buf[0] = 0x05; + tx_buf[1] = 0x00; + tx_buf[2] = 0x3C; + tx_buf[3] = 0x02; + tx_buf[4] = 0x06; + tx_buf[5] = 0x00; + libusb_single_write_and_read(tx_buf, 6, rx_buf, 633); + pretty_print_buffer(rx_buf, 637); } /* Get the trackpad ready for receiving update */ diff --git a/include/config.h b/include/config.h index 713bb87bb5..f5c26ffa55 100644 --- a/include/config.h +++ b/include/config.h @@ -1576,6 +1576,18 @@ #undef CONFIG_I2C_PASSTHRU_RESTRICTED #undef CONFIG_I2C_VIRTUAL_BATTERY +/* + * Conservative I2C reading size per single transaction. For example, register + * of stm32f0 and stm32l4 are limited to be 8 bits for this field. + */ +#define CONFIG_I2C_CHIP_MAX_READ_SIZE 255 + +/* + * Enable i2c_xfer() for receiving request larger than + * CONFIG_I2C_CHIP_MAX_READ_SIZE. + */ +#undef CONFIG_I2C_XFER_LARGE_READ + /* EC uses an I2C master interface */ #undef CONFIG_I2C_MASTER diff --git a/include/i2c.h b/include/i2c.h index 73716cf705..63169ec055 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -89,7 +89,9 @@ extern const int i2c_test_dev_used; #define I2C_XFER_SINGLE (I2C_XFER_START | I2C_XFER_STOP) /* One transaction */ /** - * Transmit one block of raw data, then receive one block of raw data. + * Transmit one block of raw data, then receive one block of raw data. However, + * received data might be capped at CONFIG_I2C_CHIP_MAX_READ_SIZE if + * CONFIG_I2C_XFER_LARGE_READ is not defined. * * This is a wrapper function for chip_i2c_xfer(), a low-level chip-dependent * function. It must be called between i2c_lock(port, 1) and i2c_lock(port, 0). |