i2c: xiic: Add timeout to the rx fifo wait loop
authorShubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Thu, 9 Jan 2020 11:37:58 +0000 (17:07 +0530)
committerWolfram Sang <wsa@the-dreams.de>
Wed, 15 Jan 2020 20:13:28 +0000 (21:13 +0100)
Add timeout to the rx fifo empty wait loop. Also check for the return
value for xiic_reinit and pass it to xiic_start_xfer.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/i2c/busses/i2c-xiic.c

index 61e081b186cc6bbb7675adee7fee8351692eab5a..3a403202bd2889a8f0d7a017a68c4e10e1425b77 100644 (file)
@@ -156,6 +156,8 @@ struct xiic_i2c {
 #define XIIC_RESET_MASK             0xAUL
 
 #define XIIC_PM_TIMEOUT                1000    /* ms */
+/* timeout waiting for the controller to respond */
+#define XIIC_I2C_TIMEOUT       (msecs_to_jiffies(1000))
 /*
  * The following constant is used for the device global interrupt enable
  * register, to enable all interrupts for the device, this is the only bit
@@ -166,7 +168,7 @@ struct xiic_i2c {
 #define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos)
 #define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos)
 
-static void xiic_start_xfer(struct xiic_i2c *i2c);
+static int xiic_start_xfer(struct xiic_i2c *i2c);
 static void __xiic_start_xfer(struct xiic_i2c *i2c);
 
 /*
@@ -247,17 +249,29 @@ static inline void xiic_irq_clr_en(struct xiic_i2c *i2c, u32 mask)
        xiic_irq_en(i2c, mask);
 }
 
-static void xiic_clear_rx_fifo(struct xiic_i2c *i2c)
+static int xiic_clear_rx_fifo(struct xiic_i2c *i2c)
 {
        u8 sr;
+       unsigned long timeout;
+
+       timeout = jiffies + XIIC_I2C_TIMEOUT;
        for (sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET);
                !(sr & XIIC_SR_RX_FIFO_EMPTY_MASK);
-               sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET))
+               sr = xiic_getreg8(i2c, XIIC_SR_REG_OFFSET)) {
                xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET);
+               if (time_after(jiffies, timeout)) {
+                       dev_err(i2c->dev, "Failed to clear rx fifo\n");
+                               return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
 }
 
-static void xiic_reinit(struct xiic_i2c *i2c)
+static int xiic_reinit(struct xiic_i2c *i2c)
 {
+       int ret;
+
        xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK);
 
        /* Set receive Fifo depth to maximum (zero based). */
@@ -270,12 +284,16 @@ static void xiic_reinit(struct xiic_i2c *i2c)
        xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK);
 
        /* make sure RX fifo is empty */
-       xiic_clear_rx_fifo(i2c);
+       ret = xiic_clear_rx_fifo(i2c);
+       if (ret)
+               return ret;
 
        /* Enable interrupts */
        xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK);
 
        xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK);
+
+       return 0;
 }
 
 static void xiic_deinit(struct xiic_i2c *i2c)
@@ -655,12 +673,18 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
 
 }
 
-static void xiic_start_xfer(struct xiic_i2c *i2c)
+static int xiic_start_xfer(struct xiic_i2c *i2c)
 {
+       int ret;
        mutex_lock(&i2c->lock);
-       xiic_reinit(i2c);
-       __xiic_start_xfer(i2c);
+
+       ret = xiic_reinit(i2c);
+       if (!ret)
+               __xiic_start_xfer(i2c);
+
        mutex_unlock(&i2c->lock);
+
+       return ret;
 }
 
 static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
@@ -682,7 +706,11 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        i2c->tx_msg = msgs;
        i2c->nmsgs = num;
 
-       xiic_start_xfer(i2c);
+       err = xiic_start_xfer(i2c);
+       if (err < 0) {
+               dev_err(adap->dev.parent, "Error xiic_start_xfer\n");
+               goto out;
+       }
 
        if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
                (i2c->state == STATE_DONE), HZ)) {
@@ -794,7 +822,11 @@ static int xiic_i2c_probe(struct platform_device *pdev)
        if (!(sr & XIIC_SR_TX_FIFO_EMPTY_MASK))
                i2c->endianness = BIG;
 
-       xiic_reinit(i2c);
+       ret = xiic_reinit(i2c);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Cannot xiic_reinit\n");
+               goto err_clk_dis;
+       }
 
        /* add i2c adapter to i2c tree */
        ret = i2c_add_adapter(&i2c->adap);