diff options
author | Robert Beckett <bob.beckett@collabora.com> | 2019-10-28 20:44:57 +0300 |
---|---|---|
committer | Heiko Schocher <hs@denx.de> | 2019-12-17 08:57:12 +0300 |
commit | 85968522b928e19a27aa79f0cb186c80b8b82e47 (patch) | |
tree | 21562077d4dc1e2c3558e76076c453fea952c87b /drivers | |
parent | 553cb06887825314e74a9bdac337467c77d1db88 (diff) | |
download | u-boot-85968522b928e19a27aa79f0cb186c80b8b82e47.tar.xz |
i2c: add support for offset overflow in to address
Some devices (2 wire eeproms for example) use some bits from the chip
address to represent the high bits of the offset instead of or as well
as using multiple bytes for the offset, effectively stealing chip
addresses on the bus.
Add a chip offset mask that can be set for any i2c chip which gets
filled with the offset overflow during offset setup.
Signed-off-by: Robert Beckett <bob.beckett@collabora.com>
Signed-off-by: Ian Ray <ian.ray@ge.com>
Reviewed-by: Heiko Schocher <hs@denx.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/i2c-uclass.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index e47abf1833..44aace3a36 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -52,16 +52,19 @@ void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs) 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; + if (chip->chip_addr_offset_mask) + msg->addr |= (offset >> (8 * offset_len)) & + chip->chip_addr_offset_mask; msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; msg->len = chip->offset_len; msg->buf = offset_buf; - if (!chip->offset_len) + if (!offset_len) return -EADDRNOTAVAIL; - assert(chip->offset_len <= I2C_MAX_OFFSET_LEN); - offset_len = chip->offset_len; + assert(offset_len <= I2C_MAX_OFFSET_LEN); + while (offset_len--) *offset_buf++ = offset >> (8 * offset_len); @@ -83,7 +86,7 @@ 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 = msg->addr; ptr->flags = msg->flags | I2C_M_RD; ptr->len = 1; ptr->buf = &buffer[i]; @@ -139,7 +142,7 @@ int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len) ptr++; if (len) { - ptr->addr = chip->chip_addr; + ptr->addr = msg->addr; ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; ptr->flags |= I2C_M_RD; ptr->len = len; @@ -323,7 +326,8 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len, struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); int ret; - if (chip->chip_addr == chip_addr) { + if (chip->chip_addr == (chip_addr & + ~chip->chip_addr_offset_mask)) { ret = device_probe(dev); debug("found, ret=%d\n", ret); if (ret) @@ -465,6 +469,22 @@ int i2c_get_chip_offset_len(struct udevice *dev) return chip->offset_len; } +int i2c_set_chip_addr_offset_mask(struct udevice *dev, uint mask) +{ + struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); + + chip->chip_addr_offset_mask = mask; + + return 0; +} + +uint i2c_get_chip_addr_offset_mask(struct udevice *dev) +{ + struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); + + return chip->chip_addr_offset_mask; +} + #ifdef CONFIG_DM_GPIO static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit) { |