On Mon, Jan 23, 2012 at 3:14 PM, Patil, Rachna <rac...@ti.com> wrote:
> commit 2faa76196af4b3e93bcb9e38ed9090cbd3b06db3
> Author: Patil, Rachna <rac...@ti.com>
> Date:   Sun Jan 22 23:44:12 2012 +0000
>
>     ARM: I2C: I2C Multi byte address support
>
>     Existing OMAP I2C driver does not support address
>     length greater than one. Hence this patch is to
>     add support for 2 byte address read/write.
>
>     Signed-off-by: Philip, Avinash <avinashphi...@ti.com>
>     Signed-off-by: Hebbar, Gururaja <gururaja.heb...@ti.com>
>     Signed-off-by: Patil, Rachna <rac...@ti.com>
>
> diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
> index a7ffd95..80932ef 100644
> --- a/drivers/i2c/omap24xx_i2c.c
> +++ b/drivers/i2c/omap24xx_i2c.c
> @@ -29,10 +29,11 @@
>
>  DECLARE_GLOBAL_DATA_PTR;
>
> -#define I2C_TIMEOUT  1000
> +#define I2C_STAT_TIMEO       (1 << 31)
> +#define I2C_TIMEOUT  10
>
> -static void wait_for_bb(void);
> -static u16 wait_for_pin(void);
> +static u32 wait_for_bb(void);
> +static u32 wait_for_status_mask(u16 mask);
>  static void flush_fifo(void);
>
>  /*
> @@ -50,7 +51,6 @@ void i2c_init(int speed, int slaveadd)
>       int psc, fsscll, fssclh;
>       int hsscll = 0, hssclh = 0;
>       u32 scll, sclh;
> -     int timeout = I2C_TIMEOUT;
>
>       /* Only handle standard, fast and high speeds */
>       if ((speed != OMAP_I2C_STANDARD) &&
> @@ -112,24 +112,14 @@ void i2c_init(int speed, int slaveadd)
>               sclh = (unsigned int)fssclh;
>       }
>
> +     if (gd->flags & GD_FLG_RELOC)
> +             bus_initialized[current_bus] = 1;
> +
>       if (readw(&i2c_base->con) & I2C_CON_EN) {
>               writew(0, &i2c_base->con);
>               udelay(50000);
>       }
>
> -     writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */
> -     udelay(1000);
> -
> -     writew(I2C_CON_EN, &i2c_base->con);
> -     while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) {
> -             if (timeout <= 0) {
> -                     puts("ERROR: Timeout in soft-reset\n");
> -                     return;
> -             }
> -             udelay(1000);
> -     }
> -
> -     writew(0, &i2c_base->con);

This change in not related to multi byte address
and why is this removed

>       writew(psc, &i2c_base->psc);
>       writew(scll, &i2c_base->scll);
>       writew(sclh, &i2c_base->sclh);
> @@ -145,81 +135,6 @@ void i2c_init(int speed, int slaveadd)
>       flush_fifo();
>       writew(0xFFFF, &i2c_base->stat);
>       writew(0, &i2c_base->cnt);
> -
> -     if (gd->flags & GD_FLG_RELOC)
> -             bus_initialized[current_bus] = 1;

why is this section of code moved above ?

