All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Mediatek I2C Fixup
@ 2015-11-09  5:43 ` Liguo Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: srv_heupstream, Matthias Brugger, Eddie Huang, Xudong Chen,
	Sascha Hauer, linux-i2c, linux-kernel, linux-arm-kernel,
	linux-mediatek

This series contain two patches, first is to optimize Mediatek I2C driver to use WRRD
if hardware support auto restart. Because auto restart will issue auto restart
interrupt, change to use WRRD can reduce interrupt latency. The second is to fix
multi transfer error in high speed mode. If hardware support auto restart, need driver
to send master code first.

Change in v2:
fix i2c checkpatch error.

Liguo Zhang (2):
  i2c: mediatek: add i2c first write then read optimization
  i2c: mediatek: fix i2c multi transfer issue in high speed mode

 drivers/i2c/busses/i2c-mt65xx.c | 78 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 72 insertions(+), 6 deletions(-)

--
1.8.1.1.dirty


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 0/2] Mediatek I2C Fixup
@ 2015-11-09  5:43 ` Liguo Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: srv_heupstream, Matthias Brugger, Eddie Huang, Xudong Chen,
	Sascha Hauer, linux-i2c, linux-kernel, linux-arm-kernel,
	linux-mediatek

This series contain two patches, first is to optimize Mediatek I2C driver to use WRRD
if hardware support auto restart. Because auto restart will issue auto restart
interrupt, change to use WRRD can reduce interrupt latency. The second is to fix
multi transfer error in high speed mode. If hardware support auto restart, need driver
to send master code first.

Change in v2:
fix i2c checkpatch error.

Liguo Zhang (2):
  i2c: mediatek: add i2c first write then read optimization
  i2c: mediatek: fix i2c multi transfer issue in high speed mode

 drivers/i2c/busses/i2c-mt65xx.c | 78 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 72 insertions(+), 6 deletions(-)

--
1.8.1.1.dirty

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 0/2] Mediatek I2C Fixup
@ 2015-11-09  5:43 ` Liguo Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: linux-arm-kernel

This series contain two patches, first is to optimize Mediatek I2C driver to use WRRD
if hardware support auto restart. Because auto restart will issue auto restart
interrupt, change to use WRRD can reduce interrupt latency. The second is to fix
multi transfer error in high speed mode. If hardware support auto restart, need driver
to send master code first.

Change in v2:
fix i2c checkpatch error.

Liguo Zhang (2):
  i2c: mediatek: add i2c first write then read optimization
  i2c: mediatek: fix i2c multi transfer issue in high speed mode

 drivers/i2c/busses/i2c-mt65xx.c | 78 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 72 insertions(+), 6 deletions(-)

--
1.8.1.1.dirty

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
  2015-11-09  5:43 ` Liguo Zhang
  (?)
@ 2015-11-09  5:43   ` Liguo Zhang
  -1 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: srv_heupstream, Matthias Brugger, Eddie Huang, Xudong Chen,
	Sascha Hauer, linux-i2c, linux-kernel, linux-arm-kernel,
	linux-mediatek, Liguo Zhang

For platform with auto restart support, between every transfer,
i2c controller will trigger an interrupt and SW need to handle
it to start new transfer. When doing write-then-read transfer,
instead of restart mechanism, using WRRD mode to have controller
send both transfer in one request to reduce latency.

Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
---
 drivers/i2c/busses/i2c-mt65xx.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 9b86716..dc4aac6 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -132,6 +132,7 @@ struct mtk_i2c_compatible {
 	unsigned char pmic_i2c: 1;
 	unsigned char dcm: 1;
 	unsigned char auto_restart: 1;
+	unsigned char aux_len_reg: 1;
 };
 
 struct mtk_i2c {
@@ -153,6 +154,7 @@ struct mtk_i2c {
 	enum mtk_trans_op op;
 	u16 timing_reg;
 	u16 high_speed_reg;
+	unsigned char auto_restart;
 	const struct mtk_i2c_compatible *dev_comp;
 };
 
@@ -178,6 +180,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
 	.pmic_i2c = 0,
 	.dcm = 1,
 	.auto_restart = 0,
+	.aux_len_reg = 0,
 };
 
 static const struct mtk_i2c_compatible mt6589_compat = {
@@ -185,6 +188,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
 	.pmic_i2c = 1,
 	.dcm = 0,
 	.auto_restart = 0,
+	.aux_len_reg = 0,
 };
 
 static const struct mtk_i2c_compatible mt8173_compat = {
@@ -192,6 +196,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
 	.pmic_i2c = 0,
 	.dcm = 1,
 	.auto_restart = 1,
+	.aux_len_reg = 1,
 };
 
 static const struct of_device_id mtk_i2c_of_match[] = {
@@ -373,7 +378,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	i2c->irq_stat = 0;
 
-	if (i2c->dev_comp->auto_restart)
+	if (i2c->auto_restart)
 		restart_flag = I2C_RS_TRANSFER;
 
 	reinit_completion(&i2c->msg_complete);
@@ -411,8 +416,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	/* Set transfer and transaction len */
 	if (i2c->op == I2C_MASTER_WRRD) {
-		writew(msgs->len | ((msgs + 1)->len) << 8,
-		       i2c->base + OFFSET_TRANSFER_LEN);
+		if (i2c->dev_comp->aux_len_reg) {
+			writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
+			writew((msgs + 1)->len, i2c->base +
+			       OFFSET_TRANSFER_LEN_AUX);
+		} else {
+			writew(msgs->len | ((msgs + 1)->len) << 8,
+			       i2c->base + OFFSET_TRANSFER_LEN);
+		}
 		writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
 	} else {
 		writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
@@ -461,7 +472,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN);
 
-	if (!i2c->dev_comp->auto_restart) {
+	if (!i2c->auto_restart) {
 		start_reg = I2C_TRANSAC_START;
 	} else {
 		start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
@@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 	if (ret)
 		return ret;
 
+	i2c->auto_restart = i2c->dev_comp->auto_restart;
+
+	/* checking if we can skip restart and optimize using WRRD mode */
+	if (i2c->auto_restart && num == 2) {
+		if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+		    msgs[0].addr == msgs[1].addr) {
+			i2c->auto_restart = 0;
+		}
+	}
+
 	while (left_num--) {
 		if (!msgs->buf) {
 			dev_dbg(i2c->dev, "data buffer is NULL.\n");
@@ -530,7 +551,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 		else
 			i2c->op = I2C_MASTER_WR;
 
-		if (!i2c->dev_comp->auto_restart) {
+		if (!i2c->auto_restart) {
 			if (num > 1) {
 				/* combined two messages into one transaction */
 				i2c->op = I2C_MASTER_WRRD;
@@ -559,7 +580,7 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
 	u16 restart_flag = 0;
 	u16 intr_stat;
 
-	if (i2c->dev_comp->auto_restart)
+	if (i2c->auto_restart)
 		restart_flag = I2C_RS_TRANSFER;
 
 	intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
-- 
1.8.1.1.dirty


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
@ 2015-11-09  5:43   ` Liguo Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: srv_heupstream, Matthias Brugger, Eddie Huang, Xudong Chen,
	Sascha Hauer, linux-i2c, linux-kernel, linux-arm-kernel,
	linux-mediatek, Liguo Zhang

