i2c: add retry-process when slave NACK. [1/1]
authorDaogao Xu <daogao.xu@amlogic.com>
Thu, 28 Feb 2019 07:01:10 +0000 (15:01 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Mon, 11 Mar 2019 03:21:36 +0000 (19:21 -0800)
PD#SWPL-4761

Problem:
When slave device is busy processing, it is unable to handle the
incoming communication attempts. i2c master have to repeatedly attemp
communication  until the slave sends an ACK after receiving its slave
address.

Solution:
add retry-process when slave NACK.

Verify:
mesonaxg_s420_32_release

Change-Id: Ieb195176cac4b80e223ea6adb502ffd3bc9ef728
Signed-off-by: Daogao Xu <daogao.xu@amlogic.com>
drivers/amlogic/i2c/i2c-meson-master.c

index 6d11198..fa19739 100644 (file)
@@ -107,6 +107,7 @@ struct meson_i2c {
        int                     count;
        int                     pos;
        int                     error;
+       int                     retries;
 
        spinlock_t              lock;
        struct completion       done;
@@ -318,6 +319,8 @@ static void meson_i2c_prepare_xfer(struct meson_i2c *i2c)
 
        if (write)
                meson_i2c_put_data(i2c, i2c->msg->buf + i2c->pos, i2c->count);
+
+       i2c->retries = 0;
 }
 
 static void meson_i2c_stop(struct meson_i2c *i2c)
@@ -340,7 +343,6 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
 
        spin_lock(&i2c->lock);
 
-       meson_i2c_reset_tokens(i2c);
        ctrl = readl(i2c->regs + REG_CTRL);
 
        dev_dbg(i2c->dev, "irq: state %d, pos %d, count %d, ctrl %08x\n",
@@ -354,12 +356,15 @@ static irqreturn_t meson_i2c_irq(int irqno, void *dev_id)
                 * condition.
                 */
                dev_dbg(i2c->dev, "error bit set\n");
-               i2c->error = -ENXIO;
-               i2c->state = STATE_IDLE;
-               complete(&i2c->done);
+               if (++i2c->retries >= i2c->adap.retries) {
+                       i2c->error = -ENXIO;
+                       i2c->state = STATE_IDLE;
+                       complete(&i2c->done);
+               }
                goto out;
        }
 
+       meson_i2c_reset_tokens(i2c);
        switch (i2c->state) {
        case STATE_READ:
                if (i2c->count > 0) {