diff options
author | Gabe Black <gabeblack@google.com> | 2011-06-10 14:52:27 -0700 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2011-08-29 10:39:28 -0700 |
commit | 6871b417c03452377b6c484a0be363484d7b835c (patch) | |
tree | ad76f3c3a4da16649849dc9354b28977754ff85f /drivers | |
parent | 6ddb4c1015086c21059bbcc00fcca01c21823e9a (diff) |
Add 16 bit register address support to the tegra2 i2c driver.
This change makes the tegra2 i2c driver's i2c_read and i2c_write functions
actually use the alen parameter instead of assuming a value of 1. This code
assumes the code handling the address is compiled little endian and that
multibyte register addresses should be transmitted as big endian.
BUG=chrome-os-partner:3580
TEST=Used the i2c u-boot command to read and write several registers on a chip
that uses 16 bit addresses. Read and wrote several registers on several devices
that use 8 bit addresses.
Change-Id: I0c2291a9d8f023822a64393b82c596bb2b2e2ff4
Reviewed-on: http://gerrit.chromium.org/gerrit/2592
Reviewed-by: Gabe Black <gabeblack@chromium.org>
Tested-by: Gabe Black <gabeblack@chromium.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/tegra2_i2c.c | 76 |
1 files changed, 48 insertions, 28 deletions
diff --git a/drivers/i2c/tegra2_i2c.c b/drivers/i2c/tegra2_i2c.c index 82c8d9aae3c..6f82131eb02 100644 --- a/drivers/i2c/tegra2_i2c.c +++ b/drivers/i2c/tegra2_i2c.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. * Copyright (c) 2010-2011 NVIDIA Corporation * NVIDIA Corporation <www.nvidia.com> * @@ -473,29 +474,47 @@ int i2c_probe(uchar chip) return 0; } +static int i2c_addr_ok(const uint addr, const int alen) +{ + if (alen < 0 || alen > sizeof(addr)) + return 0; + if (alen != sizeof(addr)) { + uint max_addr = (1 << (8 * alen)) - 1; + if (addr > max_addr) + return 0; + } + return 1; +} + /* Read bytes */ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - int rc; - uchar *ptr = buffer; - - debug("i2c_read: chip=0x%x, addr=0x%x, len=0x%x\n", chip, addr, len); + uint offset; + int i; - while (len) { - rc = i2c_write_data(chip, (uchar *)&addr, 1); - if (rc) { - debug("i2c_read: error sending (0x%x)\n", addr); - return 1; + debug("i2c_read: chip=0x%x, addr=0x%x, len=0x%x\n", + chip, addr, len); + if (!i2c_addr_ok(addr, alen)) { + debug("i2c_read: Bad address %x.%d.\n", addr, alen); + return 1; + } + for (offset = 0; offset < len; offset++) { + if (alen) { + uchar data[alen]; + for (i = 0; i < alen; i++) { + data[alen - i - 1] = + (addr + offset) >> (8 * i); + } + if (i2c_write_data(chip, data, alen)) { + debug("i2c_read: error sending (0x%x)\n", + addr); + return 1; + } } - - rc = i2c_read_data(chip, ptr, 1); - if (rc) { + if (i2c_read_data(chip, buffer + offset, 1)) { debug("i2c_read: error reading (0x%x)\n", addr); return 1; } - ++addr; - ++ptr; - --len; } return 0; @@ -504,23 +523,24 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) /* Write bytes */ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { - int rc; - uchar local_buffer[4]; - uchar *ptr = buffer; - - debug("i2c_write: chip=0x%x, addr=0x%x, len=0x%x\n", chip, addr, len); + uint offset; + int i; - while (len) { - local_buffer[0] = addr & 0xFF; - local_buffer[1] = *ptr; - rc = i2c_write_data(chip, local_buffer, 2); - if (rc) { + debug("i2c_write: chip=0x%x, addr=0x%x, len=0x%x\n", + chip, addr, len); + if (!i2c_addr_ok(addr, alen)) { + debug("i2c_write: Bad address %x.%d.\n", addr, alen); + return 1; + } + for (offset = 0; offset < len; offset++) { + uchar data[alen + 1]; + for (i = 0; i < alen; i++) + data[alen - i - 1] = (addr + offset) >> (8 * i); + data[alen] = buffer[offset]; + if (i2c_write_data(chip, data, alen + 1)) { debug("i2c_write: error sending (0x%x)\n", addr); return 1; } - ++addr; - ++ptr; - --len; } return 0; |