[U-Boot] [RFC PATCH 2/2] dm: i2c: support 10bit addressing in I2C uclass layer
Masahiro Yamada
yamada.m at jp.panasonic.com
Fri Dec 19 19:34:24 CET 2014
Master send to / receive from 10-bit addressed slave devices
can be supported by software layer without any hardware change
because the LSB 8bit of the slave address is treated as data part.
Master Send to a 10bit-addressed slave chip is performed like this:
DIR Format
M->S 11110 + address[9:8] + R/W(0)
M->S address[7:0]
M->S data0
M->S data1
...
Master Receive from a 10bit-addressed slave chip is like this:
DIR Format
M->S 11110 + address[9:8] + R/W(0)
M->S address[7:0]
(Restart)
M->S 111110 + address[9:8] + R/W(1)
S->M data0
S->M data1
...
Signed-off-by: Masahiro Yamada <yamada.m at jp.panasonic.com>
Cc: Heiko Schocher <hs at denx.de>
Cc: Simon Glass <sjg at chromium.org>
---
drivers/i2c/i2c-uclass.c | 80 +++++++++++++++++++++++++++++++-----------------
include/i2c.h | 4 +++
2 files changed, 56 insertions(+), 28 deletions(-)
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 005bf86..de9d92a 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -31,20 +31,28 @@ DECLARE_GLOBAL_DATA_PTR;
static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset,
uint8_t offset_buf[], struct i2c_msg *msg)
{
- int offset_len;
+ int offset_len = chip->offset_len;
- msg->addr = chip->chip_addr;
- msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
- msg->len = chip->offset_len;
+ msg->flags = 0;
msg->buf = offset_buf;
- if (!chip->offset_len)
- return -EADDRNOTAVAIL;
- assert(chip->offset_len <= I2C_MAX_OFFSET_LEN);
- offset_len = chip->offset_len;
- while (offset_len--)
+
+ if (chip->flags & DM_I2C_CHIP_10BIT) {
+ msg->addr = I2C_ADDR_TEN_HIGH(chip->chip_addr);
+ *offset_buf++ = I2C_ADDR_TEN_LOW(chip->chip_addr);
+ msg->len = 1;
+ } else {
+ msg->addr = chip->chip_addr;
+ msg->len = 0;
+ }
+
+ assert(offset_len <= I2C_MAX_OFFSET_LEN);
+
+ while (offset_len--) {
*offset_buf++ = offset >> (8 * offset_len);
+ msg->len++;
+ }
- return 0;
+ return msg->len ? 0 : -EADDRNOTAVAIL;
}
static int i2c_read_bytewise(struct udevice *dev, uint offset,
@@ -54,7 +62,7 @@ static int i2c_read_bytewise(struct udevice *dev, uint offset,
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
- uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+ uint8_t offset_buf[I2C_MAX_OFFSET_LEN + 1];
int ret;
int i;
@@ -62,7 +70,8 @@ static int i2c_read_bytewise(struct udevice *dev, uint offset,
if (i2c_setup_offset(chip, offset + i, offset_buf, msg))
return -EINVAL;
ptr = msg + 1;
- ptr->addr = chip->chip_addr;
+ ptr->addr = chip->flags & DM_I2C_CHIP_10BIT ?
+ I2C_ADDR_TEN_HIGH(chip->chip_addr) : chip->chip_addr;
ptr->flags = msg->flags | I2C_M_RD;
ptr->len = 1;
ptr->buf = &buffer[i];
@@ -83,7 +92,7 @@ static int i2c_write_bytewise(struct udevice *dev, uint offset,
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
- uint8_t buf[I2C_MAX_OFFSET_LEN + 1];
+ uint8_t buf[I2C_MAX_OFFSET_LEN + 2];
int ret;
int i;
@@ -106,7 +115,7 @@ int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[2], *ptr;
- uint8_t offset_buf[I2C_MAX_OFFSET_LEN];
+ uint8_t offset_buf[I2C_MAX_OFFSET_LEN + 1];
int msg_count;
if (!ops->xfer)
@@ -118,9 +127,9 @@ int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
ptr++;
if (len) {
- ptr->addr = chip->chip_addr;
- ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
- ptr->flags |= I2C_M_RD;
+ ptr->addr = chip->flags & DM_I2C_CHIP_10BIT ?
+ I2C_ADDR_TEN_HIGH(chip->chip_addr) : chip->chip_addr;
+ ptr->flags = I2C_M_RD;
ptr->len = len;
ptr->buf = buffer;
ptr++;
@@ -136,6 +145,7 @@ int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
struct udevice *bus = dev_get_parent(dev);
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
+ int buf_len;
if (!ops->xfer)
return -ENOSYS;
@@ -157,27 +167,33 @@ int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
* copying the message.
*
* Use the stack for small messages, malloc() for larger ones. We
- * need to allow space for the offset (up to 4 bytes) and the message
+ * need to allow space for the offset (up to 4 bytes), the second
+ * byte of the slave address (if 10bit addressing) and the message
* itself.
*/
- if (len < 64) {
- uint8_t buf[I2C_MAX_OFFSET_LEN + len];
+
+ buf_len = I2C_MAX_OFFSET_LEN + len;
+ if (chip->flags & DM_I2C_CHIP_10BIT)
+ buf_len++;
+
+ if (buf_len <= 64) {
+ uint8_t buf[64];
i2c_setup_offset(chip, offset, buf, msg);
+ memcpy(buf + msg->len, buffer, len);
msg->len += len;
- memcpy(buf + chip->offset_len, buffer, len);
return ops->xfer(bus, msg, 1);
} else {
uint8_t *buf;
int ret;
- buf = malloc(I2C_MAX_OFFSET_LEN + len);
+ buf = malloc(buf_len);
if (!buf)
return -ENOMEM;
i2c_setup_offset(chip, offset, buf, msg);
+ memcpy(buf + msg->len, buffer, len);
msg->len += len;
- memcpy(buf + chip->offset_len, buffer, len);
ret = ops->xfer(bus, msg, 1);
free(buf);
@@ -199,6 +215,7 @@ static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
{
struct dm_i2c_ops *ops = i2c_get_ops(bus);
struct i2c_msg msg[1];
+ u8 low_address;
int ret;
if (ops->probe_chip) {
@@ -210,11 +227,18 @@ static int i2c_probe_chip(struct udevice *bus, uint chip_addr,
if (!ops->xfer)
return -ENOSYS;
- /* Probe with a zero-length message */
- msg->addr = chip_addr;
- msg->flags = chip_flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0;
- msg->len = 0;
- msg->buf = NULL;
+ if (chip_flags & DM_I2C_CHIP_10BIT) {
+ msg->addr = I2C_ADDR_TEN_HIGH(chip_addr);
+ low_address = I2C_ADDR_TEN_LOW(chip_addr);
+ msg->buf = &low_address;
+ msg->len = 1;
+ } else {
+ /* Probe with a zero-length message */
+ msg->addr = chip_addr;
+ msg->buf = NULL;
+ msg->len = 0;
+ }
+ msg->flags = 0;
return ops->xfer(bus, msg, 1);
}
diff --git a/include/i2c.h b/include/i2c.h
index 9c6a60c..e616909 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -185,6 +185,10 @@ int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len);
*/
int i2c_deblock(struct udevice *bus);
+/* return upper, lower byte of 10 bit addressing, respectively */
+#define I2C_ADDR_TEN_HIGH(a) (0x78 | (((a) >> 8) & 0x3))
+#define I2C_ADDR_TEN_LOW(a) ((a) & 0xff)
+
/*
* Not all of these flags are implemented in the U-Boot API
*/
--
1.9.1
More information about the U-Boot
mailing list