[U-Boot] [PATCH] i2c: add NACK logic in write

Vadim Bendebury vbendeb at chromium.org
Tue Apr 23 04:44:09 CEST 2013


On Mon, Mar 25, 2013 at 4:17 AM, Akshay Saraswat <akshay.s at samsung.com> wrote:
>
> From: Naveen Krishna Chatradhi <ch.naveen at samsung.com>
>
> Adding NACK logic for i2c write.
> Verified by reading and writing to device with address 9 on i2c-0.
>
> Signed-off-by: Naveen Krishna Chatradhi <ch.naveen at samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s at samsung.com>
> ---
>  drivers/i2c/s3c24x0_i2c.c | 111
> +++++++++++++++++++++++-----------------------
>  1 file changed, 56 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
> index 769a2ba..d2b4eb0 100644
> --- a/drivers/i2c/s3c24x0_i2c.c
> +++ b/drivers/i2c/s3c24x0_i2c.c
> @@ -201,6 +201,35 @@ unsigned int i2c_get_bus_num(void)
>  }
>  #endif
>
> +/*
> + * Verify the whether I2C ACK was received or not
> + *
> + * @param i2c  pointer to I2C register base
> + * @param buf  array of data
> + * @param len  length of data
> + * return      I2C_OK when transmission done
> + *             I2C_NACK otherwise
> + */
> +static int i2c_send_verify(struct s3c24x0_i2c *i2c, unsigned char buf[],
> +                                                       unsigned char len)
> +{
> +       int i, result = I2C_OK;
> +
> +       if (IsACK(i2c)) {
> +               for (i = 0; (i < len) && (result == I2C_OK); i++) {
> +                       writel(buf[i], &i2c->iicds);
> +                       ReadWriteByte(i2c);
> +                       result = WaitForXfer(i2c);
> +                       if (!IsACK(i2c))
> +                               result = I2C_NACK;
> +               }
> +       } else {
> +               result = I2C_NACK;
> +       }
> +
> +       return result;
> +}
> +
>  void i2c_init(int speed, int slaveadd)
>  {
>         struct s3c24x0_i2c *i2c;
> @@ -302,41 +331,30 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
>                 return I2C_NOK_TOUT;
>
>         writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
> -       result = I2C_OK;
> +
> +       if (addr && addr_len) {
> +               writel(chip, &i2c->iicds);
> +               /* send START */
> +               writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
> +                       &i2c->iicstat);
> +               if (WaitForXfer(i2c) == I2C_OK)
> +                       result = i2c_send_verify(i2c, addr, addr_len);
> +               else
> +                       result = I2C_NACK;
> +       } else
> +               result = I2C_NACK;
>
>         switch (cmd_type) {
>         case I2C_WRITE:
> -               if (addr && addr_len) {
> -                       writel(chip, &i2c->iicds);
> -                       /* send START */
> -                       writel(I2C_MODE_MT | I2C_TXRX_ENA |
> I2C_START_STOP,
> -                              &i2c->iicstat);
> -                       i = 0;
> -                       while ((i < addr_len) && (result == I2C_OK)) {
> -                               result = WaitForXfer(i2c);
> -                               writel(addr[i], &i2c->iicds);
> -                               ReadWriteByte(i2c);
> -                               i++;
> -                       }
> -                       i = 0;
> -                       while ((i < data_len) && (result == I2C_OK)) {
> -                               result = WaitForXfer(i2c);
> -                               writel(data[i], &i2c->iicds);
> -                               ReadWriteByte(i2c);
> -                               i++;
> -                       }
> -               } else {
> +               if (result == I2C_OK)
> +                       result = i2c_send_verify(i2c, data, data_len);
> +               else {
>                         writel(chip, &i2c->iicds);
>                         /* send START */
>                         writel(I2C_MODE_MT | I2C_TXRX_ENA |
> I2C_START_STOP,
> -                              &i2c->iicstat);
> -                       i = 0;
> -                       while ((i < data_len) && (result = I2C_OK)) {
> -                               result = WaitForXfer(i2c);
> -                               writel(data[i], &i2c->iicds);
> -                               ReadWriteByte(i2c);
> -                               i++;
> -                       }
> +                               &i2c->iicstat);
> +                       if (WaitForXfer(i2c) == I2C_OK)
> +                               result = i2c_send_verify(i2c, data,
> data_len);
>                 }
>
>                 if (result == I2C_OK)
> @@ -348,42 +366,25 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
>                 break;
>
>         case I2C_READ:
> -               if (addr && addr_len) {
> -                       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
> +               if (result == I2C_OK) {
> +                       writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
>                         writel(chip, &i2c->iicds);
>                         /* send START */
>                         writel(readl(&i2c->iicstat) | I2C_START_STOP,
>                                &i2c->iicstat);
> -                       result = WaitForXfer(i2c);
> -                       if (IsACK(i2c)) {
> -                               i = 0;
> -                               while ((i < addr_len) && (result ==
> I2C_OK)) {
> -                                       writel(addr[i], &i2c->iicds);
> -                                       ReadWriteByte(i2c);
> -                                       result = WaitForXfer(i2c);
> -                                       i++;
> -                               }
> -
> -                               writel(chip, &i2c->iicds);
> -                               /* resend START */
> -                               writel(I2C_MODE_MR | I2C_TXRX_ENA |
> -                                      I2C_START_STOP, &i2c->iicstat);
>                         ReadWriteByte(i2c);
>                         result = WaitForXfer(i2c);
> -                               i = 0;
> -                               while ((i < data_len) && (result ==
> I2C_OK)) {
> -                                       /* disable ACK for final READ */
> -                                       if (i == data_len - 1)
> -                                               writel(readl(&i2c->iiccon)
> +                       i = 0;
> +                       while ((i < data_len) && (result == I2C_OK)) {
> +                               /* disable ACK for final READ */
> +                               if (i == data_len - 1)
> +                                       writel(readl(&i2c->iiccon)
>                                                         & ~I2CCON_ACKGEN,
>                                                         &i2c->iiccon);
>                                 ReadWriteByte(i2c);
>                                 result = WaitForXfer(i2c);
> -                                       data[i] = readl(&i2c->iicds);
> -                                       i++;
> -                               }
> -                       } else {
> -                               result = I2C_NACK;
> +                               data[i] = readl(&i2c->iicds);
> +                               i++;
>                         }
>
>                 } else {
> --
> 1.8.0
>

Guys, can we please hold on to this. I have a version which was
debugged and worked with the Infineon TPM, (which is generates NACKs
quite liberally, and not just on writes, but on reads too). I will
submit it a bit later.

--vb




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


More information about the U-Boot mailing list