qup_i2c: Fix state check in polling code.
If QUP core is in PAUSE state then the state check returns true
for any other state incorrectly. Also, if the core is in RUN state
and it's being put in RESET, then RESET state check may return true
even if it's not out of RUN (and if VALID bit is set).
State mask is used to verify what state QUP core is in to avoid this
problem.
Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index c269787..8654cb9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -327,19 +327,30 @@
}
static int
-qup_i2c_poll_state(struct qup_i2c_dev *dev, uint32_t state)
+qup_i2c_poll_state(struct qup_i2c_dev *dev, uint32_t req_state, bool only_valid)
{
uint32_t retries = 0;
- dev_dbg(dev->dev, "Polling Status for state:0x%x\n", state);
+ dev_dbg(dev->dev, "Polling for state:0x%x, or valid-only:%d\n",
+ req_state, only_valid);
while (retries != 2000) {
uint32_t status = readl_relaxed(dev->base + QUP_STATE);
- if ((status & (QUP_STATE_VALID | state)) ==
- (QUP_STATE_VALID | state))
- return 0;
- else if (retries++ == 1000)
+ /*
+ * If only valid bit needs to be checked, requested state is
+ * 'don't care'
+ */
+ if (status & QUP_STATE_VALID) {
+ if (only_valid)
+ return 0;
+ else if ((req_state & QUP_I2C_MAST_GEN) &&
+ (status & QUP_I2C_MAST_GEN))
+ return 0;
+ else if ((status & QUP_STATE_MASK) == req_state)
+ return 0;
+ }
+ if (retries++ == 1000)
udelay(100);
}
return -ETIMEDOUT;
@@ -551,10 +562,10 @@
static int
qup_update_state(struct qup_i2c_dev *dev, uint32_t state)
{
- if (qup_i2c_poll_state(dev, 0) != 0)
+ if (qup_i2c_poll_state(dev, 0, true) != 0)
return -EIO;
writel_relaxed(state, dev->base + QUP_STATE);
- if (qup_i2c_poll_state(dev, state) != 0)
+ if (qup_i2c_poll_state(dev, state, false) != 0)
return -EIO;
return 0;
}
@@ -687,7 +698,7 @@
}
writel_relaxed(1, dev->base + QUP_SW_RESET);
- ret = qup_i2c_poll_state(dev, QUP_RESET_STATE);
+ ret = qup_i2c_poll_state(dev, QUP_RESET_STATE, false);
if (ret) {
dev_err(dev->dev, "QUP Busy:Trying to recover\n");
goto out_err;
@@ -720,7 +731,7 @@
dev->err = 0;
dev->complete = &complete;
- if (qup_i2c_poll_state(dev, QUP_I2C_MAST_GEN) != 0) {
+ if (qup_i2c_poll_state(dev, QUP_I2C_MAST_GEN, false) != 0) {
ret = -EIO;
goto out_err;
}