> -}
> -
> -static int i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value)
> -{
> -     int i2c_error = 0;
> -     u16 status;
> -
> -     /* wait until bus not busy */
> -     wait_for_bb();
> -
> -     /* one byte only */
> -     writew(1, &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) {
> -                     /* Important: have to use byte access */
> -                     writeb(regoffset, &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)

Note you have removed CONFIG_OMAP44XX here
and not added in any other place in this patch
was this patch developed on latest baseline or something went wrong
while rebasing ?

> -                     *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)
> @@ -246,32 +161,42 @@ static void flush_fifo(void)
>
>  int i2c_probe(uchar chip)
>  {
> -     u16 status;
> +     u32 status;
>       int res = 1; /* default = fail */
>
>       if (chip == readw(&i2c_base->oa))
>               return res;
>
>       /* wait until bus not busy */
> -     wait_for_bb();
> +     status = wait_for_bb();
> +     /* exit on BUS busy */
> +     if (status & I2C_STAT_TIMEO)
> +             return res;
>
>       /* try to write 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);
> -
> -     status = wait_for_pin();
> -
> -     /* check for ACK (!NAK) */
> -     if (!(status & I2C_STAT_NACK))
> -             res = 0;
> -
> -     /* abort transfer (force idle state) */
> -     writew(0, &i2c_base->con);
> -
> +     writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT
> +                     | I2C_CON_STP, &i2c_base->con);
> +     /* enough delay for the NACK bit set */
> +     udelay(9000);
> +
> +     if (!(readw(&i2c_base->stat) & I2C_STAT_NACK)) {
> +             res = 0;      /* success case */

> +             flush_fifo();
> +             writew(0xFFFF, &i2c_base->stat);

flush_fifo and clearing stat is anyway at the end of function
why is this repeated

> +     } else {
> +             /* failure, clear sources*/
> +             writew(0xFFFF, &i2c_base->stat);
> +             /* finish up xfer */
> +             writew(readw(&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
> +             status = wait_for_bb();
> +             /* exit on BUS busy */
> +             if (status & I2C_STAT_TIMEO)
> +                     return res;
> +     }
>       flush_fifo();
>       /* don't allow any more data in... we don't want it. */
>       writew(0, &i2c_base->cnt);
> @@ -281,111 +206,309 @@ int i2c_probe(uchar chip)
>
>  int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
>  {
> -     int i;
> +     int i2c_error = 0, i;
> +     u32 status;
> +
> +     if ((alen > 2) || (alen < 0))
> +             return 1;
>
> -     if (alen > 1) {
> -             printf("I2C read: addr len %d not supported\n", alen);
> +     if (alen < 2) {
> +             if (addr + len > 256)
> +                     return 1;
> +     } else if (addr + len > 0xFFFF) {
>               return 1;
>       }
>
> -     if (addr + len > 256) {
> -             puts("I2C read: address out of range\n");
> +     /* wait until bus not busy */
> +     status = wait_for_bb();
> +
> +     /* exit on BUS busy */
> +     if (status & I2C_STAT_TIMEO)
>               return 1;
> +
> +     writew((alen & 0xFF), &i2c_base->cnt);
> +     /* set slave address */
> +     writew(chip, &i2c_base->sa);
> +     /* Clear the Tx & Rx FIFOs */
> +     writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
> +             I2C_TXFIFO_CLEAR), &i2c_base->buf);
> +     /* no stop bit needed here */
> +     writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
> +             I2C_CON_STT, &i2c_base->con);
> +
> +     /* wait for Transmit ready condition */
> +     status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
> +
> +     if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
> +             i2c_error = 1;
> +
> +     if (!i2c_error) {
> +             if (status & I2C_STAT_XRDY) {
> +                     switch (alen) {
> +                     case 2:
> +                             /* Send address MSByte */
> +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
> +                             writew(((addr >> 8) & 0xFF), &i2c_base->data);

writew or writeb??

> +
> +                             /* Clearing XRDY event */
> +                             writew((status & I2C_STAT_XRDY),
> +                                             &i2c_base->stat);
> +                             /* wait for Transmit ready condition */
> +                             status = wait_for_status_mask(I2C_STAT_XRDY |
> +                                             I2C_STAT_NACK);
> +
> +                             if (status & (I2C_STAT_NACK |
> +                                             I2C_STAT_TIMEO)) {
> +                                     i2c_error = 1;
> +                                     break;
> +                             }
> +#endif
> +                     case 1:
> +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
> +                             /* Send address LSByte */
> +                             writew((addr & 0xFF), &i2c_base->data);

writew or writeb??

> +#else
> +                             /* Send address Short word */
> +                             writew((addr & 0xFFFF), &i2c_base->data);
> +#endif
> +                             /* Clearing XRDY event */
> +                             writew((status & I2C_STAT_XRDY),
> +                                     &i2c_base->stat);
> +                             /*wait for Transmit ready condition */
> +                             status = wait_for_status_mask(I2C_STAT_ARDY |
> +                                             I2C_STAT_NACK);
> +
> +                             if (status & (I2C_STAT_NACK |
> +                                     I2C_STAT_TIMEO)) {
> +                                     i2c_error = 1;
> +                                     break;
> +                             }
> +                     }
> +             } else
> +                     i2c_error = 1;
>       }
>
> -     for (i = 0; i < len; i++) {
> -             if (i2c_read_byte(chip, addr + i, &buffer[i])) {
> -                     puts("I2C read: I/O error\n");
> -                     i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
> -                     return 1;
> +     /* Wait for ARDY to set */
> +     status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK
> +                     | I2C_STAT_AL);
> +
> +     if (!i2c_error) {
> +             /* set slave address */
> +             writew(chip, &i2c_base->sa);
> +             writew((len & 0xFF), &i2c_base->cnt);
> +             /* Clear the Tx & Rx FIFOs */
> +             writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
> +                     I2C_TXFIFO_CLEAR), &i2c_base->buf);
> +             /* need stop bit here */
> +             writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP,
> +                     &i2c_base->con);
> +
> +             for (i = 0; i < len; i++) {
> +                     /* wait for Receive condition */
> +                     status = wait_for_status_mask(I2C_STAT_RRDY |
> +                             I2C_STAT_NACK);
> +                     if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) {
> +                             i2c_error = 1;
> +                             break;
> +                     }
> +
> +                     if (status & I2C_STAT_RRDY) {
> +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
> +                             buffer[i] = readb(&i2c_base->data);
> +#else
> +                             *((u16 *)&buffer[i]) =
> +                                     readw(&i2c_base->data) & 0xFFFF;
> +                             i++;
> +#endif
> +                             writew((status & I2C_STAT_RRDY),
> +                                     &i2c_base->stat);
> +                             udelay(1000);
> +                     } else {
> +                             i2c_error = 1;
> +                     }
>               }
>       }
>
> +     /* Wait for ARDY to set */
> +     status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK
> +                     | I2C_STAT_AL);

