diff options
author | Gwendal Grignou <gwendal@chromium.org> | 2015-06-13 19:41:24 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-06-17 13:10:58 +0000 |
commit | cca70a517b21d32e45880d1296997436d026e7b7 (patch) | |
tree | 1c37f28074f4d9050070d7a540780fd592ff9719 | |
parent | b33531e262561e297ba1a02fc829a2110c6df515 (diff) | |
download | chrome-ec-cca70a517b21d32e45880d1296997436d026e7b7.tar.gz |
common: Add i2c 32bit read/write
Add functions and associated test to read/write a 32 bit register
BRANCH=smaug
TEST=Test on smaug with bm160 driver
BUG=chromium:39900
Change-Id: Ieff24b65f1eb8610874fe13c4a8fadf583a218cb
Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/277535
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/host/i2c.c | 30 | ||||
-rw-r--r-- | common/i2c.c | 62 | ||||
-rw-r--r-- | core/host/host_exe.lds | 8 | ||||
-rw-r--r-- | include/i2c.h | 12 | ||||
-rw-r--r-- | include/link_defs.h | 4 | ||||
-rw-r--r-- | include/test_util.h | 12 | ||||
-rw-r--r-- | test/stress.c | 6 |
7 files changed, 130 insertions, 4 deletions
diff --git a/chip/host/i2c.c b/chip/host/i2c.c index 1ce7da9340..ebf3894a43 100644 --- a/chip/host/i2c.c +++ b/chip/host/i2c.c @@ -75,6 +75,36 @@ static int test_check_detached(int port, int slave_addr) return 0; } +int i2c_read32(int port, int slave_addr, int offset, int *data) +{ + const struct test_i2c_read_dev *p; + int rv; + + if (test_check_detached(port, slave_addr)) + return EC_ERROR_UNKNOWN; + for (p = __test_i2c_read32; p < __test_i2c_read32_end; ++p) { + rv = p->routine(port, slave_addr, offset, data); + if (rv != EC_ERROR_INVAL) + return rv; + } + return EC_ERROR_UNKNOWN; +} + +int i2c_write32(int port, int slave_addr, int offset, int data) +{ + const struct test_i2c_write_dev *p; + int rv; + + if (test_check_detached(port, slave_addr)) + return EC_ERROR_UNKNOWN; + for (p = __test_i2c_write32; p < __test_i2c_write32_end; ++p) { + rv = p->routine(port, slave_addr, offset, data); + if (rv != EC_ERROR_INVAL) + return rv; + } + return EC_ERROR_UNKNOWN; +} + int i2c_read16(int port, int slave_addr, int offset, int *data) { const struct test_i2c_read_dev *p; diff --git a/common/i2c.c b/common/i2c.c index 4a851da39d..518bca0647 100644 --- a/common/i2c.c +++ b/common/i2c.c @@ -77,15 +77,68 @@ void i2c_prepare_sysjump(void) i2c_lock(i2c_ports[i].port, 1); } +int i2c_read32(int port, int slave_addr, int offset, int *data) +{ + int rv; + uint8_t reg, buf[sizeof(uint32_t)]; + + reg = offset & 0xff; + /* I2C read 32-bit word: transmit 8-bit offset, and read 32bits */ + i2c_lock(port, 1); + rv = i2c_xfer(port, slave_addr, ®, 1, buf, sizeof(uint32_t), + I2C_XFER_SINGLE); + i2c_lock(port, 0); + + if (rv) + return rv; + + if (slave_addr & I2C_FLAG_BIG_ENDIAN) + *data = ((int)buf[0] << 24) | ((int)buf[1] << 16) | + ((int)buf[0] << 8) | buf[1]; + else + *data = ((int)buf[3] << 24) | ((int)buf[2] << 16) | + ((int)buf[1] << 8) | buf[0]; + + return EC_SUCCESS; +} + +int i2c_write32(int port, int slave_addr, int offset, int data) +{ + int rv; + uint8_t buf[1 + sizeof(uint32_t)]; + + buf[0] = offset & 0xff; + + if (slave_addr & I2C_FLAG_BIG_ENDIAN) { + buf[1] = (data >> 24) & 0xff; + buf[2] = (data >> 16) & 0xff; + buf[3] = (data >> 8) & 0xff; + buf[4] = data & 0xff; + } else { + buf[1] = data & 0xff; + buf[2] = (data >> 8) & 0xff; + buf[3] = (data >> 16) & 0xff; + buf[4] = (data >> 24) & 0xff; + } + + i2c_lock(port, 1); + rv = i2c_xfer(port, slave_addr, buf, sizeof(uint32_t) + 1, NULL, 0, + I2C_XFER_SINGLE); + i2c_lock(port, 0); + + return rv; +} + int i2c_read16(int port, int slave_addr, int offset, int *data) { int rv; - uint8_t reg, buf[2]; + uint8_t reg, buf[sizeof(uint16_t)]; reg = offset & 0xff; /* I2C read 16-bit word: transmit 8-bit offset, and read 16bits */ i2c_lock(port, 1); - rv = i2c_xfer(port, slave_addr, ®, 1, buf, 2, I2C_XFER_SINGLE); + rv = i2c_xfer(port, slave_addr, ®, 1, buf, sizeof(uint16_t), + I2C_XFER_SINGLE); i2c_lock(port, 0); if (rv) @@ -102,7 +155,7 @@ int i2c_read16(int port, int slave_addr, int offset, int *data) int i2c_write16(int port, int slave_addr, int offset, int data) { int rv; - uint8_t buf[3]; + uint8_t buf[1 + sizeof(uint16_t)]; buf[0] = offset & 0xff; @@ -115,7 +168,8 @@ int i2c_write16(int port, int slave_addr, int offset, int data) } i2c_lock(port, 1); - rv = i2c_xfer(port, slave_addr, buf, 3, NULL, 0, I2C_XFER_SINGLE); + rv = i2c_xfer(port, slave_addr, buf, 1 + sizeof(uint16_t), NULL, 0, + I2C_XFER_SINGLE); i2c_lock(port, 0); return rv; diff --git a/core/host/host_exe.lds b/core/host/host_exe.lds index e61b2d1c48..a30ebb4219 100644 --- a/core/host/host_exe.lds +++ b/core/host/host_exe.lds @@ -104,6 +104,14 @@ SECTIONS { *(.rodata.test_i2c.write16) __test_i2c_write16_end = .; + __test_i2c_read32 = .; + *(.rodata.test_i2c.read32) + __test_i2c_read32_end = .; + + __test_i2c_write32 = .; + *(.rodata.test_i2c.write32) + __test_i2c_write32_end = .; + __test_i2c_read_string = .; *(.rodata.test_i2c.read_string) __test_i2c_read_string_end = .; diff --git a/include/i2c.h b/include/i2c.h index dbc51eebbd..674dd84e80 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -162,6 +162,18 @@ void i2c_prepare_sysjump(void); void i2c_set_timeout(int port, uint32_t timeout); /** + * Read a 32-bit register from the slave at 8-bit slave address <slaveaddr>, at + * the specified 8-bit <offset> in the slave's address space. + */ +int i2c_read32(int port, int slave_addr, int offset, int *data); + +/** + * Write a 32-bit register to the slave at 8-bit slave address <slaveaddr>, at + * the specified 8-bit <offset> in the slave's address space. + */ +int i2c_write32(int port, int slave_addr, int offset, int data); + +/** * Read a 16-bit register from the slave at 8-bit slave address <slaveaddr>, at * the specified 8-bit <offset> in the slave's address space. */ diff --git a/include/link_defs.h b/include/link_defs.h index 92783eb946..8c775affa2 100644 --- a/include/link_defs.h +++ b/include/link_defs.h @@ -64,8 +64,12 @@ extern const struct test_i2c_write_dev __test_i2c_write8[]; extern const struct test_i2c_write_dev __test_i2c_write8_end[]; extern const struct test_i2c_read_dev __test_i2c_read16[]; extern const struct test_i2c_read_dev __test_i2c_read16_end[]; +extern const struct test_i2c_read_dev __test_i2c_read32[]; +extern const struct test_i2c_read_dev __test_i2c_read32_end[]; extern const struct test_i2c_write_dev __test_i2c_write16[]; extern const struct test_i2c_write_dev __test_i2c_write16_end[]; +extern const struct test_i2c_write_dev __test_i2c_write32[]; +extern const struct test_i2c_write_dev __test_i2c_write32_end[]; extern const struct test_i2c_read_string_dev __test_i2c_read_string[]; extern const struct test_i2c_read_string_dev __test_i2c_read_string_end[]; diff --git a/include/test_util.h b/include/test_util.h index f8f50fcc76..b62e965563 100644 --- a/include/test_util.h +++ b/include/test_util.h @@ -256,6 +256,18 @@ struct test_i2c_write_dev { __attribute__((section(".rodata.test_i2c.write16"))) \ = {routine} +/* Register an I2C 32-bit read function. */ +#define DECLARE_TEST_I2C_READ32(routine) \ + const struct test_i2c_read_dev __test_i2c_read32_##routine \ + __attribute__((section(".rodata.test_i2c.read32"))) \ + = {routine} + +/* Register an I2C 32-bit write function. */ +#define DECLARE_TEST_I2C_WRITE32(routine) \ + const struct test_i2c_write_dev __test_i2c_write32_##routine \ + __attribute__((section(".rodata.test_i2c.write32"))) \ + = {routine} + #define DECLARE_TEST_I2C_READ_STRING(routine) \ const struct test_i2c_read_string_dev __test_i2c_rs_##routine \ __attribute__((section(".rodata.test_i2c.read_string"))) \ diff --git a/test/stress.c b/test/stress.c index 58a727adbe..5e31d4e466 100644 --- a/test/stress.c +++ b/test/stress.c @@ -98,6 +98,12 @@ static int test_i2c(void) else if (param->width == 16 && param->data >= 0) res = i2c_write16(param->port, param->addr, param->offset, param->data); + else if (param->width == 32 && param->data == -1) + res = i2c_read32(param->port, param->addr, + param->offset, &dummy_data); + else if (param->width == 32 && param->data >= 0) + res = i2c_write32(param->port, param->addr, + param->offset, param->data); return res; } |