For platform with auto restart support, between every transfer,
i2c controller will trigger an interrupt and SW need to handle
it to start new transfer. When doing write-then-read transfer,
instead of restart mechanism, using WRRD mode to have controller
send both transfer in one request to reduce latency.

Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
---
 drivers/i2c/busses/i2c-mt65xx.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 9b86716..dc4aac6 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -132,6 +132,7 @@ struct mtk_i2c_compatible {
 	unsigned char pmic_i2c: 1;
 	unsigned char dcm: 1;
 	unsigned char auto_restart: 1;
+	unsigned char aux_len_reg: 1;
 };
 
 struct mtk_i2c {
@@ -153,6 +154,7 @@ struct mtk_i2c {
 	enum mtk_trans_op op;
 	u16 timing_reg;
 	u16 high_speed_reg;
+	unsigned char auto_restart;
 	const struct mtk_i2c_compatible *dev_comp;
 };
 
@@ -178,6 +180,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
 	.pmic_i2c = 0,
 	.dcm = 1,
 	.auto_restart = 0,
+	.aux_len_reg = 0,
 };
 
 static const struct mtk_i2c_compatible mt6589_compat = {
@@ -185,6 +188,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
 	.pmic_i2c = 1,
 	.dcm = 0,
 	.auto_restart = 0,
+	.aux_len_reg = 0,
 };
 
 static const struct mtk_i2c_compatible mt8173_compat = {
@@ -192,6 +196,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
 	.pmic_i2c = 0,
 	.dcm = 1,
 	.auto_restart = 1,
+	.aux_len_reg = 1,
 };
 
 static const struct of_device_id mtk_i2c_of_match[] = {
@@ -373,7 +378,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	i2c->irq_stat = 0;
 
-	if (i2c->dev_comp->auto_restart)
+	if (i2c->auto_restart)
 		restart_flag = I2C_RS_TRANSFER;
 
 	reinit_completion(&i2c->msg_complete);
@@ -411,8 +416,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	/* Set transfer and transaction len */
 	if (i2c->op == I2C_MASTER_WRRD) {
-		writew(msgs->len | ((msgs + 1)->len) << 8,
-		       i2c->base + OFFSET_TRANSFER_LEN);
+		if (i2c->dev_comp->aux_len_reg) {
+			writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
+			writew((msgs + 1)->len, i2c->base +
+			       OFFSET_TRANSFER_LEN_AUX);
+		} else {
+			writew(msgs->len | ((msgs + 1)->len) << 8,
+			       i2c->base + OFFSET_TRANSFER_LEN);
+		}
 		writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
 	} else {
 		writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
@@ -461,7 +472,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN);
 
-	if (!i2c->dev_comp->auto_restart) {
+	if (!i2c->auto_restart) {
 		start_reg = I2C_TRANSAC_START;
 	} else {
 		start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
@@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 	if (ret)
 		return ret;
 
+	i2c->auto_restart = i2c->dev_comp->auto_restart;
+
+	/* checking if we can skip restart and optimize using WRRD mode */
+	if (i2c->auto_restart && num == 2) {
+		if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+		    msgs[0].addr == msgs[1].addr) {
+			i2c->auto_restart = 0;
+		}
+	}
+
 	while (left_num--) {
 		if (!msgs->buf) {
 			dev_dbg(i2c->dev, "data buffer is NULL.\n");
@@ -530,7 +551,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 		else
 			i2c->op = I2C_MASTER_WR;
 
-		if (!i2c->dev_comp->auto_restart) {
+		if (!i2c->auto_restart) {
 			if (num > 1) {
 				/* combined two messages into one transaction */
 				i2c->op = I2C_MASTER_WRRD;
@@ -559,7 +580,7 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
 	u16 restart_flag = 0;
 	u16 intr_stat;
 
-	if (i2c->dev_comp->auto_restart)
+	if (i2c->auto_restart)
 		restart_flag = I2C_RS_TRANSFER;
 
 	intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
@ 2015-11-09  5:43   ` Liguo Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: linux-arm-kernel

For platform with auto restart support, between every transfer,
i2c controller will trigger an interrupt and SW need to handle
it to start new transfer. When doing write-then-read transfer,
instead of restart mechanism, using WRRD mode to have controller
send both transfer in one request to reduce latency.

Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
---
 drivers/i2c/busses/i2c-mt65xx.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index 9b86716..dc4aac6 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -132,6 +132,7 @@ struct mtk_i2c_compatible {
 	unsigned char pmic_i2c: 1;
 	unsigned char dcm: 1;
 	unsigned char auto_restart: 1;
+	unsigned char aux_len_reg: 1;
 };
 
 struct mtk_i2c {
@@ -153,6 +154,7 @@ struct mtk_i2c {
 	enum mtk_trans_op op;
 	u16 timing_reg;
 	u16 high_speed_reg;
+	unsigned char auto_restart;
 	const struct mtk_i2c_compatible *dev_comp;
 };
 
@@ -178,6 +180,7 @@ static const struct mtk_i2c_compatible mt6577_compat = {
 	.pmic_i2c = 0,
 	.dcm = 1,
 	.auto_restart = 0,
+	.aux_len_reg = 0,
 };
 
 static const struct mtk_i2c_compatible mt6589_compat = {
@@ -185,6 +188,7 @@ static const struct mtk_i2c_compatible mt6589_compat = {
 	.pmic_i2c = 1,
 	.dcm = 0,
 	.auto_restart = 0,
+	.aux_len_reg = 0,
 };
 
 static const struct mtk_i2c_compatible mt8173_compat = {
@@ -192,6 +196,7 @@ static const struct mtk_i2c_compatible mt8173_compat = {
 	.pmic_i2c = 0,
 	.dcm = 1,
 	.auto_restart = 1,
+	.aux_len_reg = 1,
 };
 
 static const struct of_device_id mtk_i2c_of_match[] = {
@@ -373,7 +378,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	i2c->irq_stat = 0;
 
-	if (i2c->dev_comp->auto_restart)
+	if (i2c->auto_restart)
 		restart_flag = I2C_RS_TRANSFER;
 
 	reinit_completion(&i2c->msg_complete);
@@ -411,8 +416,14 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	/* Set transfer and transaction len */
 	if (i2c->op == I2C_MASTER_WRRD) {
-		writew(msgs->len | ((msgs + 1)->len) << 8,
-		       i2c->base + OFFSET_TRANSFER_LEN);
+		if (i2c->dev_comp->aux_len_reg) {
+			writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
+			writew((msgs + 1)->len, i2c->base +
+			       OFFSET_TRANSFER_LEN_AUX);
+		} else {
+			writew(msgs->len | ((msgs + 1)->len) << 8,
+			       i2c->base + OFFSET_TRANSFER_LEN);
+		}
 		writew(I2C_WRRD_TRANAC_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
 	} else {
 		writew(msgs->len, i2c->base + OFFSET_TRANSFER_LEN);
@@ -461,7 +472,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 
 	writel(I2C_DMA_START_EN, i2c->pdmabase + OFFSET_EN);
 
-	if (!i2c->dev_comp->auto_restart) {
+	if (!i2c->auto_restart) {
 		start_reg = I2C_TRANSAC_START;
 	} else {
 		start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG;
@@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 	if (ret)
 		return ret;
 
+	i2c->auto_restart = i2c->dev_comp->auto_restart;
+
+	/* checking if we can skip restart and optimize using WRRD mode */
+	if (i2c->auto_restart && num == 2) {
+		if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
+		    msgs[0].addr == msgs[1].addr) {
+			i2c->auto_restart = 0;
+		}
+	}
+
 	while (left_num--) {
 		if (!msgs->buf) {
 			dev_dbg(i2c->dev, "data buffer is NULL.\n");
@@ -530,7 +551,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 		else
 			i2c->op = I2C_MASTER_WR;
 
-		if (!i2c->dev_comp->auto_restart) {
+		if (!i2c->auto_restart) {
 			if (num > 1) {
 				/* combined two messages into one transaction */
 				i2c->op = I2C_MASTER_WRRD;
@@ -559,7 +580,7 @@ static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id)
 	u16 restart_flag = 0;
 	u16 intr_stat;
 
-	if (i2c->dev_comp->auto_restart)
+	if (i2c->auto_restart)
 		restart_flag = I2C_RS_TRANSFER;
 
 	intr_stat = readw(i2c->base + OFFSET_INTR_STAT);
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
  2015-11-09  5:43 ` Liguo Zhang
  (?)
@ 2015-11-09  5:43   ` Liguo Zhang
  -1 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: srv_heupstream, Matthias Brugger, Eddie Huang, Xudong Chen,
	Sascha Hauer, linux-i2c, linux-kernel, linux-arm-kernel,
	linux-mediatek, Liguo Zhang

For platform with auto restart support, when doing i2c multi transfer
in high speed, for example, doing write-then-read transfer, the master
code will occupy the first transfer, and the second transfer will be
the read transfer, the write transfer will be discarded. So we should
first send the master code, and then start i2c multi transfer.

Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
---
 drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index dc4aac6..249df86 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -53,6 +53,8 @@
 #define I2C_FS_TIME_INIT_VALUE		0x1303
 #define I2C_WRRD_TRANAC_VALUE		0x0002
 #define I2C_RD_TRANAC_VALUE		0x0001
+#define I2C_TRAN_DEFAULT_VALUE		0x0001
+#define I2C_TRANAC_DEFAULT_VALUE	0x0001
 
 #define I2C_DMA_CON_TX			0x0000
 #define I2C_DMA_CON_RX			0x0001
@@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
 	return 0;
 }
 
+static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
+{
+	int ret = 0;
+
+	reinit_completion(&i2c->msg_complete);
+
+	writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
+	       I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
+	       i2c->base + OFFSET_CONTROL);
+
+	/* Clear interrupt status */
+	writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
+	       i2c->base + OFFSET_INTR_STAT);
+
+	/* Enable interrupt */
+	writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
+	       OFFSET_INTR_MASK);
+
+	writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
+	writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
+
+	writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
+
+	ret = wait_for_completion_timeout(&i2c->msg_complete,
+					  i2c->adap.timeout);
+
+	completion_done(&i2c->msg_complete);
+
+	if (ret == 0) {
+		dev_dbg(i2c->dev, "send master code timeout.\n");
+		mtk_i2c_init_hw(i2c);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 			       int num, int left_num)
 {
@@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 		}
 	}
 
+	if (i2c->auto_restart && i2c->speed_hz > 400000) {
+		ret = mtk_i2c_send_master_code(i2c);
+		if (ret)
+			return ret;
+	}
+
 	while (left_num--) {
 		if (!msgs->buf) {
 			dev_dbg(i2c->dev, "data buffer is NULL.\n");
-- 
1.8.1.1.dirty


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-11-09  5:43   ` Liguo Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: srv_heupstream, Matthias Brugger, Eddie Huang, Xudong Chen,
	Sascha Hauer, linux-i2c, linux-kernel, linux-arm-kernel,
	linux-mediatek, Liguo Zhang

For platform with auto restart support, when doing i2c multi transfer
in high speed, for example, doing write-then-read transfer, the master
code will occupy the first transfer, and the second transfer will be
the read transfer, the write transfer will be discarded. So we should
first send the master code, and then start i2c multi transfer.

Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
---
 drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index dc4aac6..249df86 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -53,6 +53,8 @@
 #define I2C_FS_TIME_INIT_VALUE		0x1303
 #define I2C_WRRD_TRANAC_VALUE		0x0002
 #define I2C_RD_TRANAC_VALUE		0x0001
+#define I2C_TRAN_DEFAULT_VALUE		0x0001
+#define I2C_TRANAC_DEFAULT_VALUE	0x0001
 
 #define I2C_DMA_CON_TX			0x0000
 #define I2C_DMA_CON_RX			0x0001
@@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
 	return 0;
 }
 
+static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
+{
+	int ret = 0;
+
+	reinit_completion(&i2c->msg_complete);
+
+	writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
+	       I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
+	       i2c->base + OFFSET_CONTROL);
+
+	/* Clear interrupt status */
+	writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
+	       i2c->base + OFFSET_INTR_STAT);
+
+	/* Enable interrupt */
+	writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
+	       OFFSET_INTR_MASK);
+
+	writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
+	writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
+
+	writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
+
+	ret = wait_for_completion_timeout(&i2c->msg_complete,
+					  i2c->adap.timeout);
+
+	completion_done(&i2c->msg_complete);
+
+	if (ret == 0) {
+		dev_dbg(i2c->dev, "send master code timeout.\n");
+		mtk_i2c_init_hw(i2c);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 			       int num, int left_num)
 {
@@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 		}
 	}
 
+	if (i2c->auto_restart && i2c->speed_hz > 400000) {
+		ret = mtk_i2c_send_master_code(i2c);
+		if (ret)
+			return ret;
+	}
+
 	while (left_num--) {
 		if (!msgs->buf) {
 			dev_dbg(i2c->dev, "data buffer is NULL.\n");
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-11-09  5:43   ` Liguo Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang @ 2015-11-09  5:43 UTC (permalink / raw)
  To: linux-arm-kernel

For platform with auto restart support, when doing i2c multi transfer
in high speed, for example, doing write-then-read transfer, the master
code will occupy the first transfer, and the second transfer will be
the read transfer, the write transfer will be discarded. So we should
first send the master code, and then start i2c multi transfer.

Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
---
 drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index dc4aac6..249df86 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -53,6 +53,8 @@
 #define I2C_FS_TIME_INIT_VALUE		0x1303
 #define I2C_WRRD_TRANAC_VALUE		0x0002
 #define I2C_RD_TRANAC_VALUE		0x0001
+#define I2C_TRAN_DEFAULT_VALUE		0x0001
+#define I2C_TRANAC_DEFAULT_VALUE	0x0001
 
 #define I2C_DMA_CON_TX			0x0000
 #define I2C_DMA_CON_RX			0x0001
@@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
 	return 0;
 }
 
+static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
+{
+	int ret = 0;
+
+	reinit_completion(&i2c->msg_complete);
+
+	writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
+	       I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
+	       i2c->base + OFFSET_CONTROL);
+
+	/* Clear interrupt status */
+	writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
+	       i2c->base + OFFSET_INTR_STAT);
+
+	/* Enable interrupt */
+	writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
+	       OFFSET_INTR_MASK);
+
+	writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
+	writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
+
+	writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
+
+	ret = wait_for_completion_timeout(&i2c->msg_complete,
+					  i2c->adap.timeout);
+
+	completion_done(&i2c->msg_complete);
+
+	if (ret == 0) {
+		dev_dbg(i2c->dev, "send master code timeout.\n");
+		mtk_i2c_init_hw(i2c);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
 			       int num, int left_num)
 {
@@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
 		}
 	}
 
+	if (i2c->auto_restart && i2c->speed_hz > 400000) {
+		ret = mtk_i2c_send_master_code(i2c);
+		if (ret)
+			return ret;
+	}
+
 	while (left_num--) {
 		if (!msgs->buf) {
 			dev_dbg(i2c->dev, "data buffer is NULL.\n");
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
  2015-11-09  5:43   ` Liguo Zhang
@ 2015-11-09 14:25     ` Andy Shevchenko
  -1 siblings, 0 replies; 30+ messages in thread
From: Andy Shevchenko @ 2015-11-09 14:25 UTC (permalink / raw)
  To: Liguo Zhang
  Cc: Wolfram Sang, srv_heupstream, Matthias Brugger, Eddie Huang,
	Xudong Chen, Sascha Hauer, linux-i2c, linux-kernel,
	linux-arm Mailing List, linux-mediatek

On Mon, Nov 9, 2015 at 7:43 AM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> For platform with auto restart support, between every transfer,
> i2c controller will trigger an interrupt and SW need to handle
> it to start new transfer. When doing write-then-read transfer,
> instead of restart mechanism, using WRRD mode to have controller
> send both transfer in one request to reduce latency.


> @@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>         if (ret)
>                 return ret;
>
> +       i2c->auto_restart = i2c->dev_comp->auto_restart;
> +
> +       /* checking if we can skip restart and optimize using WRRD mode */
> +       if (i2c->auto_restart && num == 2) {
> +               if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
> +                   msgs[0].addr == msgs[1].addr) {

Nitpick (optional):

((msgs[0].flags & msgs[1].flags) & I2C_M_RD)
?

> +                       i2c->auto_restart = 0;
> +               }
> +       }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
@ 2015-11-09 14:25     ` Andy Shevchenko
  0 siblings, 0 replies; 30+ messages in thread
From: Andy Shevchenko @ 2015-11-09 14:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 9, 2015 at 7:43 AM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> For platform with auto restart support, between every transfer,
> i2c controller will trigger an interrupt and SW need to handle
> it to start new transfer. When doing write-then-read transfer,
> instead of restart mechanism, using WRRD mode to have controller
> send both transfer in one request to reduce latency.


> @@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>         if (ret)
>                 return ret;
>
> +       i2c->auto_restart = i2c->dev_comp->auto_restart;
> +
> +       /* checking if we can skip restart and optimize using WRRD mode */
> +       if (i2c->auto_restart && num == 2) {
> +               if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
> +                   msgs[0].addr == msgs[1].addr) {

Nitpick (optional):

((msgs[0].flags & msgs[1].flags) & I2C_M_RD)
?

> +                       i2c->auto_restart = 0;
> +               }
> +       }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
  2015-11-09 14:25     ` Andy Shevchenko
@ 2015-11-10  0:34       ` Daniel Kurtz
  -1 siblings, 0 replies; 30+ messages in thread
From: Daniel Kurtz @ 2015-11-10  0:34 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Liguo Zhang, Wolfram Sang, srv_heupstream, Matthias Brugger,
	Eddie Huang, Xudong Chen, Sascha Hauer, Linux I2C, linux-kernel,
	linux-arm Mailing List, linux-mediatek

On Mon, Nov 9, 2015 at 10:25 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Mon, Nov 9, 2015 at 7:43 AM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
>> For platform with auto restart support, between every transfer,
>> i2c controller will trigger an interrupt and SW need to handle
>> it to start new transfer. When doing write-then-read transfer,
>> instead of restart mechanism, using WRRD mode to have controller
>> send both transfer in one request to reduce latency.
>
>
>> @@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>>         if (ret)
>>                 return ret;
>>
>> +       i2c->auto_restart = i2c->dev_comp->auto_restart;
>> +
>> +       /* checking if we can skip restart and optimize using WRRD mode */
>> +       if (i2c->auto_restart && num == 2) {
>> +               if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
>> +                   msgs[0].addr == msgs[1].addr) {
>
> Nitpick (optional):
>
> ((msgs[0].flags & msgs[1].flags) & I2C_M_RD)
> ?

IMHO, this makes the code less readable.
Leave this to the compiler's optimizer.

-Dan

>
>> +                       i2c->auto_restart = 0;
>> +               }
>> +       }
>
> --
> With Best Regards,
> Andy Shevchenko
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
@ 2015-11-10  0:34       ` Daniel Kurtz
  0 siblings, 0 replies; 30+ messages in thread
From: Daniel Kurtz @ 2015-11-10  0:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 9, 2015 at 10:25 PM, Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
> On Mon, Nov 9, 2015 at 7:43 AM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
>> For platform with auto restart support, between every transfer,
>> i2c controller will trigger an interrupt and SW need to handle
>> it to start new transfer. When doing write-then-read transfer,
>> instead of restart mechanism, using WRRD mode to have controller
>> send both transfer in one request to reduce latency.
>
>
>> @@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>>         if (ret)
>>                 return ret;
>>
>> +       i2c->auto_restart = i2c->dev_comp->auto_restart;
>> +
>> +       /* checking if we can skip restart and optimize using WRRD mode */
>> +       if (i2c->auto_restart && num == 2) {
>> +               if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
>> +                   msgs[0].addr == msgs[1].addr) {
>
> Nitpick (optional):
>
> ((msgs[0].flags & msgs[1].flags) & I2C_M_RD)
> ?

IMHO, this makes the code less readable.
Leave this to the compiler's optimizer.

-Dan

>
>> +                       i2c->auto_restart = 0;
>> +               }
>> +       }
>
> --
> With Best Regards,
> Andy Shevchenko
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
  2015-11-09 14:25     ` Andy Shevchenko
  (?)
@ 2015-11-10  0:50       ` Yingjoe Chen
  -1 siblings, 0 replies; 30+ messages in thread
From: Yingjoe Chen @ 2015-11-10  0:50 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Liguo Zhang, Xudong Chen, srv_heupstream, Wolfram Sang,
	Sascha Hauer, linux-kernel, linux-mediatek, linux-i2c,
	Matthias Brugger, Eddie Huang, linux-arm Mailing List

On Mon, 2015-11-09 at 16:25 +0200, Andy Shevchenko wrote:
> On Mon, Nov 9, 2015 at 7:43 AM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, between every transfer,
> > i2c controller will trigger an interrupt and SW need to handle
> > it to start new transfer. When doing write-then-read transfer,
> > instead of restart mechanism, using WRRD mode to have controller
> > send both transfer in one request to reduce latency.
> 
> 
> > @@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >         if (ret)
> >                 return ret;
> >
> > +       i2c->auto_restart = i2c->dev_comp->auto_restart;
> > +
> > +       /* checking if we can skip restart and optimize using WRRD mode */
> > +       if (i2c->auto_restart && num == 2) {
> > +               if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
> > +                   msgs[0].addr == msgs[1].addr) {
> 
> Nitpick (optional):
> 
> ((msgs[0].flags & msgs[1].flags) & I2C_M_RD)
> ?

These 2 check for different conditions.
The original one check the first one must NOT set I2C_M_RD, but second
one must set I2C_M_RD.

Joe.C



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
@ 2015-11-10  0:50       ` Yingjoe Chen
  0 siblings, 0 replies; 30+ messages in thread
From: Yingjoe Chen @ 2015-11-10  0:50 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Liguo Zhang, Xudong Chen, srv_heupstream, Wolfram Sang,
	Sascha Hauer, linux-kernel, linux-mediatek, linux-i2c,
	Matthias Brugger, Eddie Huang, linux-arm Mailing List

On Mon, 2015-11-09 at 16:25 +0200, Andy Shevchenko wrote:
> On Mon, Nov 9, 2015 at 7:43 AM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, between every transfer,
> > i2c controller will trigger an interrupt and SW need to handle
> > it to start new transfer. When doing write-then-read transfer,
> > instead of restart mechanism, using WRRD mode to have controller
> > send both transfer in one request to reduce latency.
> 
> 
> > @@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >         if (ret)
> >                 return ret;
> >
> > +       i2c->auto_restart = i2c->dev_comp->auto_restart;
> > +
> > +       /* checking if we can skip restart and optimize using WRRD mode */
> > +       if (i2c->auto_restart && num == 2) {
> > +               if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
> > +                   msgs[0].addr == msgs[1].addr) {
> 
> Nitpick (optional):
> 
> ((msgs[0].flags & msgs[1].flags) & I2C_M_RD)
> ?

These 2 check for different conditions.
The original one check the first one must NOT set I2C_M_RD, but second
one must set I2C_M_RD.

Joe.C

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
@ 2015-11-10  0:50       ` Yingjoe Chen
  0 siblings, 0 replies; 30+ messages in thread
From: Yingjoe Chen @ 2015-11-10  0:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 2015-11-09 at 16:25 +0200, Andy Shevchenko wrote:
> On Mon, Nov 9, 2015 at 7:43 AM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, between every transfer,
> > i2c controller will trigger an interrupt and SW need to handle
> > it to start new transfer. When doing write-then-read transfer,
> > instead of restart mechanism, using WRRD mode to have controller
> > send both transfer in one request to reduce latency.
> 
> 
> > @@ -518,6 +529,16 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >         if (ret)
> >                 return ret;
> >
> > +       i2c->auto_restart = i2c->dev_comp->auto_restart;
> > +
> > +       /* checking if we can skip restart and optimize using WRRD mode */
> > +       if (i2c->auto_restart && num == 2) {
> > +               if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) &&
> > +                   msgs[0].addr == msgs[1].addr) {
> 
> Nitpick (optional):
> 
> ((msgs[0].flags & msgs[1].flags) & I2C_M_RD)
> ?

These 2 check for different conditions.
The original one check the first one must NOT set I2C_M_RD, but second
one must set I2C_M_RD.

Joe.C

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-11-14 14:38     ` Daniel Kurtz
  0 siblings, 0 replies; 30+ messages in thread
From: Daniel Kurtz @ 2015-11-14 14:38 UTC (permalink / raw)
  To: Liguo Zhang
  Cc: Wolfram Sang, srv_heupstream, Matthias Brugger, Eddie Huang,
	Xudong Chen, Sascha Hauer, Linux I2C, linux-kernel,
	linux-arm-kernel, linux-mediatek

On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> For platform with auto restart support, when doing i2c multi transfer
> in high speed, for example, doing write-then-read transfer, the master
> code will occupy the first transfer, and the second transfer will be
> the read transfer, the write transfer will be discarded. So we should
> first send the master code, and then start i2c multi transfer.
>
> Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> ---
>  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> index dc4aac6..249df86 100644
> --- a/drivers/i2c/busses/i2c-mt65xx.c
> +++ b/drivers/i2c/busses/i2c-mt65xx.c
> @@ -53,6 +53,8 @@
>  #define I2C_FS_TIME_INIT_VALUE         0x1303
>  #define I2C_WRRD_TRANAC_VALUE          0x0002
>  #define I2C_RD_TRANAC_VALUE            0x0001
> +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> +#define I2C_TRANAC_DEFAULT_VALUE       0x0001

"TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
and "TRANSAC", based on the names of the registers to which you write
these constants.

Furthermore, these are not "default" values, they are the transfer
length and number of transactions for sending the "master code", so:

#define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
#define I2C_TRANSAC_LEN_MASTER_CODE       0x0001

Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
I2C_RD_TRANAC_VALUE should also be TRANSAC.

>
>  #define I2C_DMA_CON_TX                 0x0000
>  #define I2C_DMA_CON_RX                 0x0001
> @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
>         return 0;
>  }
>
> +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> +{
> +       int ret = 0;
> +
> +       reinit_completion(&i2c->msg_complete);
> +
> +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> +              i2c->base + OFFSET_CONTROL);
> +
> +       /* Clear interrupt status */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> +              i2c->base + OFFSET_INTR_STAT);
> +
> +       /* Enable interrupt */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> +              OFFSET_INTR_MASK);
> +
> +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> +
> +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> +
> +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> +                                         i2c->adap.timeout);