why do you have to wait for ARDY when transaction is done?

> +
> +     if (i2c_error) {
> +             writew(0, &i2c_base->con);
> +             return 1;
> +     }
> +
> +     writew(I2C_CON_EN, &i2c_base->con);
> +
> +     while (readw(&i2c_base->stat)
> +             || (readw(&i2c_base->con) & I2C_CON_MST)) {
> +             udelay(10000);
> +             writew(0xFFFF, &i2c_base->stat);
> +     }
> +
> +     writew(I2C_CON_EN, &i2c_base->con);
> +     flush_fifo();
> +     writew(0xFFFF, &i2c_base->stat);
> +     writew(0, &i2c_base->cnt);
> +
>       return 0;
>  }
>
>  int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
>  {
> -     int i;
> -     u16 status;
> -     int i2c_error = 0;
>
> -     if (alen > 1) {
> -             printf("I2C write: addr len %d not supported\n", alen);
> +     int i, i2c_error = 0;
> +     u32 status;
> +     u16 writelen;
> +
> +     if (alen > 2)
>               return 1;
> -     }
>
> -     if (addr + len > 256) {
> -             printf("I2C write: address 0x%x + 0x%x out of range\n",
> -                             addr, len);
> +     if (alen < 2) {
> +             if (addr + len > 256)
> +                     return 1;
> +     } else if (addr + len > 0xFFFF) {
>               return 1;
>       }
>
>       /* wait until bus not busy */
> -     wait_for_bb();
> +     status = wait_for_bb();
> +
> +     /* exiting on BUS busy */
> +     if (status & I2C_STAT_TIMEO)
> +             return 1;
>
> -     /* start address phase - will write regoffset + len bytes data */
> -     /* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
> -     writew(alen + len, &i2c_base->cnt);
> +     writelen = (len & 0xFFFF) + alen;
> +
> +     /* two bytes */
> +     writew((writelen & 0xFFFF), &i2c_base->cnt);

where else is this variable writelen used ?

> +     /* Clear the Tx & Rx FIFOs */
> +     writew((readw(&i2c_base->buf) | I2C_RXFIFO_CLEAR |
> +                     I2C_TXFIFO_CLEAR), &i2c_base->buf);
>       /* 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);
>
> -     /* Send address byte */
> -     status = wait_for_pin();
> +     /* wait for Transmit ready condition */
> +     status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
>
> -     if (status == 0 || status & I2C_STAT_NACK) {
> +     if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
>               i2c_error = 1;
> -             printf("error waiting for i2c address ACK (status=0x%x)\n",
> -                   status);
> -             goto write_exit;
> -     }
>
> -     if (status & I2C_STAT_XRDY) {
> -             writeb(addr & 0xFF, &i2c_base->data);
> -             writew(I2C_STAT_XRDY, &i2c_base->stat);
> -     } else {
> -             i2c_error = 1;
> -             printf("i2c bus not ready for transmit (status=0x%x)\n",
> -                   status);
> -             goto write_exit;
> -     }
> +     if (!i2c_error) {
> +             if (status & I2C_STAT_XRDY) {
> +                     switch (alen) {
> +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
> +                     case 2:

what is the logical reason behind keeping case statement under
compilation flag ?

> +                             /* send out MSB byte */
> +                             writeb(((addr >> 8) & 0xFF), &i2c_base->data);
> +#else
> +                             writeb((addr  & 0xFFFF), &i2c_base->data);

bit field is masked for 16 bits but byte write is used !!

> +                             break;
> +#endif
> +                             /* Clearing XRDY event */
> +                             writew((status & I2C_STAT_XRDY),
> +                                     &i2c_base->stat);
> +                             /*waiting for Transmit ready * condition */
> +                             status = wait_for_status_mask(I2C_STAT_XRDY |
> +                                             I2C_STAT_NACK);
> +
> +                             if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO)) {
> +                                     i2c_error = 1;
> +                                     break;
> +                             }

This should be in #if part for better readablity

> +                     case 1:
> +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
> +                             /* send out MSB byte */
> +                             writeb((addr  & 0xFF), &i2c_base->data);
> +#else
> +                             writew(((buffer[0] << 8) | (addr & 0xFF)),
> +                                     &i2c_base->data);

can you explain the logic behind using buffer[0]

> +#endif
> +                     }
>
> -     /* address phase is over, now write data */
> -     for (i = 0; i < len; i++) {
> -             status = wait_for_pin();
> +                     /* Clearing XRDY event */
> +                     writew((status & I2C_STAT_XRDY), &i2c_base->stat);
> +             }
> +
> +             /* waiting for Transmit ready condition */
> +             status = wait_for_status_mask(I2C_STAT_XRDY | I2C_STAT_NACK);
>
> -             if (status == 0 || status & I2C_STAT_NACK) {
> +             if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
>                       i2c_error = 1;
> -                     printf("i2c error waiting for data ACK (status=0x%x)\n",
> -                                     status);
> -                     goto write_exit;
> +
> +             if (!i2c_error) {
> +                     for (i = ((alen > 1) ? 0 : 1); i < len; i++) {

this is again not correct
Did you test this patch for alen = 1 ?

> +                             if (status & I2C_STAT_XRDY) {
> +#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
> +                                     writeb((buffer[i] & 0xFF),
> +                                             &i2c_base->data);
> +#else
> +                                     writew((((buffer[i] << 8) |
> +                                     buffer[i + 1]) & 0xFFFF),
> +                                             &i2c_base->data);
> +                                     i++;
> +#endif
> +                             } else
> +                                     i2c_error = 1;

> +                                     /* Clearing XRDY event */
> +                                     writew((status & I2C_STAT_XRDY),
> +                                             &i2c_base->stat);

wrong indent

> +                                     /* waiting for XRDY condition */
> +                                     status = wait_for_status_mask(
> +                                             I2C_STAT_XRDY |
> +                                             I2C_STAT_ARDY |
> +                                             I2C_STAT_NACK);
> +                                     if (status & (I2C_STAT_NACK |
> +                                             I2C_STAT_TIMEO)) {
> +                                             i2c_error = 1;
> +                                             break;
> +                                     }
> +                                     if (status & I2C_STAT_ARDY)
> +                                             break;
> +                     }
>               }
> +     }
>
> -             if (status & I2C_STAT_XRDY) {
> -                     writeb(buffer[i], &i2c_base->data);
> -                     writew(I2C_STAT_XRDY, &i2c_base->stat);
> -             } else {
> -                     i2c_error = 1;
> -                     printf("i2c bus not ready for Tx (i=%d)\n", i);
> -                     goto write_exit;
> +     status = wait_for_status_mask(I2C_STAT_ARDY | I2C_STAT_NACK |
> +                             I2C_STAT_AL);

why do have to wait for ARDY here?

> +
> +     if (status & (I2C_STAT_NACK | I2C_STAT_TIMEO))
> +             i2c_error = 1;
> +
> +     if (i2c_error) {
> +             writew(0, &i2c_base->con);
> +             return 1;
> +     }
> +
> +     if (!i2c_error) {
> +             int eout = 200;
> +
> +             writew(I2C_CON_EN, &i2c_base->con);
> +             while ((status = readw(&i2c_base->stat)) ||
> +                             (readw(&i2c_base->con) & I2C_CON_MST)) {

is this a workaround or errata ? if yes can you please add some comment?
why should MST bit get set after writing I2C_CON_EN ??

> +                     udelay(1000);
> +                     /* have to read to clear intrrupt */

wrong comment and typo
This patch series is not really tested for other platform
like (CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
and the patch is buggy for OMAP4430 panda

<snip>
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to