* [PATCH 1/5] i2c: sirf: reset i2c controller early after we get a noack
[not found] ` <1376385091-30597-1-git-send-email-Baohua.Song-kQvG35nSl+M@public.gmane.org>
@ 2013-08-13 9:11 ` Barry Song
[not found] ` <1376385091-30597-2-git-send-email-Baohua.Song-kQvG35nSl+M@public.gmane.org>
2013-08-13 9:11 ` [PATCH 2/5] i2c: sirf: we need to wait I2C_RESET status in resume Barry Song
` (3 subsequent siblings)
4 siblings, 1 reply; 12+ messages in thread
From: Barry Song @ 2013-08-13 9:11 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, linux-i2c-u79uwXL29TY76Z2rM5mHXA
Cc: workgroup.linux-kQvG35nSl+M, Zhiwu Song, Barry Song
From: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
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-kQvG35nSl+M@public.gmane.org>
Signed-off-by: Barry Song <Baohua.Song-kQvG35nSl+M@public.gmane.org>
---
drivers/i2c/busses/i2c-sirf.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index a63c7d5..055210e 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -65,6 +65,8 @@
#define SIRFSOC_I2C_START BIT(7)
#define SIRFSOC_I2C_DEFAULT_SPEED 100000
+#define SIRFSOC_I2C_ERR_NOACK 1
+#define SIRFSOC_I2C_ERR_TIMEOUT 2
struct sirfsoc_i2c {
void __iomem *base;
@@ -143,14 +145,24 @@ static irqreturn_t i2c_sirfsoc_irq(int irq, void *dev_id)
if (i2c_stat & SIRFSOC_I2C_STAT_ERR) {
/* Error conditions */
- siic->err_status = 1;
+ siic->err_status = SIRFSOC_I2C_ERR_NOACK;
writel(SIRFSOC_I2C_STAT_ERR, siic->base + SIRFSOC_I2C_STATUS);
if (i2c_stat & SIRFSOC_I2C_STAT_NACK)
- dev_err(&siic->adapter.dev, "ACK not received\n");
+ dev_dbg(&siic->adapter.dev, "ACK not received\n");
else
dev_err(&siic->adapter.dev, "I2C error\n");
+ /*
+ * 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
+ */
+ writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
+ siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
+
complete(&siic->done);
} else if (i2c_stat & SIRFSOC_I2C_STAT_CMD_DONE) {
/* CMD buffer execution complete */
@@ -191,7 +203,6 @@ static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
u32 regval = readl(siic->base + SIRFSOC_I2C_CTRL);
/* timeout waiting for the xfer to finish or fail */
int timeout = msecs_to_jiffies((msg->len + 1) * 50);
- int ret = 0;
i2c_sirfsoc_set_address(siic, msg);
@@ -200,7 +211,7 @@ static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
i2c_sirfsoc_queue_cmd(siic);
if (wait_for_completion_timeout(&siic->done, timeout) == 0) {
- siic->err_status = 1;
+ siic->err_status = SIRFSOC_I2C_ERR_TIMEOUT;
dev_err(&siic->adapter.dev, "Transfer timeout\n");
}
@@ -208,16 +219,14 @@ static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
siic->base + SIRFSOC_I2C_CTRL);
writel(0, siic->base + SIRFSOC_I2C_CMD_START);
- if (siic->err_status) {
+ /* i2c control doesn't response, reset it */
+ if (siic->err_status == SIRFSOC_I2C_ERR_TIMEOUT) {
writel(readl(siic->base + SIRFSOC_I2C_CTRL) | SIRFSOC_I2C_RESET,
siic->base + SIRFSOC_I2C_CTRL);
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
cpu_relax();
-
- ret = -EIO;
}
-
- return ret;
+ return siic->err_status ? -EIO : 0;
}
static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
--
1.8.2.3
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 2/5] i2c: sirf: we need to wait I2C_RESET status in resume
[not found] ` <1376385091-30597-1-git-send-email-Baohua.Song-kQvG35nSl+M@public.gmane.org>
2013-08-13 9:11 ` [PATCH 1/5] i2c: sirf: reset i2c controller early after we get a noack Barry Song
@ 2013-08-13 9:11 ` Barry Song
2013-08-13 9:11 ` [PATCH 3/5] i2c: sirf: fix the typo for setting bitrate to less than 100k Barry Song
` (2 subsequent siblings)
4 siblings, 0 replies; 12+ messages in thread
From: Barry Song @ 2013-08-13 9:11 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, linux-i2c-u79uwXL29TY76Z2rM5mHXA
Cc: workgroup.linux-kQvG35nSl+M, Zhiwu Song, Barry Song
From: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
this fixes the issue that we lost to wait the i2c reset finished.
Signed-off-by: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
Signed-off-by: Barry Song <Baohua.Song-kQvG35nSl+M@public.gmane.org>
---
drivers/i2c/busses/i2c-sirf.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 055210e..45a8881 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -425,6 +425,8 @@ static int i2c_sirfsoc_resume(struct device *dev)
clk_enable(siic->clk);
writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
+ while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
+ cpu_relax();
writel(SIRFSOC_I2C_CORE_EN | SIRFSOC_I2C_MASTER_MODE,
siic->base + SIRFSOC_I2C_CTRL);
writel(siic->clk_div, siic->base + SIRFSOC_I2C_CLK_CTRL);
--
1.8.2.3
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 3/5] i2c: sirf: fix the typo for setting bitrate to less than 100k
[not found] ` <1376385091-30597-1-git-send-email-Baohua.Song-kQvG35nSl+M@public.gmane.org>
2013-08-13 9:11 ` [PATCH 1/5] i2c: sirf: reset i2c controller early after we get a noack Barry Song
2013-08-13 9:11 ` [PATCH 2/5] i2c: sirf: we need to wait I2C_RESET status in resume Barry Song
@ 2013-08-13 9:11 ` Barry Song
2013-08-13 9:11 ` [PATCH 4/5] i2c: sirfsoc: support reverse direction of address Barry Song
2013-08-13 9:11 ` [PATCH 5/5] i2c: sirf: retry 3 times as sometimes we get random noack and timeout Barry Song
4 siblings, 0 replies; 12+ messages in thread
From: Barry Song @ 2013-08-13 9:11 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, linux-i2c-u79uwXL29TY76Z2rM5mHXA
Cc: workgroup.linux-kQvG35nSl+M, Zhiwu Song, Barry Song
From: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
there is a typo before, it makes the final bitrate wrong, this patch fixes
it.
Signed-off-by: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
Signed-off-by: Barry Song <Baohua.Song-kQvG35nSl+M@public.gmane.org>
---
drivers/i2c/busses/i2c-sirf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 45a8881..746388f 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -357,7 +357,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
if (bitrate < 100000)
regval =
- (2 * ctrl_speed) / (2 * bitrate * 11);
+ (2 * ctrl_speed) / (bitrate * 11);
else
regval = ctrl_speed / (bitrate * 5);
--
1.8.2.3
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 4/5] i2c: sirfsoc: support reverse direction of address
[not found] ` <1376385091-30597-1-git-send-email-Baohua.Song-kQvG35nSl+M@public.gmane.org>
` (2 preceding siblings ...)
2013-08-13 9:11 ` [PATCH 3/5] i2c: sirf: fix the typo for setting bitrate to less than 100k Barry Song
@ 2013-08-13 9:11 ` Barry Song
[not found] ` <1376385091-30597-5-git-send-email-Baohua.Song-kQvG35nSl+M@public.gmane.org>
2013-08-13 9:11 ` [PATCH 5/5] i2c: sirf: retry 3 times as sometimes we get random noack and timeout Barry Song
4 siblings, 1 reply; 12+ messages in thread
From: Barry Song @ 2013-08-13 9:11 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, linux-i2c-u79uwXL29TY76Z2rM5mHXA
Cc: workgroup.linux-kQvG35nSl+M, Zhiwu Song, Rongjun Ying, Barry Song
From: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
if users set I2C_M_REV_DIR_ADDR, revert the direction of address.
Signed-off-by: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
Signed-off-by: Rongjun Ying <rongjun.ying-kQvG35nSl+M@public.gmane.org>
Signed-off-by: Barry Song <Baohua.Song-kQvG35nSl+M@public.gmane.org>
---
drivers/i2c/busses/i2c-sirf.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 746388f..d2b7913 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -195,6 +195,10 @@ static void i2c_sirfsoc_set_address(struct sirfsoc_i2c *siic,
if (msg->flags & I2C_M_RD)
addr |= 1;
+ /* Reverse direction bit */
+ if (msg->flags & I2C_M_REV_DIR_ADDR)
+ addr ^= 1;
+
writel(addr, siic->base + SIRFSOC_I2C_CMD(siic->cmd_ptr++));
}
--
1.8.2.3
^ permalink raw reply related [flat|nested] 12+ messages in thread* [PATCH 5/5] i2c: sirf: retry 3 times as sometimes we get random noack and timeout
[not found] ` <1376385091-30597-1-git-send-email-Baohua.Song-kQvG35nSl+M@public.gmane.org>
` (3 preceding siblings ...)
2013-08-13 9:11 ` [PATCH 4/5] i2c: sirfsoc: support reverse direction of address Barry Song
@ 2013-08-13 9:11 ` Barry Song
4 siblings, 0 replies; 12+ messages in thread
From: Barry Song @ 2013-08-13 9:11 UTC (permalink / raw)
To: wsa-z923LK4zBo2bacvFa/9K2g, linux-i2c-u79uwXL29TY76Z2rM5mHXA
Cc: workgroup.linux-kQvG35nSl+M, Zhiwu Song, Barry Song
From: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
let i2c core retry 3 times as sometimes we get random noack and timeout
even when we access an existing i2c client.
Signed-off-by: Zhiwu Song <Zhiwu.Song-kQvG35nSl+M@public.gmane.org>
Signed-off-by: Barry Song <Baohua.Song-kQvG35nSl+M@public.gmane.org>
---
drivers/i2c/busses/i2c-sirf.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index d2b7913..90adc2d 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -230,7 +230,7 @@ static int i2c_sirfsoc_xfer_msg(struct sirfsoc_i2c *siic, struct i2c_msg *msg)
while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
cpu_relax();
}
- return siic->err_status ? -EIO : 0;
+ return siic->err_status ? -EAGAIN : 0;
}
static u32 i2c_sirfsoc_func(struct i2c_adapter *adap)
@@ -334,6 +334,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
adap->algo = &i2c_sirfsoc_algo;
adap->algo_data = siic;
+ adap->retries = 3;
adap->dev.of_node = pdev->dev.of_node;
adap->dev.parent = &pdev->dev;
--
1.8.2.3
^ permalink raw reply related [flat|nested] 12+ messages in thread