How does the hardware know that this transaction should be a "master code"?
Do you have to tell the hardware what value ('00001XXX') to use as the
master code?
The Master Code must be sent at <= 400 kHz, not the target clock.  How
does the hardware know what rate to use?
When sending the master code, arbitration is supposed to occur, such
that only one winning master can proceed with the following high speed
transaction.
Where do you check that you won this arbitration?
If this is not implemented, adding a "TODO" would be helpful.

> +
> +       completion_done(&i2c->msg_complete);

This completion_done() is only useful if you check the return value.
You should check it too, since we should only check for timeout if the
message hasn't completed.

> +
> +       if (ret == 0) {
> +               dev_dbg(i2c->dev, "send master code timeout.\n");
> +               mtk_i2c_init_hw(i2c);
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
>  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
>                                int num, int left_num)
>  {
> @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>                 }
>         }
>
> +       if (i2c->auto_restart && i2c->speed_hz > 400000) {

Don't we need to send the master code for *every* HS transaction, not
just "auto_restart"?

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

> +               ret = mtk_i2c_send_master_code(i2c);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         while (left_num--) {
>                 if (!msgs->buf) {
>                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> --
> 1.8.1.1.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-11-14 14:38     ` Daniel Kurtz
  0 siblings, 0 replies; 30+ messages in thread
From: Daniel Kurtz @ 2015-11-14 14:38 UTC (permalink / raw)
  To: Liguo Zhang
  Cc: Xudong Chen, srv_heupstream, Wolfram Sang, Sascha Hauer,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Linux I2C,
	Matthias Brugger, Eddie Huang,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org> wrote:
> For platform with auto restart support, when doing i2c multi transfer
> in high speed, for example, doing write-then-read transfer, the master
> code will occupy the first transfer, and the second transfer will be
> the read transfer, the write transfer will be discarded. So we should
> first send the master code, and then start i2c multi transfer.
>
> Signed-off-by: Liguo Zhang <liguo.zhang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> Reviewed-by: Eddie Huang <eddie.huang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> ---
>  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> index dc4aac6..249df86 100644
> --- a/drivers/i2c/busses/i2c-mt65xx.c
> +++ b/drivers/i2c/busses/i2c-mt65xx.c
> @@ -53,6 +53,8 @@
>  #define I2C_FS_TIME_INIT_VALUE         0x1303
>  #define I2C_WRRD_TRANAC_VALUE          0x0002
>  #define I2C_RD_TRANAC_VALUE            0x0001
> +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> +#define I2C_TRANAC_DEFAULT_VALUE       0x0001

"TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
and "TRANSAC", based on the names of the registers to which you write
these constants.

Furthermore, these are not "default" values, they are the transfer
length and number of transactions for sending the "master code", so:

#define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
#define I2C_TRANSAC_LEN_MASTER_CODE       0x0001

Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
I2C_RD_TRANAC_VALUE should also be TRANSAC.

>
>  #define I2C_DMA_CON_TX                 0x0000
>  #define I2C_DMA_CON_RX                 0x0001
> @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
>         return 0;
>  }
>
> +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> +{
> +       int ret = 0;
> +
> +       reinit_completion(&i2c->msg_complete);
> +
> +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> +              i2c->base + OFFSET_CONTROL);
> +
> +       /* Clear interrupt status */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> +              i2c->base + OFFSET_INTR_STAT);
> +
> +       /* Enable interrupt */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> +              OFFSET_INTR_MASK);
> +
> +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> +
> +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> +
> +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> +                                         i2c->adap.timeout);

How does the hardware know that this transaction should be a "master code"?
Do you have to tell the hardware what value ('00001XXX') to use as the
master code?
The Master Code must be sent at <= 400 kHz, not the target clock.  How
does the hardware know what rate to use?
When sending the master code, arbitration is supposed to occur, such
that only one winning master can proceed with the following high speed
transaction.
Where do you check that you won this arbitration?
If this is not implemented, adding a "TODO" would be helpful.

> +
> +       completion_done(&i2c->msg_complete);

This completion_done() is only useful if you check the return value.
You should check it too, since we should only check for timeout if the
message hasn't completed.

> +
> +       if (ret == 0) {
> +               dev_dbg(i2c->dev, "send master code timeout.\n");
> +               mtk_i2c_init_hw(i2c);
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
>  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
>                                int num, int left_num)
>  {
> @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>                 }
>         }
>
> +       if (i2c->auto_restart && i2c->speed_hz > 400000) {

Don't we need to send the master code for *every* HS transaction, not
just "auto_restart"?

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

> +               ret = mtk_i2c_send_master_code(i2c);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         while (left_num--) {
>                 if (!msgs->buf) {
>                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> --
> 1.8.1.1.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-11-14 14:38     ` Daniel Kurtz
  0 siblings, 0 replies; 30+ messages in thread
From: Daniel Kurtz @ 2015-11-14 14:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> For platform with auto restart support, when doing i2c multi transfer
> in high speed, for example, doing write-then-read transfer, the master
> code will occupy the first transfer, and the second transfer will be
> the read transfer, the write transfer will be discarded. So we should
> first send the master code, and then start i2c multi transfer.
>
> Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> ---
>  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> index dc4aac6..249df86 100644
> --- a/drivers/i2c/busses/i2c-mt65xx.c
> +++ b/drivers/i2c/busses/i2c-mt65xx.c
> @@ -53,6 +53,8 @@
>  #define I2C_FS_TIME_INIT_VALUE         0x1303
>  #define I2C_WRRD_TRANAC_VALUE          0x0002
>  #define I2C_RD_TRANAC_VALUE            0x0001
> +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> +#define I2C_TRANAC_DEFAULT_VALUE       0x0001

"TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
and "TRANSAC", based on the names of the registers to which you write
these constants.

Furthermore, these are not "default" values, they are the transfer
length and number of transactions for sending the "master code", so:

#define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
#define I2C_TRANSAC_LEN_MASTER_CODE       0x0001

Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
I2C_RD_TRANAC_VALUE should also be TRANSAC.

>
>  #define I2C_DMA_CON_TX                 0x0000
>  #define I2C_DMA_CON_RX                 0x0001
> @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
>         return 0;
>  }
>
> +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> +{
> +       int ret = 0;
> +
> +       reinit_completion(&i2c->msg_complete);
> +
> +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> +              i2c->base + OFFSET_CONTROL);
> +
> +       /* Clear interrupt status */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> +              i2c->base + OFFSET_INTR_STAT);
> +
> +       /* Enable interrupt */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> +              OFFSET_INTR_MASK);
> +
> +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> +
> +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> +
> +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> +                                         i2c->adap.timeout);

