diff options
| author | Evan Wilson <evan@oliodevices.com> | 2014-04-07 14:30:35 -0700 |
|---|---|---|
| committer | Evan Wilson <evan@oliodevices.com> | 2014-04-08 14:12:07 -0700 |
| commit | 28d07728d0de3a41e96bdcc7a6b2fd2b0336d005 (patch) | |
| tree | feb3745261b9d6a0f175a0f8352dac10faffcfe0 | |
| parent | e8ef8bc0e561ced14dd10da50bd9854f16c7df41 (diff) | |
| download | olio-uboot-2014.01-28d07728d0de3a41e96bdcc7a6b2fd2b0336d005.tar.xz olio-uboot-2014.01-28d07728d0de3a41e96bdcc7a6b2fd2b0336d005.zip | |
Revert "ARM: OMAP: I2C: New read, write and probe functions"
This reverts commit 960187ffa125b3938fec4b827bd9e8c04a204af8.
| -rw-r--r-- | drivers/i2c/omap24xx_i2c.c | 482 |
1 files changed, 187 insertions, 295 deletions
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index ef38d7172..54e9b1586 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -18,20 +18,6 @@ * * Adapted for OMAP2420 I2C, r-woodruff2@ti.com * - * Copyright (c) 2013 Lubomir Popov <lpopov@mm-sol.com>, MM Solutions - * New i2c_read, i2c_write and i2c_probe functions, tested on OMAP4 - * (4430/60/70), OMAP5 (5430) and AM335X (3359); should work on older - * OMAPs and derivatives as well. The only anticipated exception would - * be the OMAP2420, which shall require driver modification. - * - Rewritten i2c_read to operate correctly with all types of chips - * (old function could not read consistent data from some I2C slaves). - * - Optimized i2c_write. - * - New i2c_probe, performs write access vs read. The old probe could - * hang the system under certain conditions (e.g. unconfigured pads). - * - The read/write/probe functions try to identify unconfigured bus. - * - Status functions now read irqstatus_raw as per TRM guidelines - * (except for OMAP243X and OMAP34XX). - * - Driver now supports up to I2C5 (OMAP5). */ #include <common.h> @@ -45,11 +31,8 @@ DECLARE_GLOBAL_DATA_PTR; #define I2C_TIMEOUT 1000 -/* Absolutely safe for status update at 100 kHz I2C: */ -#define I2C_WAIT 200 - static int wait_for_bb(void); -static u16 wait_for_event(void); +static u16 wait_for_pin(void); static void flush_fifo(void); /* @@ -154,14 +137,10 @@ void i2c_init(int speed, int slaveadd) /* own address */ writew(slaveadd, &i2c_base->oa); writew(I2C_CON_EN, &i2c_base->con); -#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) - /* - * Have to enable interrupts for OMAP2/3, these IPs don't have - * an 'irqstatus_raw' register and we shall have to poll 'stat' - */ + + /* have to enable intrrupts or OMAP i2c module doesn't work */ writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | - I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); -#endif + I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); udelay(1000); flush_fifo(); writew(0xFFFF, &i2c_base->stat); @@ -171,6 +150,88 @@ void i2c_init(int speed, int slaveadd) bus_initialized[current_bus] = 1; } +static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value) +{ + int i2c_error = 0; + u16 status; + int i = 2 - alen; + u8 tmpbuf[2] = {(regoffset) >> 8, regoffset & 0xff}; + u16 w; + + /* wait until bus not busy */ + if (wait_for_bb()) + return 1; + + /* one byte only */ + writew(alen, &i2c_base->cnt); + /* set slave address */ + writew(devaddr, &i2c_base->sa); + /* no stop bit needed here */ + writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | + I2C_CON_TRX, &i2c_base->con); + + /* send register offset */ + while (1) { + status = wait_for_pin(); + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + goto read_exit; + } + if (status & I2C_STAT_XRDY) { + w = tmpbuf[i++]; +#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX)) + w |= tmpbuf[i++] << 8; +#endif + writew(w, &i2c_base->data); + writew(I2C_STAT_XRDY, &i2c_base->stat); + } + if (status & I2C_STAT_ARDY) { + writew(I2C_STAT_ARDY, &i2c_base->stat); + break; + } + } + + /* set slave address */ + writew(devaddr, &i2c_base->sa); + /* read one byte from slave */ + writew(1, &i2c_base->cnt); + /* need stop bit here */ + writew(I2C_CON_EN | I2C_CON_MST | + I2C_CON_STT | I2C_CON_STP, + &i2c_base->con); + + /* receive data */ + while (1) { + status = wait_for_pin(); + if (status == 0 || status & I2C_STAT_NACK) { + i2c_error = 1; + goto read_exit; + } + if (status & I2C_STAT_RRDY) { +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX) + *value = readb(&i2c_base->data); +#else + *value = readw(&i2c_base->data); +#endif + writew(I2C_STAT_RRDY, &i2c_base->stat); + } + if (status & I2C_STAT_ARDY) { + writew(I2C_STAT_ARDY, &i2c_base->stat); + break; + } + } + +read_exit: + flush_fifo(); + writew(0xFFFF, &i2c_base->stat); + writew(0, &i2c_base->cnt); + return i2c_error; +} + static void flush_fifo(void) { u16 stat; @@ -180,7 +241,13 @@ static void flush_fifo(void) while (1) { stat = readw(&i2c_base->stat); if (stat == I2C_STAT_RRDY) { +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX) readb(&i2c_base->data); +#else + readw(&i2c_base->data); +#endif writew(I2C_STAT_RRDY, &i2c_base->stat); udelay(1000); } else @@ -188,10 +255,6 @@ static void flush_fifo(void) } } -/* - * i2c_probe: Use write access. Allows to identify addresses that are - * write-only (like the config register of dual-port EEPROMs) - */ int i2c_probe(uchar chip) { u16 status; @@ -200,81 +263,61 @@ int i2c_probe(uchar chip) if (chip == readw(&i2c_base->oa)) return res; - /* Wait until bus is free */ + /* wait until bus not busy */ if (wait_for_bb()) return res; - /* No data transfer, slave addr only */ - writew(0, &i2c_base->cnt); - /* Set slave address */ + /* try to read one byte */ + writew(1, &i2c_base->cnt); + /* set slave address */ writew(chip, &i2c_base->sa); - /* Stop bit needed here */ - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | - I2C_CON_STP, &i2c_base->con); + /* stop bit needed here */ + writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con); - status = wait_for_event(); + while (1) { + status = wait_for_pin(); + if (status == 0 || status & I2C_STAT_AL) { + res = 1; + goto probe_exit; + } + if (status & I2C_STAT_NACK) { + res = 1; + writew(0xff, &i2c_base->stat); + writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con); - if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) { - /* - * With current high-level command implementation, notifying - * the user shall flood the console with 127 messages. If - * silent exit is desired upon unconfigured bus, remove the - * following 'if' section: - */ - if (status == I2C_STAT_XRDY) - printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); + if (wait_for_bb()) + res = 1; - goto pr_exit; + break; + } + if (status & I2C_STAT_ARDY) { + writew(I2C_STAT_ARDY, &i2c_base->stat); + break; + } + if (status & I2C_STAT_RRDY) { + res = 0; +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX) + readb(&i2c_base->data); +#else + readw(&i2c_base->data); +#endif + writew(I2C_STAT_RRDY, &i2c_base->stat); + } } - /* Check for ACK (!NAK) */ - if (!(status & I2C_STAT_NACK)) { - res = 0; /* Device found */ - udelay(I2C_WAIT); /* Required by AM335X in SPL */ - /* Abort transfer (force idle state) */ - writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */ - udelay(1000); - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX | - I2C_CON_STP, &i2c_base->con); /* STP */ - } -pr_exit: +probe_exit: flush_fifo(); - writew(0xFFFF, &i2c_base->stat); + /* don't allow any more data in... we don't want it. */ writew(0, &i2c_base->cnt); + writew(0xFFFF, &i2c_base->stat); return res; } -/* - * i2c_read: Function now uses a single I2C read transaction with bulk transfer - * of the requested number of bytes (note that the 'i2c md' command - * limits this to 16 bytes anyway). If CONFIG_I2C_REPEATED_START is - * defined in the board config header, this transaction shall be with - * Repeated Start (Sr) between the address and data phases; otherwise - * Stop-Start (P-S) shall be used (some I2C chips do require a P-S). - * The address (reg offset) may be 0, 1 or 2 bytes long. - * Function now reads correctly from chips that return more than one - * byte of data per addressed register (like TI temperature sensors), - * or that do not need a register address at all (such as some clock - * distributors). - */ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - int i2c_error = 0; - u16 status; - - if (alen < 0) { - puts("I2C read: addr len < 0\n"); - return 1; - } - if (len < 0) { - puts("I2C read: data len < 0\n"); - return 1; - } - if (buffer == NULL) { - puts("I2C read: NULL pointer passed\n"); - return 1; - } + int i; if (alen > 2) { printf("I2C read: addr len %d not supported\n", alen); @@ -286,122 +329,24 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) return 1; } - /* Wait until bus not busy */ - if (wait_for_bb()) - return 1; - - /* Zero, one or two bytes reg address (offset) */ - writew(alen, &i2c_base->cnt); - /* Set slave address */ - writew(chip, &i2c_base->sa); - - if (alen) { - /* Must write reg offset first */ -#ifdef CONFIG_I2C_REPEATED_START - /* No stop bit, use Repeated Start (Sr) */ - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | - I2C_CON_TRX, &i2c_base->con); -#else - /* Stop - Start (P-S) */ - writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP | - I2C_CON_TRX, &i2c_base->con); -#endif - /* Send register offset */ - while (1) { - status = wait_for_event(); - /* Try to identify bus that is not padconf'd for I2C */ - if (status == I2C_STAT_XRDY) { - i2c_error = 2; - printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); - goto rd_exit; - } - if (status == 0 || status & I2C_STAT_NACK) { - i2c_error = 1; - printf("i2c_read: error waiting for addr ACK (status=0x%x)\n", - status); - goto rd_exit; - } - if (alen) { - if (status & I2C_STAT_XRDY) { - alen--; - /* Do we have to use byte access? */ - writeb((addr >> (8 * alen)) & 0xff, - &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); - } - } - if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); - break; - } - } - } - /* Set slave address */ - writew(chip, &i2c_base->sa); - /* Read len bytes from slave */ - writew(len, &i2c_base->cnt); - /* Need stop bit here */ - writew(I2C_CON_EN | I2C_CON_MST | - I2C_CON_STT | I2C_CON_STP, - &i2c_base->con); - - /* Receive data */ - while (1) { - status = wait_for_event(); - /* - * Try to identify bus that is not padconf'd for I2C. This - * state could be left over from previous transactions if - * the address phase is skipped due to alen=0. - */ - if (status == I2C_STAT_XRDY) { - i2c_error = 2; - printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); - goto rd_exit; - } - if (status == 0 || status & I2C_STAT_NACK) { - i2c_error = 1; - goto rd_exit; - } - if (status & I2C_STAT_RRDY) { - *buffer++ = readb(&i2c_base->data); - writew(I2C_STAT_RRDY, &i2c_base->stat); - } - if (status & I2C_STAT_ARDY) { - writew(I2C_STAT_ARDY, &i2c_base->stat); - break; + for (i = 0; i < len; i++) { + if (i2c_read_byte(chip, addr + i, alen, &buffer[i])) { + puts("I2C read: I/O error\n"); + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + return 1; } } -rd_exit: - flush_fifo(); - writew(0xFFFF, &i2c_base->stat); - writew(0, &i2c_base->cnt); - return i2c_error; + return 0; } -/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { int i; u16 status; int i2c_error = 0; - - if (alen < 0) { - puts("I2C write: addr len < 0\n"); - return 1; - } - - if (len < 0) { - puts("I2C write: data len < 0\n"); - return 1; - } - - if (buffer == NULL) { - puts("I2C write: NULL pointer passed\n"); - return 1; - } + u16 w; + u8 tmpbuf[2] = {addr >> 8, addr & 0xff}; if (alen > 2) { printf("I2C write: addr len %d not supported\n", alen); @@ -410,137 +355,92 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) if (addr + len > (1 << 16)) { printf("I2C write: address 0x%x + 0x%x out of range\n", - addr, len); + addr, len); return 1; } - /* Wait until bus not busy */ + /* wait until bus not busy */ if (wait_for_bb()) return 1; - /* Start address phase - will write regoffset + len bytes data */ + /* start address phase - will write regoffset + len bytes data */ + /* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */ writew(alen + len, &i2c_base->cnt); - /* Set slave address */ + /* set slave address */ writew(chip, &i2c_base->sa); - /* Stop bit needed here */ + /* stop bit needed here */ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | - I2C_CON_STP, &i2c_base->con); + I2C_CON_STP, &i2c_base->con); + + /* Send address and data */ + for (i = -alen; i < len; i++) { + status = wait_for_pin(); - while (alen) { - /* Must write reg offset (one or two bytes) */ - status = wait_for_event(); - /* Try to identify bus that is not padconf'd for I2C */ - if (status == I2C_STAT_XRDY) { - i2c_error = 2; - printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n", - current_bus, status); - goto wr_exit; - } - if (status == 0 || status & I2C_STAT_NACK) { - i2c_error = 1; - printf("i2c_write: error waiting for addr ACK (status=0x%x)\n", - status); - goto wr_exit; - } - if (status & I2C_STAT_XRDY) { - alen--; - writeb((addr >> (8 * alen)) & 0xff, &i2c_base->data); - writew(I2C_STAT_XRDY, &i2c_base->stat); - } else { - i2c_error = 1; - printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n", - status); - goto wr_exit; - } - } - /* Address phase is over, now write data */ - for (i = 0; i < len; i++) { - status = wait_for_event(); if (status == 0 || status & I2C_STAT_NACK) { i2c_error = 1; - printf("i2c_write: error waiting for data ACK (status=0x%x)\n", - status); - goto wr_exit; + printf("i2c error waiting for data ACK (status=0x%x)\n", + status); + goto write_exit; } + if (status & I2C_STAT_XRDY) { - writeb(buffer[i], &i2c_base->data); + w = (i < 0) ? tmpbuf[2+i] : buffer[i]; +#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX)) + w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8; +#endif + writew(w, &i2c_base->data); writew(I2C_STAT_XRDY, &i2c_base->stat); } else { i2c_error = 1; - printf("i2c_write: bus not ready for data Tx (i=%d)\n", - i); - goto wr_exit; + printf("i2c bus not ready for Tx (i=%d)\n", i); + goto write_exit; } } -wr_exit: +write_exit: flush_fifo(); writew(0xFFFF, &i2c_base->stat); - writew(0, &i2c_base->cnt); return i2c_error; } -/* - * Wait for the bus to be free by checking the Bus Busy (BB) - * bit to become clear - */ static int wait_for_bb(void) { int timeout = I2C_TIMEOUT; u16 stat; writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/ -#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) { -#else - /* Read RAW status */ - while ((stat = readw(&i2c_base->irqstatus_raw) & - I2C_STAT_BB) && timeout--) { -#endif writew(stat, &i2c_base->stat); - udelay(I2C_WAIT); + udelay(1000); } if (timeout <= 0) { - printf("Timed out in wait_for_bb: status=%04x\n", - stat); + printf("timed out in wait_for_bb: I2C_STAT=%x\n", + readw(&i2c_base->stat)); return 1; } writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/ return 0; } -/* - * Wait for the I2C controller to complete current action - * and update status - */ -static u16 wait_for_event(void) +static u16 wait_for_pin(void) { u16 status; int timeout = I2C_TIMEOUT; do { - udelay(I2C_WAIT); -#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) + udelay(1000); status = readw(&i2c_base->stat); -#else - /* Read RAW status */ - status = readw(&i2c_base->irqstatus_raw); -#endif } while (!(status & (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | I2C_STAT_AL)) && timeout--); if (timeout <= 0) { - printf("Timed out in wait_for_event: status=%04x\n", - status); - /* - * If status is still 0 here, probably the bus pads have - * not been configured for I2C, and/or pull-ups are missing. - */ - printf("Check if pads/pull-ups of bus %d are properly configured\n", - current_bus); + printf("timed out in wait_for_pin: I2C_STAT=%x\n", + readw(&i2c_base->stat)); writew(0xFFFF, &i2c_base->stat); status = 0; } @@ -550,36 +450,28 @@ static u16 wait_for_event(void) int i2c_set_bus_num(unsigned int bus) { - if (bus >= I2C_BUS_MAX) { - printf("Bad bus: %x\n", bus); + if ((bus < 0) || (bus >= I2C_BUS_MAX)) { + printf("Bad bus: %d\n", bus); return -1; } - switch (bus) { - default: - bus = 0; /* Fall through */ - case 0: - i2c_base = (struct i2c *)I2C_BASE1; - break; - case 1: - i2c_base = (struct i2c *)I2C_BASE2; - break; -#if (I2C_BUS_MAX > 2) - case 2: - i2c_base = (struct i2c *)I2C_BASE3; - break; -#if (I2C_BUS_MAX > 3) - case 3: +#if I2C_BUS_MAX == 4 + if (bus == 3) i2c_base = (struct i2c *)I2C_BASE4; - break; -#if (I2C_BUS_MAX > 4) - case 4: - i2c_base = (struct i2c *)I2C_BASE5; - break; -#endif + else + if (bus == 2) + i2c_base = (struct i2c *)I2C_BASE3; + else #endif +#if I2C_BUS_MAX == 3 + if (bus == 2) + i2c_base = (struct i2c *)I2C_BASE3; + else #endif - } + if (bus == 1) + i2c_base = (struct i2c *)I2C_BASE2; + else + i2c_base = (struct i2c *)I2C_BASE1; current_bus = bus; |