diff options
author | Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com> | 2020-01-09 17:07:58 +0530 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2020-01-15 21:13:28 +0100 |
commit | b4c119dbc300c7a6ee2da70d5c7ba14747b35142 (patch) | |
tree | d5f596270a709549b52c50814a080ff8e1558b17 | |
parent | 40b2ec1251c370bc5557568e259d4058c651d405 (diff) |
i2c: xiic: Add timeout to the rx fifo wait loop
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>
-rw-r--r-- | drivers/i2c/busses/i2c-xiic.c | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 61e081b186cc..3a403202bd28 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -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); |