How does the hardware know that this transaction should be a "master code"?
Do you have to tell the hardware what value ('00001XXX') to use as the
master code?
The Master Code must be sent at <= 400 kHz, not the target clock.  How
does the hardware know what rate to use?
When sending the master code, arbitration is supposed to occur, such
that only one winning master can proceed with the following high speed
transaction.
Where do you check that you won this arbitration?
If this is not implemented, adding a "TODO" would be helpful.

> +
> +       completion_done(&i2c->msg_complete);

This completion_done() is only useful if you check the return value.
You should check it too, since we should only check for timeout if the
message hasn't completed.

> +
> +       if (ret == 0) {
> +               dev_dbg(i2c->dev, "send master code timeout.\n");
> +               mtk_i2c_init_hw(i2c);
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
>  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
>                                int num, int left_num)
>  {
> @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>                 }
>         }
>
> +       if (i2c->auto_restart && i2c->speed_hz > 400000) {

Don't we need to send the master code for *every* HS transaction, not
just "auto_restart"?

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

> +               ret = mtk_i2c_send_master_code(i2c);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         while (left_num--) {
>                 if (!msgs->buf) {
>                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> --
> 1.8.1.1.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
  2015-11-14 14:38     ` Daniel Kurtz
  (?)
@ 2015-12-01  0:54       ` Wolfram Sang
  -1 siblings, 0 replies; 30+ messages in thread
From: Wolfram Sang @ 2015-12-01  0:54 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: Liguo Zhang, srv_heupstream, Matthias Brugger, Eddie Huang,
	Xudong Chen, Sascha Hauer, Linux I2C, linux-kernel,
	linux-arm-kernel, linux-mediatek

[-- Attachment #1: Type: text/plain, Size: 4761 bytes --]

On Sat, Nov 14, 2015 at 10:38:42PM +0800, Daniel Kurtz wrote:
> On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, when doing i2c multi transfer
> > in high speed, for example, doing write-then-read transfer, the master
> > code will occupy the first transfer, and the second transfer will be
> > the read transfer, the write transfer will be discarded. So we should
> > first send the master code, and then start i2c multi transfer.
> >
> > Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> > Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> > ---
> >  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 45 insertions(+)
> >
> > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> > index dc4aac6..249df86 100644
> > --- a/drivers/i2c/busses/i2c-mt65xx.c
> > +++ b/drivers/i2c/busses/i2c-mt65xx.c
> > @@ -53,6 +53,8 @@
> >  #define I2C_FS_TIME_INIT_VALUE         0x1303
> >  #define I2C_WRRD_TRANAC_VALUE          0x0002
> >  #define I2C_RD_TRANAC_VALUE            0x0001
> > +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> > +#define I2C_TRANAC_DEFAULT_VALUE       0x0001
> 
> "TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
> and "TRANSAC", based on the names of the registers to which you write
> these constants.
> 
> Furthermore, these are not "default" values, they are the transfer
> length and number of transactions for sending the "master code", so:
> 
> #define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
> #define I2C_TRANSAC_LEN_MASTER_CODE       0x0001
> 
> Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
> I2C_RD_TRANAC_VALUE should also be TRANSAC.
> 
> >
> >  #define I2C_DMA_CON_TX                 0x0000
> >  #define I2C_DMA_CON_RX                 0x0001
> > @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
> >         return 0;
> >  }
> >
> > +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> > +{
> > +       int ret = 0;
> > +
> > +       reinit_completion(&i2c->msg_complete);
> > +
> > +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> > +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> > +              i2c->base + OFFSET_CONTROL);
> > +
> > +       /* Clear interrupt status */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> > +              i2c->base + OFFSET_INTR_STAT);
> > +
> > +       /* Enable interrupt */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> > +              OFFSET_INTR_MASK);
> > +
> > +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> > +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> > +
> > +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> > +
> > +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> > +                                         i2c->adap.timeout);
> 
> How does the hardware know that this transaction should be a "master code"?
> Do you have to tell the hardware what value ('00001XXX') to use as the
> master code?
> The Master Code must be sent at <= 400 kHz, not the target clock.  How
> does the hardware know what rate to use?
> When sending the master code, arbitration is supposed to occur, such
> that only one winning master can proceed with the following high speed
> transaction.
> Where do you check that you won this arbitration?
> If this is not implemented, adding a "TODO" would be helpful.
> 
> > +
> > +       completion_done(&i2c->msg_complete);
> 
> This completion_done() is only useful if you check the return value.
> You should check it too, since we should only check for timeout if the
> message hasn't completed.
> 
> > +
> > +       if (ret == 0) {
> > +               dev_dbg(i2c->dev, "send master code timeout.\n");
> > +               mtk_i2c_init_hw(i2c);
> > +               return -ETIMEDOUT;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
> >                                int num, int left_num)
> >  {
> > @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >                 }
> >         }
> >
> > +       if (i2c->auto_restart && i2c->speed_hz > 400000) {
> 
> Don't we need to send the master code for *every* HS transaction, not
> just "auto_restart"?
> 
> "400000" => You already have a macro for this: MAX_FS_MODE_SPEED

Please address Daniel's comments and questions.

Thanks!


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-12-01  0:54       ` Wolfram Sang
  0 siblings, 0 replies; 30+ messages in thread
From: Wolfram Sang @ 2015-12-01  0:54 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: Liguo Zhang, srv_heupstream, Matthias Brugger, Eddie Huang,
	Xudong Chen, Sascha Hauer, Linux I2C, linux-kernel,
	linux-arm-kernel, linux-mediatek

[-- Attachment #1: Type: text/plain, Size: 4761 bytes --]

On Sat, Nov 14, 2015 at 10:38:42PM +0800, Daniel Kurtz wrote:
> On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, when doing i2c multi transfer
> > in high speed, for example, doing write-then-read transfer, the master
> > code will occupy the first transfer, and the second transfer will be
> > the read transfer, the write transfer will be discarded. So we should
> > first send the master code, and then start i2c multi transfer.
> >
> > Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> > Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> > ---
> >  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 45 insertions(+)
> >
> > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> > index dc4aac6..249df86 100644
> > --- a/drivers/i2c/busses/i2c-mt65xx.c
> > +++ b/drivers/i2c/busses/i2c-mt65xx.c
> > @@ -53,6 +53,8 @@
> >  #define I2C_FS_TIME_INIT_VALUE         0x1303
> >  #define I2C_WRRD_TRANAC_VALUE          0x0002
> >  #define I2C_RD_TRANAC_VALUE            0x0001
> > +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> > +#define I2C_TRANAC_DEFAULT_VALUE       0x0001
> 
> "TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
> and "TRANSAC", based on the names of the registers to which you write
> these constants.
> 
> Furthermore, these are not "default" values, they are the transfer
> length and number of transactions for sending the "master code", so:
> 
> #define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
> #define I2C_TRANSAC_LEN_MASTER_CODE       0x0001
> 
> Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
> I2C_RD_TRANAC_VALUE should also be TRANSAC.
> 
> >
> >  #define I2C_DMA_CON_TX                 0x0000
> >  #define I2C_DMA_CON_RX                 0x0001
> > @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
> >         return 0;
> >  }
> >
> > +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> > +{
> > +       int ret = 0;
> > +
> > +       reinit_completion(&i2c->msg_complete);
> > +
> > +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> > +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> > +              i2c->base + OFFSET_CONTROL);
> > +
> > +       /* Clear interrupt status */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> > +              i2c->base + OFFSET_INTR_STAT);
> > +
> > +       /* Enable interrupt */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> > +              OFFSET_INTR_MASK);
> > +
> > +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> > +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> > +
> > +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> > +
> > +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> > +                                         i2c->adap.timeout);
> 
> How does the hardware know that this transaction should be a "master code"?
> Do you have to tell the hardware what value ('00001XXX') to use as the
> master code?
> The Master Code must be sent at <= 400 kHz, not the target clock.  How
> does the hardware know what rate to use?
> When sending the master code, arbitration is supposed to occur, such
> that only one winning master can proceed with the following high speed
> transaction.
> Where do you check that you won this arbitration?
> If this is not implemented, adding a "TODO" would be helpful.
> 
> > +
> > +       completion_done(&i2c->msg_complete);
> 
> This completion_done() is only useful if you check the return value.
> You should check it too, since we should only check for timeout if the
> message hasn't completed.
> 
> > +
> > +       if (ret == 0) {
> > +               dev_dbg(i2c->dev, "send master code timeout.\n");
> > +               mtk_i2c_init_hw(i2c);
> > +               return -ETIMEDOUT;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
> >                                int num, int left_num)
> >  {
> > @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >                 }
> >         }
> >
> > +       if (i2c->auto_restart && i2c->speed_hz > 400000) {
> 
> Don't we need to send the master code for *every* HS transaction, not
> just "auto_restart"?
> 
> "400000" => You already have a macro for this: MAX_FS_MODE_SPEED

Please address Daniel's comments and questions.

Thanks!


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-12-01  0:54       ` Wolfram Sang
  0 siblings, 0 replies; 30+ messages in thread
From: Wolfram Sang @ 2015-12-01  0:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Nov 14, 2015 at 10:38:42PM +0800, Daniel Kurtz wrote:
> On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, when doing i2c multi transfer
> > in high speed, for example, doing write-then-read transfer, the master
> > code will occupy the first transfer, and the second transfer will be
> > the read transfer, the write transfer will be discarded. So we should
> > first send the master code, and then start i2c multi transfer.
> >
> > Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> > Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> > ---
> >  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 45 insertions(+)
> >
> > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> > index dc4aac6..249df86 100644
> > --- a/drivers/i2c/busses/i2c-mt65xx.c
> > +++ b/drivers/i2c/busses/i2c-mt65xx.c
> > @@ -53,6 +53,8 @@
> >  #define I2C_FS_TIME_INIT_VALUE         0x1303
> >  #define I2C_WRRD_TRANAC_VALUE          0x0002
> >  #define I2C_RD_TRANAC_VALUE            0x0001
> > +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> > +#define I2C_TRANAC_DEFAULT_VALUE       0x0001
> 
> "TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
> and "TRANSAC", based on the names of the registers to which you write
> these constants.
> 
> Furthermore, these are not "default" values, they are the transfer
> length and number of transactions for sending the "master code", so:
> 
> #define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
> #define I2C_TRANSAC_LEN_MASTER_CODE       0x0001
> 
> Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
> I2C_RD_TRANAC_VALUE should also be TRANSAC.
> 
> >
> >  #define I2C_DMA_CON_TX                 0x0000
> >  #define I2C_DMA_CON_RX                 0x0001
> > @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
> >         return 0;
> >  }
> >
> > +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> > +{
> > +       int ret = 0;
> > +
> > +       reinit_completion(&i2c->msg_complete);
> > +
> > +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> > +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> > +              i2c->base + OFFSET_CONTROL);
> > +
> > +       /* Clear interrupt status */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> > +              i2c->base + OFFSET_INTR_STAT);
> > +
> > +       /* Enable interrupt */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> > +              OFFSET_INTR_MASK);
> > +
> > +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> > +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> > +
> > +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> > +
> > +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> > +                                         i2c->adap.timeout);
> 
> How does the hardware know that this transaction should be a "master code"?
> Do you have to tell the hardware what value ('00001XXX') to use as the
> master code?
> The Master Code must be sent at <= 400 kHz, not the target clock.  How
> does the hardware know what rate to use?
> When sending the master code, arbitration is supposed to occur, such
> that only one winning master can proceed with the following high speed
> transaction.
> Where do you check that you won this arbitration?
> If this is not implemented, adding a "TODO" would be helpful.
> 
> > +
> > +       completion_done(&i2c->msg_complete);
> 
> This completion_done() is only useful if you check the return value.
> You should check it too, since we should only check for timeout if the
> message hasn't completed.
> 
> > +
> > +       if (ret == 0) {
> > +               dev_dbg(i2c->dev, "send master code timeout.\n");
> > +               mtk_i2c_init_hw(i2c);
> > +               return -ETIMEDOUT;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
> >                                int num, int left_num)
> >  {
> > @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >                 }
> >         }
> >
> > +       if (i2c->auto_restart && i2c->speed_hz > 400000) {
> 
> Don't we need to send the master code for *every* HS transaction, not
> just "auto_restart"?
> 
> "400000" => You already have a macro for this: MAX_FS_MODE_SPEED

Please address Daniel's comments and questions.

Thanks!

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20151201/8df0fc2b/attachment.sig>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
  2015-11-09  5:43   ` Liguo Zhang
@ 2015-12-01  0:56     ` Wolfram Sang
  -1 siblings, 0 replies; 30+ messages in thread
From: Wolfram Sang @ 2015-12-01  0:56 UTC (permalink / raw)
  To: Liguo Zhang
  Cc: srv_heupstream, Matthias Brugger, Eddie Huang, Xudong Chen,
	Sascha Hauer, linux-i2c, linux-kernel, linux-arm-kernel,
	linux-mediatek

[-- Attachment #1: Type: text/plain, Size: 535 bytes --]

On Mon, Nov 09, 2015 at 01:43:58PM +0800, Liguo Zhang wrote:
> For platform with auto restart support, between every transfer,
> i2c controller will trigger an interrupt and SW need to handle
> it to start new transfer. When doing write-then-read transfer,
> instead of restart mechanism, using WRRD mode to have controller
> send both transfer in one request to reduce latency.
> 
> Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>

Applied to for-next, thanks!


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization
@ 2015-12-01  0:56     ` Wolfram Sang
  0 siblings, 0 replies; 30+ messages in thread
From: Wolfram Sang @ 2015-12-01  0:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 09, 2015 at 01:43:58PM +0800, Liguo Zhang wrote:
> For platform with auto restart support, between every transfer,
> i2c controller will trigger an interrupt and SW need to handle
> it to start new transfer. When doing write-then-read transfer,
> instead of restart mechanism, using WRRD mode to have controller
> send both transfer in one request to reduce latency.
> 
> Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>

Applied to for-next, thanks!

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20151201/e1db99ff/attachment.sig>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* RE: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
  2015-11-14 14:38     ` Daniel Kurtz
  (?)
@ 2015-12-01 11:24       ` Liguo Zhang (张立国)
  -1 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang (张立国) @ 2015-12-01 11:24 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: Wolfram Sang, srv_heupstream, Matthias Brugger,
	Eddie Huang (黃智傑),
	Xudong Chen (陈旭东),
	Sascha Hauer, Linux I2C, linux-kernel, linux-arm-kernel,
	linux-mediatek, Jun Gao (高俊),
	Yingjoe Chen (陳英洲)

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 6746 bytes --]

Dear Daniel,

1. I will rename "TRAN" & "TRANAC" & "I2C_TRAN_DEFAULT_VALUE" & "I2C_TRAN_DEFAULT_VALUE".

2. How does the hardware know that this transaction should be a "master code"?
When we set i2c speed > 400K , the hardware will send master code. We have a register to configure master code,and usually we use the default value "00001000".

How does the hardware know what rate to use?
The i2c speed is defined in dts, and we will set the i2c speed in i2c register, so HW will know the rate to use.

When sending the master code, arbitration is supposed to occur, such that only one winning master can proceed with the following high speed transaction.
Where do you check that you won this arbitration?
Our i2c driver now only support one master.

3. I will delete the completion_done() function.

4. Don't we need to send the master code for *every* HS transaction, not just "auto_restart"?
When we don't use auto restart, we also need to send the master code, the master code is sent by HW automatically.
I am improving the master code section when use auto restart, and this will be released in the next patch.

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

Yes, I will use MAX_FS_MODE_SPEED.

Thanks!

-----Original Message-----
From: djkurtz@google.com [mailto:djkurtz@google.com] On Behalf Of Daniel Kurtz
Sent: 2015年11月14日 22:39
To: Liguo Zhang (张立国)
Cc: Wolfram Sang; srv_heupstream; Matthias Brugger; Eddie Huang (黃智傑); Xudong Chen (陈旭东); Sascha Hauer; Linux I2C; linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org
Subject: Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode

On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> For platform with auto restart support, when doing i2c multi transfer 
> in high speed, for example, doing write-then-read transfer, the master 
> code will occupy the first transfer, and the second transfer will be 
> the read transfer, the write transfer will be discarded. So we should 
> first send the master code, and then start i2c multi transfer.
>
> Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> ---
>  drivers/i2c/busses/i2c-mt65xx.c | 45 
> +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-mt65xx.c 
> b/drivers/i2c/busses/i2c-mt65xx.c index dc4aac6..249df86 100644
> --- a/drivers/i2c/busses/i2c-mt65xx.c
> +++ b/drivers/i2c/busses/i2c-mt65xx.c
> @@ -53,6 +53,8 @@
>  #define I2C_FS_TIME_INIT_VALUE         0x1303
>  #define I2C_WRRD_TRANAC_VALUE          0x0002
>  #define I2C_RD_TRANAC_VALUE            0x0001
> +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> +#define I2C_TRAN_DEFAULT_VALUE       0x0001

"TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
and "TRANSAC", based on the names of the registers to which you write these constants.

Furthermore, these are not "default" values, they are the transfer length and number of transactions for sending the "master code", so:

#define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
#define I2C_TRANSAC_LEN_MASTER_CODE       0x0001

Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and I2C_RD_TRANAC_VALUE should also be TRANSAC.

>
>  #define I2C_DMA_CON_TX                 0x0000
>  #define I2C_DMA_CON_RX                 0x0001
> @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
>         return 0;
>  }
>
> +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c) {
> +       int ret = 0;
> +
> +       reinit_completion(&i2c->msg_complete);
> +
> +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> +              i2c->base + OFFSET_CONTROL);
> +
> +       /* Clear interrupt status */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> +              i2c->base + OFFSET_INTR_STAT);
> +
> +       /* Enable interrupt */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> +              OFFSET_INTR_MASK);
> +
> +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + 
> + OFFSET_TRANSAC_LEN);
> +
> +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + 
> + OFFSET_START);
> +
> +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> +                                         i2c->adap.timeout);

How does the hardware know that this transaction should be a "master code"?
Do you have to tell the hardware what value ('00001XXX') to use as the master code?
The Master Code must be sent at <= 400 kHz, not the target clock.  How does the hardware know what rate to use?
When sending the master code, arbitration is supposed to occur, such that only one winning master can proceed with the following high speed transaction.
Where do you check that you won this arbitration?
If this is not implemented, adding a "TODO" would be helpful.

> +
> +       completion_done(&i2c->msg_complete);

This completion_done() is only useful if you check the return value.
You should check it too, since we should only check for timeout if the message hasn't completed.

> +
> +       if (ret == 0) {
> +               dev_dbg(i2c->dev, "send master code timeout.\n");
> +               mtk_i2c_init_hw(i2c);
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
>  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
>                                int num, int left_num)  { @@ -539,6 
> +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>                 }
>         }
>
> +       if (i2c->auto_restart && i2c->speed_hz > 400000) {

Don't we need to send the master code for *every* HS transaction, not just "auto_restart"?

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

> +               ret = mtk_i2c_send_master_code(i2c);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         while (left_num--) {
>                 if (!msgs->buf) {
>                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> --
> 1.8.1.1.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-kernel" in the body of a message to majordomo@vger.kernel.org 
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 30+ messages in thread

* RE: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-12-01 11:24       ` Liguo Zhang (张立国)
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang (张立国) @ 2015-12-01 11:24 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: Wolfram Sang, srv_heupstream, Matthias Brugger,
	Eddie Huang (黃智傑),
	Xudong Chen (陈旭东),
	Sascha Hauer, Linux I2C, linux-kernel, linux-arm-kernel,
	linux-mediatek, Jun Gao (高俊),
	Yingjoe Chen (陳英洲)

Dear Daniel,

1. I will rename "TRAN" & "TRANAC" & "I2C_TRAN_DEFAULT_VALUE" & "I2C_TRAN_DEFAULT_VALUE".

2. How does the hardware know that this transaction should be a "master code"?
When we set i2c speed > 400K , the hardware will send master code. We have a register to configure master code,and usually we use the default value "00001000".

How does the hardware know what rate to use?
The i2c speed is defined in dts, and we will set the i2c speed in i2c register, so HW will know the rate to use.

When sending the master code, arbitration is supposed to occur, such that only one winning master can proceed with the following high speed transaction.
Where do you check that you won this arbitration?
Our i2c driver now only support one master.

3. I will delete the completion_done() function.

4. Don't we need to send the master code for *every* HS transaction, not just "auto_restart"?
When we don't use auto restart, we also need to send the master code, the master code is sent by HW automatically.
I am improving the master code section when use auto restart, and this will be released in the next patch.

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

Yes, I will use MAX_FS_MODE_SPEED.

Thanks!

-----Original Message-----
From: djkurtz@google.com [mailto:djkurtz@google.com] On Behalf Of Daniel Kurtz
Sent: 2015年11月14日 22:39
To: Liguo Zhang (张立国)
Cc: Wolfram Sang; srv_heupstream; Matthias Brugger; Eddie Huang (黃智傑); Xudong Chen (陈旭东); Sascha Hauer; Linux I2C; linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-mediatek@lists.infradead.org
Subject: Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode

On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> For platform with auto restart support, when doing i2c multi transfer 
> in high speed, for example, doing write-then-read transfer, the master 
> code will occupy the first transfer, and the second transfer will be 
> the read transfer, the write transfer will be discarded. So we should 
> first send the master code, and then start i2c multi transfer.
>
> Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> ---
>  drivers/i2c/busses/i2c-mt65xx.c | 45 
> +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-mt65xx.c 
> b/drivers/i2c/busses/i2c-mt65xx.c index dc4aac6..249df86 100644
> --- a/drivers/i2c/busses/i2c-mt65xx.c
> +++ b/drivers/i2c/busses/i2c-mt65xx.c
> @@ -53,6 +53,8 @@
>  #define I2C_FS_TIME_INIT_VALUE         0x1303
>  #define I2C_WRRD_TRANAC_VALUE          0x0002
>  #define I2C_RD_TRANAC_VALUE            0x0001
> +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> +#define I2C_TRAN_DEFAULT_VALUE       0x0001

"TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
and "TRANSAC", based on the names of the registers to which you write these constants.

Furthermore, these are not "default" values, they are the transfer length and number of transactions for sending the "master code", so:

#define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
#define I2C_TRANSAC_LEN_MASTER_CODE       0x0001

Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and I2C_RD_TRANAC_VALUE should also be TRANSAC.

>
>  #define I2C_DMA_CON_TX                 0x0000
>  #define I2C_DMA_CON_RX                 0x0001
> @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
>         return 0;
>  }
>
> +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c) {
> +       int ret = 0;
> +
> +       reinit_completion(&i2c->msg_complete);
> +
> +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> +              i2c->base + OFFSET_CONTROL);
> +
> +       /* Clear interrupt status */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> +              i2c->base + OFFSET_INTR_STAT);
> +
> +       /* Enable interrupt */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> +              OFFSET_INTR_MASK);
> +
> +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + 
> + OFFSET_TRANSAC_LEN);
> +
> +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + 
> + OFFSET_START);
> +
> +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> +                                         i2c->adap.timeout);

