aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorZhiwu Song <Zhiwu.Song@csr.com>2013-08-13 05:11:27 -0400
committerWolfram Sang <wsa@the-dreams.de>2013-08-28 05:43:34 -0400
commitc984319ad9c54c269493b6bc0517e8c2dfca4456 (patch)
tree87a41ed1f90e639973c321caec782445eb0c1b96 /drivers/i2c
parent57cd1e3029e5fb4d238ad11fd0d7ad917179fdf2 (diff)
i2c: sirf: reset i2c controller early after we get a noack
Due to hardware ANOMALY, we need to reset I2C earlier after we get NOACK while accessing non-existing clients, otherwise we will get errors even we access existing clients later Signed-off-by: Zhiwu Song <Zhiwu.Song@csr.com> Signed-off-by: Barry Song <Baohua.Song@csr.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-sirf.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 0ff22e29e7df..ff47a767f756 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -64,6 +64,8 @@
64#define SIRFSOC_I2C_START BIT(7) 64#define SIRFSOC_I2C_START BIT(7)
65 65
66#define SIRFSOC_I2C_DEFAULT_SPEED 100000 66#define SIRFSOC_I2C_DEFAULT_SPEED 100000
67#define SIRFSOC_I2C_ERR_NOACK 1
68#define SIRFSOC_I2C_ERR_TIMEOUT 2
67 69
68struct sirfsoc_i2c { 70struct sirfsoc_i2c {
69 void __iomem *base; 71 void __iomem *base;
@@ -142,14 +144,24 @@ static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
142 144
143 if (i2c_stat & SIRFSOC_I2C_STAT_ERR) { 145 if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
144 /* Error conditions */ 146 /* Error conditions */
145 siic->err_status = 1; 147 siic->err_status = SIRFSOC_I2C_ERR_NOACK;
146 writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS); 148 writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
147 149
148 if (i2c_stat & SIRFSOC_I2C_STAT_NACK) 150 if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
149 dev_err(&siic->adapter.dev, "ACK not received\n"); 151 dev_dbg(&siic->adapter.dev, "ACK not received\n");
150 else 152 else
151 dev_err(&siic->adapter.dev, "I2C error\n"); 153 dev_err(&siic->adapter.dev, "I2C error\n");
152 154
155 /*
156 * Due to hardware ANOMALY, we need to reset I2C earlier after
157 * we get NOACK while accessing non-existing clients, otherwise
158 * we will get errors even we access existing clients later
159 */
160 writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
161 siic->base + SIRFSOC_I2C_CTRL);
162 while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
163 cpu_relax();
164
153 complete(&siic->done); 165 complete(&siic->done);
154 } else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) { 166 } else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
155 /* CMD buffer execution complete */ 167 /* CMD buffer execution complete */
@@ -190,7 +202,6 @@ static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
190 u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL); 202 u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
191 /* timeout waiting for the xfer to finish or fail */ 203 /* timeout waiting for the xfer to finish or fail */
192 int timeout = msecs_to_jiffies((msg->len + 1) * 50); 204 int timeout = msecs_to_jiffies((msg->len + 1) * 50);
193 int ret = 0;
194 205
195 i2c_sirfsoc_set_address(siic, msg); 206 i2c_sirfsoc_set_address(siic, msg);
196 207
@@ -199,7 +210,7 @@ static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
199 i2c_sirfsoc_queue_cmd(siic); 210 i2c_sirfsoc_queue_cmd(siic);
200 211
201 if (wait_for_completion_timeout(&siic->done, timeout) == 0) { 212 if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
202 siic->err_status = 1; 213 siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT;
203 dev_err(&siic->adapter.dev, "Transfer timeout\n"); 214 dev_err(&siic->adapter.dev, "Transfer timeout\n");
204 } 215 }
205 216
@@ -207,16 +218,14 @@ static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
207 siic->base + SIRFSOC_I2C_CTRL); 218 siic->base + SIRFSOC_I2C_CTRL);
208 writel(0, siic->base + SIRFSOC_I2C_CMD_START); 219 writel(0, siic->base + SIRFSOC_I2C_CMD_START);
209 220
210 if (siic->err_status) { 221 /* i2c control doesn't response, reset it */
222 if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) {
211 writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET, 223 writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
212 siic->base + SIRFSOC_I2C_CTRL); 224 siic->base + SIRFSOC_I2C_CTRL);
213 while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET) 225 while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
214 cpu_relax(); 226 cpu_relax();
215
216 ret = -EIO;
217 } 227 }
218 228 return siic->err_status ? -EIO : 0;
219 return ret;
220} 229}
221 230
222static u32 i2c_sirfsoc_func(struct i2c_adapter *adap) 231static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)