[U-Boot] [PATCH] Exynos5: i2c: Fix read NACK handling and remove some redundancy

Akshay Saraswat akshay.s at samsung.com
Tue Apr 9 10:08:23 CEST 2013


Hi Hung-ying Tyan,

>On which branch is this patch based? It looks quite off from ToT.
>

I rebased this patch on u-boot-samsung and posted. But it's been quite some
time since I posted it, so I am not sure if it could be applied straightway now.

>
>On Mon, Mar 25, 2013 at 7:46 PM, Akshay Saraswat <akshay.s at samsung.com> wrote:
>
>From: Gabe Black <gabeblack at google.com>
>
>The exynos s3c24x0 i2c driver wouldn't do the right thing when a NACK was
>received on a read because it didn't attempt a read before waiting for the
>read to finish. Putting a call to ReadWriteByte in the NACK path fixed a
>problem where getting a NACK reading from a device would jam up the bus and
>prevent future accesses like probing from working.
>
>Because other than the ReadWriteByte call the NACK and normal paths were
>almost the same thing, and to avoid future instances of the NACK path not
>working because it's not exercised normally, this change also consolidates
>those two paths.
>
>Signed-off-by: Gabe Black <gabeblack at google.com>
>Signed-off-by: Akshay Saraswat <akshay.s at samsung.com>
>---
> drivers/i2c/s3c24x0_i2c.c | 53 ++++++++++++++++-------------------------------
> 1 file changed, 18 insertions(+), 35 deletions(-)
>
>diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
>index d2b4eb0..91298a7 100644
>--- a/drivers/i2c/s3c24x0_i2c.c
>+++ b/drivers/i2c/s3c24x0_i2c.c
>@@ -366,21 +366,25 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
>                break;
>
>        case I2C_READ:
>-               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);
>-                       ReadWriteByte(i2c);
>-                       result = WaitForXfer(i2c);
>+       {
>+               int was_ok = (result == I2C_OK);
>+
>+               writel(chip, &i2c->iicds);
>+               /* resend START */
>+               writel(I2C_MODE_MR | I2C_TXRX_ENA |
>+                                       I2C_START_STOP, &i2c->iicstat);
>+               ReadWriteByte(i2c);
>+               result = WaitForXfer(i2c);
>+
>+               if (was_ok || IsACK(i2c)) {
>                        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);
>+                               if (i == data_len - 1) {
>+                                       writel(readl(&i2c->iiccon) &
>+                                             ~I2CCON_ACKGEN,
>+                                             &i2c->iiccon);
>+                               }
>                                ReadWriteByte(i2c);
>                                result = WaitForXfer(i2c);
>                                data[i] = readl(&i2c->iicds);
>@@ -388,35 +392,14 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
>                        }
>
>                } else {
>-                       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 < 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;
>-                       }
>+                       result = I2C_NACK;
>                }
>
>                /* send STOP */
>                writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
>                ReadWriteByte(i2c);
>                break;
>+       }
>
>        default:
>                debug("i2c_transfer: bad call\n");
>--
>1.8.0
>
>

Regards,
Akshay Saraswat


More information about the U-Boot mailing list