How does the hardware know that this transaction should be a "master code"?
Do you have to tell the hardware what value ('00001XXX') to use as the master code?
The Master Code must be sent at <= 400 kHz, not the target clock.  How does the hardware know what rate to use?
When sending the master code, arbitration is supposed to occur, such that only one winning master can proceed with the following high speed transaction.
Where do you check that you won this arbitration?
If this is not implemented, adding a "TODO" would be helpful.

> +
> +       completion_done(&i2c->msg_complete);

This completion_done() is only useful if you check the return value.
You should check it too, since we should only check for timeout if the message hasn't completed.

> +
> +       if (ret == 0) {
> +               dev_dbg(i2c->dev, "send master code timeout.\n");
> +               mtk_i2c_init_hw(i2c);
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
>  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
>                                int num, int left_num)  { @@ -539,6 
> +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>                 }
>         }
>
> +       if (i2c->auto_restart && i2c->speed_hz > 400000) {

Don't we need to send the master code for *every* HS transaction, not just "auto_restart"?

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

> +               ret = mtk_i2c_send_master_code(i2c);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         while (left_num--) {
>                 if (!msgs->buf) {
>                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> --
> 1.8.1.1.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-kernel" in the body of a message to majordomo@vger.kernel.org 
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

************* Email Confidentiality Notice ********************
The information contained in this e-mail message (including any 
attachments) may be confidential, proprietary, privileged, or otherwise
exempt from disclosure under applicable laws. It is intended to be 
conveyed only to the designated recipient(s). Any use, dissemination, 
distribution, printing, retaining or copying of this e-mail (including its 
attachments) by unintended recipient(s) is strictly prohibited and may 
be unlawful. If you are not an intended recipient of this e-mail, or believe 
that you have received this e-mail in error, please notify the sender 
immediately (by replying to this e-mail), delete any and all copies of 
this e-mail (including any attachments) from your system, and do not
disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-12-01 11:24       ` Liguo Zhang (张立国)
  0 siblings, 0 replies; 30+ messages in thread
From: Liguo Zhang (张立国) @ 2015-12-01 11:24 UTC (permalink / raw)
  To: linux-arm-kernel

Dear Daniel,

1. I will rename "TRAN" & "TRANAC" & "I2C_TRAN_DEFAULT_VALUE" & "I2C_TRAN_DEFAULT_VALUE".

2. How does the hardware know that this transaction should be a "master code"?
When we set i2c speed > 400K , the hardware will send master code. We have a register to configure master code?and usually we use the default value "00001000".

How does the hardware know what rate to use?
The i2c speed is defined in dts, and we will set the i2c speed in i2c register, so HW will know the rate to use.

When sending the master code, arbitration is supposed to occur, such that only one winning master can proceed with the following high speed transaction.
Where do you check that you won this arbitration?
Our i2c driver now only support one master.

3. I will delete the completion_done() function.

4. Don't we need to send the master code for *every* HS transaction, not just "auto_restart"?
When we don't use auto restart, we also need to send the master code, the master code is sent by HW automatically.
I am improving the master code section when use auto restart, and this will be released in the next patch.

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

Yes, I will use MAX_FS_MODE_SPEED.

Thanks!

-----Original Message-----
From: djkurtz@google.com [mailto:djkurtz at google.com] On Behalf Of Daniel Kurtz
Sent: 2015?11?14? 22:39
To: Liguo Zhang (???)
Cc: Wolfram Sang; srv_heupstream; Matthias Brugger; Eddie Huang (???); Xudong Chen (???); Sascha Hauer; Linux I2C; linux-kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-mediatek at lists.infradead.org
Subject: Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode

On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> For platform with auto restart support, when doing i2c multi transfer 
> in high speed, for example, doing write-then-read transfer, the master 
> code will occupy the first transfer, and the second transfer will be 
> the read transfer, the write transfer will be discarded. So we should 
> first send the master code, and then start i2c multi transfer.
>
> Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> ---
>  drivers/i2c/busses/i2c-mt65xx.c | 45 
> +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>
> diff --git a/drivers/i2c/busses/i2c-mt65xx.c 
> b/drivers/i2c/busses/i2c-mt65xx.c index dc4aac6..249df86 100644
> --- a/drivers/i2c/busses/i2c-mt65xx.c
> +++ b/drivers/i2c/busses/i2c-mt65xx.c
> @@ -53,6 +53,8 @@
>  #define I2C_FS_TIME_INIT_VALUE         0x1303
>  #define I2C_WRRD_TRANAC_VALUE          0x0002
>  #define I2C_RD_TRANAC_VALUE            0x0001
> +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> +#define I2C_TRAN_DEFAULT_VALUE       0x0001

"TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
and "TRANSAC", based on the names of the registers to which you write these constants.

Furthermore, these are not "default" values, they are the transfer length and number of transactions for sending the "master code", so:

#define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
#define I2C_TRANSAC_LEN_MASTER_CODE       0x0001

Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and I2C_RD_TRANAC_VALUE should also be TRANSAC.

>
>  #define I2C_DMA_CON_TX                 0x0000
>  #define I2C_DMA_CON_RX                 0x0001
> @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
>         return 0;
>  }
>
> +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c) {
> +       int ret = 0;
> +
> +       reinit_completion(&i2c->msg_complete);
> +
> +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> +              i2c->base + OFFSET_CONTROL);
> +
> +       /* Clear interrupt status */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> +              i2c->base + OFFSET_INTR_STAT);
> +
> +       /* Enable interrupt */
> +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> +              OFFSET_INTR_MASK);
> +
> +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + 
> + OFFSET_TRANSAC_LEN);
> +
> +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + 
> + OFFSET_START);
> +
> +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> +                                         i2c->adap.timeout);

How does the hardware know that this transaction should be a "master code"?
Do you have to tell the hardware what value ('00001XXX') to use as the master code?
The Master Code must be sent at <= 400 kHz, not the target clock.  How does the hardware know what rate to use?
When sending the master code, arbitration is supposed to occur, such that only one winning master can proceed with the following high speed transaction.
Where do you check that you won this arbitration?
If this is not implemented, adding a "TODO" would be helpful.

> +
> +       completion_done(&i2c->msg_complete);

This completion_done() is only useful if you check the return value.
You should check it too, since we should only check for timeout if the message hasn't completed.

> +
> +       if (ret == 0) {
> +               dev_dbg(i2c->dev, "send master code timeout.\n");
> +               mtk_i2c_init_hw(i2c);
> +               return -ETIMEDOUT;
> +       }
> +
> +       return 0;
> +}
> +
>  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
>                                int num, int left_num)  { @@ -539,6 
> +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
>                 }
>         }
>
> +       if (i2c->auto_restart && i2c->speed_hz > 400000) {

Don't we need to send the master code for *every* HS transaction, not just "auto_restart"?

"400000" => You already have a macro for this: MAX_FS_MODE_SPEED

> +               ret = mtk_i2c_send_master_code(i2c);
> +               if (ret)
> +                       return ret;
> +       }
> +
>         while (left_num--) {
>                 if (!msgs->buf) {
>                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> --
> 1.8.1.1.dirty
>
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-kernel" in the body of a message to majordomo at vger.kernel.org 
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

************* Email Confidentiality Notice ********************
The information contained in this e-mail message (including any 
attachments) may be confidential, proprietary, privileged, or otherwise
exempt from disclosure under applicable laws. It is intended to be 
conveyed only to the designated recipient(s). Any use, dissemination, 
distribution, printing, retaining or copying of this e-mail (including its 
attachments) by unintended recipient(s) is strictly prohibited and may 
be unlawful. If you are not an intended recipient of this e-mail, or believe 
that you have received this e-mail in error, please notify the sender 
immediately (by replying to this e-mail), delete any and all copies of 
this e-mail (including any attachments) from your system, and do not
disclose the content of this e-mail to any other person. Thank you!

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
  2015-11-14 14:38     ` Daniel Kurtz
  (?)
@ 2015-12-02  2:51       ` liguo zhang
  -1 siblings, 0 replies; 30+ messages in thread
From: liguo zhang @ 2015-12-02  2:51 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: Wolfram Sang, srv_heupstream, Matthias Brugger, Eddie Huang,
	Xudong Chen, Sascha Hauer, Linux I2C, linux-kernel,
	linux-arm-kernel, linux-mediatek

On Sat, 2015-11-14 at 22:38 +0800, Daniel Kurtz wrote:
> On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, when doing i2c multi transfer
> > in high speed, for example, doing write-then-read transfer, the master
> > code will occupy the first transfer, and the second transfer will be
> > the read transfer, the write transfer will be discarded. So we should
> > first send the master code, and then start i2c multi transfer.
> >
> > Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> > Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> > ---
> >  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 45 insertions(+)
> >
> > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> > index dc4aac6..249df86 100644
> > --- a/drivers/i2c/busses/i2c-mt65xx.c
> > +++ b/drivers/i2c/busses/i2c-mt65xx.c
> > @@ -53,6 +53,8 @@
> >  #define I2C_FS_TIME_INIT_VALUE         0x1303
> >  #define I2C_WRRD_TRANAC_VALUE          0x0002
> >  #define I2C_RD_TRANAC_VALUE            0x0001
> > +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> > +#define I2C_TRANAC_DEFAULT_VALUE       0x0001
> 
> "TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
> and "TRANSAC", based on the names of the registers to which you write
> these constants.
> 
> Furthermore, these are not "default" values, they are the transfer
> length and number of transactions for sending the "master code", so:
> 
> #define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
> #define I2C_TRANSAC_LEN_MASTER_CODE       0x0001
> 
> Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
> I2C_RD_TRANAC_VALUE should also be TRANSAC.
> 

Yes, I will follow your advice.

> >
> >  #define I2C_DMA_CON_TX                 0x0000
> >  #define I2C_DMA_CON_RX                 0x0001
> > @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
> >         return 0;
> >  }
> >
> > +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> > +{
> > +       int ret = 0;
> > +
> > +       reinit_completion(&i2c->msg_complete);
> > +
> > +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> > +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> > +              i2c->base + OFFSET_CONTROL);
> > +
> > +       /* Clear interrupt status */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> > +              i2c->base + OFFSET_INTR_STAT);
> > +
> > +       /* Enable interrupt */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> > +              OFFSET_INTR_MASK);
> > +
> > +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> > +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> > +
> > +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> > +
> > +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> > +                                         i2c->adap.timeout);
> 
> How does the hardware know that this transaction should be a "master code"?
> Do you have to tell the hardware what value ('00001XXX') to use as the
> master code?

When we set i2c speed > 400K , the hardware will send master code. We
have a register to configure master code,and usually we use the default
value "00001000".

> The Master Code must be sent at <= 400 kHz, not the target clock.  How
> does the hardware know what rate to use?

The i2c speed is defined in dts, and we will set the i2c speed in i2c
register, so HW will know the rate to use.

> When sending the master code, arbitration is supposed to occur, such
> that only one winning master can proceed with the following high speed
> transaction.
> Where do you check that you won this arbitration?

> If this is not implemented, adding a "TODO" would be helpful.
> 
Our i2c driver now only support one master.

> > +
> > +       completion_done(&i2c->msg_complete);
> 
> This completion_done() is only useful if you check the return value.
> You should check it too, since we should only check for timeout if the
> message hasn't completed.
> 
I will delete the completion_done() function.

> > +
> > +       if (ret == 0) {
> > +               dev_dbg(i2c->dev, "send master code timeout.\n");
> > +               mtk_i2c_init_hw(i2c);
> > +               return -ETIMEDOUT;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
> >                                int num, int left_num)
> >  {
> > @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >                 }
> >         }
> >
> > +       if (i2c->auto_restart && i2c->speed_hz > 400000) {
> 
> Don't we need to send the master code for *every* HS transaction, not
> just "auto_restart"?
> 
When we don't use auto restart, we also need to send the master code,
the master code is sent by HW automatically.
I am improving the master code section when use auto restart, and this
will be released in the next patch.

> "400000" => You already have a macro for this: MAX_FS_MODE_SPEED
> 
Yes, I will use MAX_FS_MODE_SPEED.

> > +               ret = mtk_i2c_send_master_code(i2c);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> >         while (left_num--) {
> >                 if (!msgs->buf) {
> >                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> > --
> > 1.8.1.1.dirty
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/



^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-12-02  2:51       ` liguo zhang
  0 siblings, 0 replies; 30+ messages in thread
From: liguo zhang @ 2015-12-02  2:51 UTC (permalink / raw)
  To: Daniel Kurtz
  Cc: Wolfram Sang, srv_heupstream, Matthias Brugger, Eddie Huang,
	Xudong Chen, Sascha Hauer, Linux I2C, linux-kernel,
	linux-arm-kernel, linux-mediatek

On Sat, 2015-11-14 at 22:38 +0800, Daniel Kurtz wrote:
> On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, when doing i2c multi transfer
> > in high speed, for example, doing write-then-read transfer, the master
> > code will occupy the first transfer, and the second transfer will be
> > the read transfer, the write transfer will be discarded. So we should
> > first send the master code, and then start i2c multi transfer.
> >
> > Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> > Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> > ---
> >  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 45 insertions(+)
> >
> > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> > index dc4aac6..249df86 100644
> > --- a/drivers/i2c/busses/i2c-mt65xx.c
> > +++ b/drivers/i2c/busses/i2c-mt65xx.c
> > @@ -53,6 +53,8 @@
> >  #define I2C_FS_TIME_INIT_VALUE         0x1303
> >  #define I2C_WRRD_TRANAC_VALUE          0x0002
> >  #define I2C_RD_TRANAC_VALUE            0x0001
> > +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> > +#define I2C_TRANAC_DEFAULT_VALUE       0x0001
> 
> "TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
> and "TRANSAC", based on the names of the registers to which you write
> these constants.
> 
> Furthermore, these are not "default" values, they are the transfer
> length and number of transactions for sending the "master code", so:
> 
> #define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
> #define I2C_TRANSAC_LEN_MASTER_CODE       0x0001
> 
> Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
> I2C_RD_TRANAC_VALUE should also be TRANSAC.
> 

Yes, I will follow your advice.

> >
> >  #define I2C_DMA_CON_TX                 0x0000
> >  #define I2C_DMA_CON_RX                 0x0001
> > @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
> >         return 0;
> >  }
> >
> > +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> > +{
> > +       int ret = 0;
> > +
> > +       reinit_completion(&i2c->msg_complete);
> > +
> > +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> > +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> > +              i2c->base + OFFSET_CONTROL);
> > +
> > +       /* Clear interrupt status */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> > +              i2c->base + OFFSET_INTR_STAT);
> > +
> > +       /* Enable interrupt */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> > +              OFFSET_INTR_MASK);
> > +
> > +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> > +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> > +
> > +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> > +
> > +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> > +                                         i2c->adap.timeout);
> 
> How does the hardware know that this transaction should be a "master code"?
> Do you have to tell the hardware what value ('00001XXX') to use as the
> master code?

When we set i2c speed > 400K , the hardware will send master code. We
have a register to configure master code,and usually we use the default
value "00001000".

> The Master Code must be sent at <= 400 kHz, not the target clock.  How
> does the hardware know what rate to use?

The i2c speed is defined in dts, and we will set the i2c speed in i2c
register, so HW will know the rate to use.

> When sending the master code, arbitration is supposed to occur, such
> that only one winning master can proceed with the following high speed
> transaction.
> Where do you check that you won this arbitration?

> If this is not implemented, adding a "TODO" would be helpful.
> 
Our i2c driver now only support one master.

> > +
> > +       completion_done(&i2c->msg_complete);
> 
> This completion_done() is only useful if you check the return value.
> You should check it too, since we should only check for timeout if the
> message hasn't completed.
> 
I will delete the completion_done() function.

> > +
> > +       if (ret == 0) {
> > +               dev_dbg(i2c->dev, "send master code timeout.\n");
> > +               mtk_i2c_init_hw(i2c);
> > +               return -ETIMEDOUT;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
> >                                int num, int left_num)
> >  {
> > @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >                 }
> >         }
> >
> > +       if (i2c->auto_restart && i2c->speed_hz > 400000) {
> 
> Don't we need to send the master code for *every* HS transaction, not
> just "auto_restart"?
> 
When we don't use auto restart, we also need to send the master code,
the master code is sent by HW automatically.
I am improving the master code section when use auto restart, and this
will be released in the next patch.

> "400000" => You already have a macro for this: MAX_FS_MODE_SPEED
> 
Yes, I will use MAX_FS_MODE_SPEED.

> > +               ret = mtk_i2c_send_master_code(i2c);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> >         while (left_num--) {
> >                 if (!msgs->buf) {
> >                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> > --
> > 1.8.1.1.dirty
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode
@ 2015-12-02  2:51       ` liguo zhang
  0 siblings, 0 replies; 30+ messages in thread
From: liguo zhang @ 2015-12-02  2:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, 2015-11-14 at 22:38 +0800, Daniel Kurtz wrote:
> On Mon, Nov 9, 2015 at 1:43 PM, Liguo Zhang <liguo.zhang@mediatek.com> wrote:
> > For platform with auto restart support, when doing i2c multi transfer
> > in high speed, for example, doing write-then-read transfer, the master
> > code will occupy the first transfer, and the second transfer will be
> > the read transfer, the write transfer will be discarded. So we should
> > first send the master code, and then start i2c multi transfer.
> >
> > Signed-off-by: Liguo Zhang <liguo.zhang@mediatek.com>
> > Reviewed-by: Eddie Huang <eddie.huang@mediatek.com>
> > ---
> >  drivers/i2c/busses/i2c-mt65xx.c | 45 +++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 45 insertions(+)
> >
> > diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
> > index dc4aac6..249df86 100644
> > --- a/drivers/i2c/busses/i2c-mt65xx.c
> > +++ b/drivers/i2c/busses/i2c-mt65xx.c
> > @@ -53,6 +53,8 @@
> >  #define I2C_FS_TIME_INIT_VALUE         0x1303
> >  #define I2C_WRRD_TRANAC_VALUE          0x0002
> >  #define I2C_RD_TRANAC_VALUE            0x0001
> > +#define I2C_TRAN_DEFAULT_VALUE         0x0001
> > +#define I2C_TRANAC_DEFAULT_VALUE       0x0001
> 
> "TRAN" and "TRANAC" are not good names; this should be "TRANSFER_LEN"
> and "TRANSAC", based on the names of the registers to which you write
> these constants.
> 
> Furthermore, these are not "default" values, they are the transfer
> length and number of transactions for sending the "master code", so:
> 
> #define I2C_TRANSFER_LEN_MASTER_CODE         0x0001
> #define I2C_TRANSAC_LEN_MASTER_CODE       0x0001
> 
> Similarly, I think the "TRANAC" in I2C_WRRD_TRANAC_VALUE and
> I2C_RD_TRANAC_VALUE should also be TRANSAC.
> 

Yes, I will follow your advice.

> >
> >  #define I2C_DMA_CON_TX                 0x0000
> >  #define I2C_DMA_CON_RX                 0x0001
> > @@ -365,6 +367,43 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk,
> >         return 0;
> >  }
> >
> > +static int mtk_i2c_send_master_code(struct mtk_i2c *i2c)
> > +{
> > +       int ret = 0;
> > +
> > +       reinit_completion(&i2c->msg_complete);
> > +
> > +       writew(I2C_CONTROL_RS | I2C_CONTROL_ACKERR_DET_EN |
> > +              I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN,
> > +              i2c->base + OFFSET_CONTROL);
> > +
> > +       /* Clear interrupt status */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP | I2C_HS_NACKERR | I2C_ACKERR,
> > +              i2c->base + OFFSET_INTR_STAT);
> > +
> > +       /* Enable interrupt */
> > +       writew(I2C_RS_TRANSFER | I2C_TRANSAC_COMP, i2c->base +
> > +              OFFSET_INTR_MASK);
> > +
> > +       writew(I2C_TRAN_DEFAULT_VALUE, i2c->base + OFFSET_TRANSFER_LEN);
> > +       writew(I2C_TRANAC_DEFAULT_VALUE, i2c->base + OFFSET_TRANSAC_LEN);
> > +
> > +       writew(I2C_TRANSAC_START | I2C_RS_MUL_CNFG, i2c->base + OFFSET_START);
> > +
> > +       ret = wait_for_completion_timeout(&i2c->msg_complete,
> > +                                         i2c->adap.timeout);
> 
> How does the hardware know that this transaction should be a "master code"?
> Do you have to tell the hardware what value ('00001XXX') to use as the
> master code?

When we set i2c speed > 400K , the hardware will send master code. We
have a register to configure master code?and usually we use the default
value "00001000".

> The Master Code must be sent at <= 400 kHz, not the target clock.  How
> does the hardware know what rate to use?

The i2c speed is defined in dts, and we will set the i2c speed in i2c
register, so HW will know the rate to use.

> When sending the master code, arbitration is supposed to occur, such
> that only one winning master can proceed with the following high speed
> transaction.
> Where do you check that you won this arbitration?

> If this is not implemented, adding a "TODO" would be helpful.
> 
Our i2c driver now only support one master.

> > +
> > +       completion_done(&i2c->msg_complete);
> 
> This completion_done() is only useful if you check the return value.
> You should check it too, since we should only check for timeout if the
> message hasn't completed.
> 
I will delete the completion_done() function.

> > +
> > +       if (ret == 0) {
> > +               dev_dbg(i2c->dev, "send master code timeout.\n");
> > +               mtk_i2c_init_hw(i2c);
> > +               return -ETIMEDOUT;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> >  static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
> >                                int num, int left_num)
> >  {
> > @@ -539,6 +578,12 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
> >                 }
> >         }
> >
> > +       if (i2c->auto_restart && i2c->speed_hz > 400000) {
> 
> Don't we need to send the master code for *every* HS transaction, not
> just "auto_restart"?
> 
When we don't use auto restart, we also need to send the master code,
the master code is sent by HW automatically.
I am improving the master code section when use auto restart, and this
will be released in the next patch.

> "400000" => You already have a macro for this: MAX_FS_MODE_SPEED
> 
Yes, I will use MAX_FS_MODE_SPEED.

> > +               ret = mtk_i2c_send_master_code(i2c);
> > +               if (ret)
> > +                       return ret;
> > +       }
> > +
> >         while (left_num--) {
> >                 if (!msgs->buf) {
> >                         dev_dbg(i2c->dev, "data buffer is NULL.\n");
> > --
> > 1.8.1.1.dirty
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2015-12-02  2:51 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-09  5:43 [PATCH v2 0/2] Mediatek I2C Fixup Liguo Zhang
2015-11-09  5:43 ` Liguo Zhang
2015-11-09  5:43 ` Liguo Zhang
2015-11-09  5:43 ` [PATCH v2 1/2] i2c: mediatek: add i2c first write then read optimization Liguo Zhang
2015-11-09  5:43   ` Liguo Zhang
2015-11-09  5:43   ` Liguo Zhang
2015-11-09 14:25   ` Andy Shevchenko
2015-11-09 14:25     ` Andy Shevchenko
2015-11-10  0:34     ` Daniel Kurtz
2015-11-10  0:34       ` Daniel Kurtz
2015-11-10  0:50     ` Yingjoe Chen
2015-11-10  0:50       ` Yingjoe Chen
2015-11-10  0:50       ` Yingjoe Chen
2015-12-01  0:56   ` Wolfram Sang
2015-12-01  0:56     ` Wolfram Sang
2015-11-09  5:43 ` [PATCH v2 2/2] i2c: mediatek: fix i2c multi transfer issue in high speed mode Liguo Zhang
2015-11-09  5:43   ` Liguo Zhang
2015-11-09  5:43   ` Liguo Zhang
2015-11-14 14:38   ` Daniel Kurtz
2015-11-14 14:38     ` Daniel Kurtz
2015-11-14 14:38     ` Daniel Kurtz
2015-12-01  0:54     ` Wolfram Sang
2015-12-01  0:54       ` Wolfram Sang
2015-12-01  0:54       ` Wolfram Sang
2015-12-01 11:24     ` Liguo Zhang (张立国)
2015-12-01 11:24       ` Liguo Zhang (张立国)
2015-12-01 11:24       ` Liguo Zhang (张立国)
2015-12-02  2:51     ` liguo zhang
2015-12-02  2:51       ` liguo zhang
2015-12-02  2:51       ` liguo zhang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.