linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver
@ 2023-11-02  2:53 Hans Hu
  2023-11-02  2:53 ` [PATCH v3 01/12] i2c: wmt: Reduce redundant: bus busy check Hans Hu
                   ` (13 more replies)
  0 siblings, 14 replies; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Hi Andi, Wolfram,

Due to some corporate and personal delays, I only recently had time
to prepare the patch v3. Please kindly review.

In version v2, the patch consists of 2 files.
In version v3, the patch consists of 12 files.
I wish it was a little clearer how I do with it.

Among them, patch 0001-0009 is mainly some format modification and
removal of redundancy.
Patch 0010 splits i2c-wmt.c into i2c-wmt-plt.c and i2c-viai2c-common.c.
Patch 0011 shows some differences between zhaoxin and wmt.
Patch 0012 is the reset driver by zhaoxin's own controller.

Hans Hu (12):
  i2c: wmt: Reduce redundant: bus busy check
  i2c: wmt: Reduce redundant: wait event complete
  i2c: wmt: Reduce redundant: clock mode setting
  i2c: wmt: Reduce redundant: REG_CR setting
  i2c: wmt: Reduce redundant: function parameter
  i2c: wmt: delete .remove_new
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: rename marcos with prefix WMTI2C_
  i2c: wmt: adjust line length to meet style
  i2c: wmt: split out common files
  i2c: via-common: add zhaoxin platform
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                            |   8 +
 drivers/i2c/busses/Kconfig             |  10 +
 drivers/i2c/busses/Makefile            |   4 +
 drivers/i2c/busses/i2c-viai2c-common.c | 246 +++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  79 +++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 139 ++++++++
 drivers/i2c/busses/i2c-wmt.c           | 466 -------------------------
 drivers/i2c/busses/i2c-zhaoxin-plt.c   | 296 ++++++++++++++++
 8 files changed, 782 insertions(+), 466 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

-- 
2.34.1


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

* [PATCH v3 01/12] i2c: wmt: Reduce redundant: bus busy check
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-12-22  9:33   ` Wolfram Sang
  2023-11-02  2:53 ` [PATCH v3 02/12] i2c: wmt: Reduce redundant: wait event complete Hans Hu
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Put wmt_i2c_wait_bus_not_busy() in a more appropriate place
to reduce code redundancy

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 76118abc6e10..d554c6377533 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -128,12 +128,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	unsigned long wait_result;
 	int xfer_len = 0;
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
-		if (ret < 0)
-			return ret;
-	}
-
 	if (pmsg->len == 0) {
 		/*
 		 * We still need to run through the while (..) once, so
@@ -219,12 +213,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	unsigned long wait_result;
 	u32 xfer_len = 0;
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
-		if (ret < 0)
-			return ret;
-	}
-
 	val = readw(i2c_dev->base + REG_CR);
 	val &= ~CR_TX_END;
 	writew(val, i2c_dev->base + REG_CR);
@@ -297,11 +285,18 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap,
 	struct i2c_msg *pmsg;
 	int i, is_last;
 	int ret = 0;
+	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		is_last = ((i + 1) == num);
 
 		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			if (ret < 0)
+				return ret;
+		}
+
 		if (pmsg->flags & I2C_M_RD)
 			ret = wmt_i2c_read(adap, pmsg, is_last);
 		else
-- 
2.34.1


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

* [PATCH v3 02/12] i2c: wmt: Reduce redundant: wait event complete
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
  2023-11-02  2:53 ` [PATCH v3 01/12] i2c: wmt: Reduce redundant: bus busy check Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-12-22  9:34   ` Wolfram Sang
  2023-11-02  2:53 ` [PATCH v3 03/12] i2c: wmt: Reduce redundant: clock mode setting Hans Hu
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Put the handling of interrupt events in a function class
to reduce code redundancy.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index d554c6377533..1b31330ba4eb 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -109,6 +109,12 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
 {
 	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
 
 	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
 		ret = -EIO;
@@ -125,7 +131,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 	u16 val, tcr_val;
 	int ret;
-	unsigned long wait_result;
 	int xfer_len = 0;
 
 	if (pmsg->len == 0) {
@@ -167,12 +172,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	}
 
 	while (xfer_len < pmsg->len) {
-		wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-							msecs_to_jiffies(500));
-
-		if (wait_result == 0)
-			return -ETIMEDOUT;
-
 		ret = wmt_check_status(i2c_dev);
 		if (ret)
 			return ret;
@@ -210,7 +209,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 	u16 val, tcr_val;
 	int ret;
-	unsigned long wait_result;
 	u32 xfer_len = 0;
 
 	val = readw(i2c_dev->base + REG_CR);
@@ -251,12 +249,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	}
 
 	while (xfer_len < pmsg->len) {
-		wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-							msecs_to_jiffies(500));
-
-		if (!wait_result)
-			return -ETIMEDOUT;
-
 		ret = wmt_check_status(i2c_dev);
 		if (ret)
 			return ret;
-- 
2.34.1


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

* [PATCH v3 03/12] i2c: wmt: Reduce redundant: clock mode setting
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
  2023-11-02  2:53 ` [PATCH v3 01/12] i2c: wmt: Reduce redundant: bus busy check Hans Hu
  2023-11-02  2:53 ` [PATCH v3 02/12] i2c: wmt: Reduce redundant: wait event complete Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-12-22  9:36   ` Wolfram Sang
  2023-11-02  2:53 ` [PATCH v3 04/12] i2c: wmt: Reduce redundant: REG_CR setting Hans Hu
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

The frequency setting mode is adjusted to reduce the code redundancy,
and it is also convenient to share with zhaoxin

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 28 +++++++---------------------
 1 file changed, 7 insertions(+), 21 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 1b31330ba4eb..a44ce5fdde8a 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -74,9 +74,6 @@
 #define MCR_APB_96M		7
 #define MCR_APB_166M		12
 
-#define I2C_MODE_STANDARD	0
-#define I2C_MODE_FAST		1
-
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
 struct wmt_i2c_dev {
@@ -85,7 +82,7 @@ struct wmt_i2c_dev {
 	struct device		*dev;
 	void __iomem		*base;
 	struct clk		*clk;
-	int			mode;
+	u16			tcr;
 	int			irq;
 	u16			cmd_status;
 };
@@ -129,7 +126,7 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 			 int last)
 {
 	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
-	u16 val, tcr_val;
+	u16 val, tcr_val = i2c_dev->tcr;
 	int ret;
 	int xfer_len = 0;
 
@@ -156,11 +153,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 
 	reinit_completion(&i2c_dev->complete);
 
-	if (i2c_dev->mode == I2C_MODE_STANDARD)
-		tcr_val = TCR_STANDARD_MODE;
-	else
-		tcr_val = TCR_FAST_MODE;
-
 	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
 
 	writew(tcr_val, i2c_dev->base + REG_TCR);
@@ -207,7 +199,7 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 			int last)
 {
 	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
-	u16 val, tcr_val;
+	u16 val, tcr_val = i2c_dev->tcr;
 	int ret;
 	u32 xfer_len = 0;
 
@@ -233,11 +225,6 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 
 	reinit_completion(&i2c_dev->complete);
 
-	if (i2c_dev->mode == I2C_MODE_STANDARD)
-		tcr_val = TCR_STANDARD_MODE;
-	else
-		tcr_val = TCR_FAST_MODE;
-
 	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
 
 	writew(tcr_val, i2c_dev->base + REG_TCR);
@@ -346,10 +333,10 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 	readw(i2c_dev->base + REG_CSR);		/* read clear */
 	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
 
-	if (i2c_dev->mode == I2C_MODE_STANDARD)
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
-	else
+	if (i2c_dev->tcr == TCR_FAST_MODE)
 		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	else
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
 
 	return 0;
 }
@@ -382,10 +369,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 		return PTR_ERR(i2c_dev->clk);
 	}
 
-	i2c_dev->mode = I2C_MODE_STANDARD;
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->mode = I2C_MODE_FAST;
+		i2c_dev->tcr = TCR_FAST_MODE;
 
 	i2c_dev->dev = &pdev->dev;
 
-- 
2.34.1


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

* [PATCH v3 04/12] i2c: wmt: Reduce redundant: REG_CR setting
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (2 preceding siblings ...)
  2023-11-02  2:53 ` [PATCH v3 03/12] i2c: wmt: Reduce redundant: clock mode setting Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-12-22  9:38   ` Wolfram Sang
  2023-11-02  2:53 ` [PATCH v3 05/12] i2c: wmt: Reduce redundant: function parameter Hans Hu
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

These Settings for the same register, REG_CR, 
can be put together to reduce code redundancy.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 35 +++++++++--------------------------
 1 file changed, 9 insertions(+), 26 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index a44ce5fdde8a..d503e85752ea 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -144,9 +144,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c_dev->base + REG_CR);
 		val &= ~CR_TX_END;
-		writew(val, i2c_dev->base + REG_CR);
-
-		val = readw(i2c_dev->base + REG_CR);
 		val |= CR_CPU_RDY;
 		writew(val, i2c_dev->base + REG_CR);
 	}
@@ -204,24 +201,15 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	u32 xfer_len = 0;
 
 	val = readw(i2c_dev->base + REG_CR);
-	val &= ~CR_TX_END;
-	writew(val, i2c_dev->base + REG_CR);
+	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~CR_TX_NEXT_NO_ACK;
-	writew(val, i2c_dev->base + REG_CR);
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
+	if (!(pmsg->flags & I2C_M_NOSTART))
 		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
 
-	if (pmsg->len == 1) {
-		val = readw(i2c_dev->base + REG_CR);
+	if (pmsg->len == 1)
 		val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
-	}
+
+	writew(val, i2c_dev->base + REG_CR);
 
 	reinit_completion(&i2c_dev->complete);
 
@@ -243,15 +231,10 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
 		xfer_len++;
 
-		if (xfer_len == pmsg->len - 1) {
-			val = readw(i2c_dev->base + REG_CR);
-			val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY);
-			writew(val, i2c_dev->base + REG_CR);
-		} else {
-			val = readw(i2c_dev->base + REG_CR);
-			val |= CR_CPU_RDY;
-			writew(val, i2c_dev->base + REG_CR);
-		}
+		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + REG_CR);
 	}
 
 	return 0;
-- 
2.34.1


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

* [PATCH v3 05/12] i2c: wmt: Reduce redundant: function parameter
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (3 preceding siblings ...)
  2023-11-02  2:53 ` [PATCH v3 04/12] i2c: wmt: Reduce redundant: REG_CR setting Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-12-22  9:48   ` Wolfram Sang
  2023-11-02  2:53 ` [PATCH v3 06/12] i2c: wmt: delete .remove_new Hans Hu
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Use more appropriate parameter passing to reduce the amount of code

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index d503e85752ea..ec2a8da134e5 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -122,10 +122,9 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
 	return ret;
 }
 
-static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 			 int last)
 {
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 	u16 val, tcr_val = i2c_dev->tcr;
 	int ret;
 	int xfer_len = 0;
@@ -192,10 +191,8 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 	return 0;
 }
 
-static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
-			int last)
+static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 {
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 	u16 val, tcr_val = i2c_dev->tcr;
 	int ret;
 	u32 xfer_len = 0;
@@ -245,13 +242,11 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap,
 			int num)
 {
 	struct i2c_msg *pmsg;
-	int i, is_last;
+	int i;
 	int ret = 0;
 	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
-		is_last = ((i + 1) == num);
-
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
 			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
@@ -260,9 +255,9 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap,
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(adap, pmsg, is_last);
+			ret = wmt_i2c_read(i2c_dev, pmsg);
 		else
-			ret = wmt_i2c_write(adap, pmsg, is_last);
+			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
-- 
2.34.1


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

* [PATCH v3 06/12] i2c: wmt: delete .remove_new
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (4 preceding siblings ...)
  2023-11-02  2:53 ` [PATCH v3 05/12] i2c: wmt: Reduce redundant: function parameter Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-12-22  9:51   ` Wolfram Sang
  2023-11-02  2:53 ` [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init Hans Hu
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

use API devm_i2c_add_adapter instead of i2c_add_adapter,
remove callback remove_new.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 17 +----------------
 1 file changed, 1 insertion(+), 16 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index ec2a8da134e5..406b6827c42d 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -376,23 +376,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	err = i2c_add_adapter(adap);
-	if (err)
-		return err;
-
 	platform_set_drvdata(pdev, i2c_dev);
 
-	return 0;
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	return devm_i2c_add_adapter(&pdev->dev, &i2c_dev->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
@@ -402,7 +388,6 @@ static const struct of_device_id wmt_i2c_dt_ids[] = {
 
 static struct platform_driver wmt_i2c_driver = {
 	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
 	.driver		= {
 		.name	= "wmt-i2c",
 		.of_match_table = wmt_i2c_dt_ids,
-- 
2.34.1


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

* [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (5 preceding siblings ...)
  2023-11-02  2:53 ` [PATCH v3 06/12] i2c: wmt: delete .remove_new Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-12-22 10:26   ` Wolfram Sang
  2023-11-02  2:53 ` [PATCH v3 08/12] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 70 ++++++++++++++++++++++--------------
 1 file changed, 44 insertions(+), 26 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 406b6827c42d..b2fb2e7e4f0d 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -286,6 +286,47 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	int irq_flags;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	if (np) {
+		irq_flags = 0;
+		i2c_dev->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c_dev->irq)
+			return -EINVAL;
+	} else {
+		irq_flags = IRQF_SHARED;
+		i2c_dev->irq = platform_get_irq(pdev, 0);
+		if (i2c_dev->irq < 0)
+			return i2c_dev->irq;
+	}
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					irq_flags, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +368,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -351,15 +382,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,16 +390,12 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
 	}
 
-	platform_set_drvdata(pdev, i2c_dev);
-
 	return devm_i2c_add_adapter(&pdev->dev, &i2c_dev->adapter);
 }
 
-- 
2.34.1


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

* [PATCH v3 08/12] i2c: wmt: rename marcos with prefix WMTI2C_
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (6 preceding siblings ...)
  2023-11-02  2:53 ` [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-11-02  2:53 ` [PATCH v3 09/12] i2c: wmt: adjust line length to meet style Hans Hu
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Tweaked a few formatting things: rename marcos with prefix WMTI2C_

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 174 +++++++++++++++++------------------
 1 file changed, 87 insertions(+), 87 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index b2fb2e7e4f0d..ec9e4bfc52b0 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -20,59 +20,59 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
+#define WMTI2C_REG_CR		0x00
+#define WMTI2C_REG_TCR		0x02
+#define WMTI2C_REG_CSR		0x04
+#define WMTI2C_REG_ISR		0x06
+#define WMTI2C_REG_IMR		0x08
+#define WMTI2C_REG_CDR		0x0A
+#define WMTI2C_REG_TR		0x0C
+#define WMTI2C_REG_MCR		0x0E
+#define WMTI2C_REG_SLAVE_CR	0x10
+#define WMTI2C_REG_SLAVE_SR	0x12
+#define WMTI2C_REG_SLAVE_ISR	0x14
+#define WMTI2C_REG_SLAVE_IMR	0x16
+#define WMTI2C_REG_SLAVE_DR	0x18
+#define WMTI2C_REG_SLAVE_TR	0x1A
 
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define WMTI2C_CR_TX_NEXT_ACK		0x0000
+#define WMTI2C_CR_ENABLE		0x0001
+#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
+#define WMTI2C_CR_TX_END		0x0004
+#define WMTI2C_CR_CPU_RDY		0x0008
+#define WMTI2C_SLAV_MODE_SEL		0x8000
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define WMTI2C_TCR_STANDARD_MODE	0x0000
+#define WMTI2C_TCR_MASTER_WRITE		0x0000
+#define WMTI2C_TCR_HS_MODE		0x2000
+#define WMTI2C_TCR_MASTER_READ		0x4000
+#define WMTI2C_TCR_FAST_MODE		0x8000
+#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define WMTI2C_ISR_NACK_ADDR		0x0001
+#define WMTI2C_ISR_BYTE_END		0x0002
+#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
+#define WMTI2C_ISR_WRITE_ALL		0x0007
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define WMTI2C_IMR_ENABLE_ALL		0x0007
 
 /* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
+#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
+#define WMTI2C_CSR_READY_MASK		0x0002
 
 /* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
 
 /* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
@@ -92,7 +92,7 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	unsigned long timeout;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
@@ -113,10 +113,10 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
@@ -135,28 +135,28 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val &= ~WMTI2C_CR_TX_END;
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -166,25 +166,25 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
+		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
 			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
+			writew(val, i2c_dev->base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+								WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		}
 	}
 
@@ -197,27 +197,27 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= WMTI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c_dev->base + WMTI2C_REG_CR);
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -225,13 +225,13 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -278,8 +278,8 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	struct wmt_i2c_dev *i2c_dev = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
 
 	complete(&i2c_dev->complete);
 
@@ -344,18 +344,18 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c_dev->base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -380,7 +380,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
 
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
-- 
2.34.1


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

* [PATCH v3 09/12] i2c: wmt: adjust line length to meet style
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (7 preceding siblings ...)
  2023-11-02  2:53 ` [PATCH v3 08/12] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
@ 2023-11-02  2:53 ` Hans Hu
  2023-11-02  2:54 ` [PATCH v3 10/12] i2c: wmt: split out common files Hans Hu
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:53 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Tweaked a few formatting things:
rename wmt_i2c_dev to wmt_i2c, i2c_dev to i2c, etc. 

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 203 ++++++++++++++++++-----------------
 1 file changed, 107 insertions(+), 96 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index ec9e4bfc52b0..3dea153c62aa 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -76,7 +76,7 @@
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct wmt_i2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -87,14 +87,16 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
 {
 	unsigned long timeout;
+	void __iomem *base = i2c->base;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev,
+					"timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -103,31 +105,32 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+static int wmt_check_status(struct wmt_i2c *i2c)
 {
 	int ret = 0;
 	unsigned long wait_result;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+	wait_result = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
+	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
+static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
 			 int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
+	void __iomem *base = i2c->base;
 
 	if (pmsg->len == 0) {
 		/*
@@ -135,69 +138,73 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(0, base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val &= ~WMTI2C_CR_TX_END;
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
-		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(base + WMTI2C_REG_CSR);
+		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
-			writew(val, i2c_dev->base + WMTI2C_REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
+				| WMTI2C_CR_ENABLE;
+			writew(val, base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
+					base + WMTI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
 
-	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val = readw(base + WMTI2C_REG_CR);
 	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
@@ -206,32 +213,33 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	if (pmsg->len == 1)
 		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + WMTI2C_REG_CR);
+	writew(val, base + WMTI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
 			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -244,20 +252,20 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap,
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = wmt_i2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = wmt_i2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
@@ -275,87 +283,90 @@ static const struct i2c_algorithm wmt_i2c_algo = {
 
 static irqreturn_t wmt_i2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct wmt_i2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
+	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
 {
 	int err;
 	int irq_flags;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
 	if (np) {
 		irq_flags = 0;
-		i2c_dev->irq = irq_of_parse_and_map(np, 0);
-		if (!i2c_dev->irq)
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
 			return -EINVAL;
 	} else {
 		irq_flags = IRQF_SHARED;
-		i2c_dev->irq = platform_get_irq(pdev, 0);
-		if (i2c_dev->irq < 0)
-			return i2c_dev->irq;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	}
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					irq_flags, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+					irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
 {
 	int err;
+	void __iomem *base = i2c->base;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
-	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
-
-	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
+	writew(0, base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+	readw(base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+
+	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS,
+				base + WMTI2C_REG_TR);
 	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD,
+				base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -363,40 +374,40 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = wmt_i2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
+		i2c->tcr = WMTI2C_TCR_FAST_MODE;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
 	}
 
-	return devm_i2c_add_adapter(&pdev->dev, &i2c_dev->adapter);
+	return devm_i2c_add_adapter(&pdev->dev, &i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.34.1


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

* [PATCH v3 10/12] i2c: wmt: split out common files
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (8 preceding siblings ...)
  2023-11-02  2:53 ` [PATCH v3 09/12] i2c: wmt: adjust line length to meet style Hans Hu
@ 2023-11-02  2:54 ` Hans Hu
  2023-11-02  2:54 ` [PATCH v3 11/12] i2c: via-common: add zhaoxin platform Hans Hu
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:54 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Since the I2C IP of both wmt and zhaoxin come from VIA,
the common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-wmt-plt.c.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/Makefile            |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c | 232 +++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  72 +++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 139 ++++++++
 drivers/i2c/busses/i2c-wmt.c           | 431 -------------------------
 5 files changed, 445 insertions(+), 431 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index af56fe2c75c0..19262f4d30fe 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -120,7 +120,9 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-wmt-plt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
+
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
 i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 000000000000..45ac56941bee
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+int viai2c_wait_bus_ready(struct viai2c *i2c)
+{
+	unsigned long timeout;
+	void __iomem *base = i2c->base;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c->dev, "timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+int viai2c_wait_status(struct viai2c *i2c, u8 status)
+{
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c->cmd_status & status)
+		return 0;
+
+	return -EIO;
+}
+
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
+{
+	u16 val, tcr_val = i2c->tcr;
+	int xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, base + VIAI2C_REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
+	}
+
+	reinit_completion(&i2c->complete);
+	writew(tcr_val | pmsg->addr, base + VIAI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		int err;
+
+		err = viai2c_wait_status(i2c, VIAI2C_ISR_BYTE_END);
+		if (err)
+			return err;
+
+		xfer_len++;
+
+		val = readw(base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY
+				| VIAI2C_CR_ENABLE;
+			writew(val, base + VIAI2C_REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (!last)
+				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
+					base + VIAI2C_REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c->tcr;
+	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	val = readw(base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= VIAI2C_CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= VIAI2C_CR_RX_END;
+
+	writew(val, base + VIAI2C_REG_CR);
+
+	reinit_completion(&i2c->complete);
+
+	tcr_val |= VIAI2C_TCR_MASTER_READ | pmsg->addr;
+
+	writew(tcr_val, base + VIAI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		int err;
+
+		err = viai2c_wait_status(i2c, VIAI2C_ISR_BYTE_END);
+		if (err)
+			return err;
+
+		pmsg->buf[xfer_len] = readw(base + VIAI2C_REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= VIAI2C_CR_RX_END;
+		writew(val, base + VIAI2C_REG_CR);
+	}
+
+	return 0;
+}
+
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct viai2c *i2c = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = viai2c_wait_bus_ready(i2c);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = viai2c_read(i2c, pmsg);
+		else
+			ret = viai2c_write(i2c, pmsg, i == (num - 1));
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+static irqreturn_t viai2c_isr(int irq, void *data)
+{
+	struct viai2c *i2c = data;
+
+	/* save the status and write-clear it */
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
+
+	complete(&i2c->complete);
+
+	return IRQ_HANDLED;
+}
+
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+{
+	int err;
+	int irq_flags;
+	struct viai2c *i2c;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
+
+	if (np) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
+	}
+
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
+					irq_flags, pdev->name, i2c);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c->irq);
+
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
+
+	*pi2c = i2c;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 000000000000..f3dcc609679e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+/* REG_CR Bit fields */
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+
+/* REG_TCR Bit fields */
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_MASTER_READ		BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+
+/* REG_CSR Bit fields */
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
+
+/* REG_ISR Bit fields */
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
+
+/* REG_IMR Bit fields */
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_ADDRNACK		BIT(0)
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
+
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
+
+enum {
+	VIAI2C_PLAT_WMT = 1,
+};
+
+struct viai2c {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+	u8			platform;
+};
+
+int viai2c_wait_bus_ready(struct viai2c *i2c);
+int viai2c_wait_status(struct viai2c *i2c, u8 status);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
new file mode 100644
index 000000000000..1789156a656e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+#define WMTI2C_REG_SLAVE_CR	0x10
+#define WMTI2C_REG_SLAVE_SR	0x12
+#define WMTI2C_REG_SLAVE_ISR	0x14
+#define WMTI2C_REG_SLAVE_IMR	0x16
+#define WMTI2C_REG_SLAVE_DR	0x18
+#define WMTI2C_REG_SLAVE_TR	0x1A
+
+/* REG_TR */
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
+
+/* REG_MCR */
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
+
+#define wmt_i2c viai2c
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= viai2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
+{
+	int err;
+	void __iomem *base = i2c->base;
+
+	err = clk_prepare_enable(i2c->clk);
+	if (err) {
+		dev_err(i2c->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c->clk, 20000000);
+	if (err) {
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
+		return err;
+	}
+
+	writew(0, base + VIAI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+	readw(base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
+
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS,
+				base + VIAI2C_REG_TR);
+	else
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD,
+				base + VIAI2C_REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c *i2c;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = viai2c_init(pdev, &i2c);
+	if (err)
+		return err;
+
+	i2c->platform = VIAI2C_PLAT_WMT;
+
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+		i2c->tcr = VIAI2C_TCR_FAST;
+
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	return devm_i2c_add_adapter(&pdev->dev, &i2c->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index 3dea153c62aa..000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,431 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define WMTI2C_REG_CR		0x00
-#define WMTI2C_REG_TCR		0x02
-#define WMTI2C_REG_CSR		0x04
-#define WMTI2C_REG_ISR		0x06
-#define WMTI2C_REG_IMR		0x08
-#define WMTI2C_REG_CDR		0x0A
-#define WMTI2C_REG_TR		0x0C
-#define WMTI2C_REG_MCR		0x0E
-#define WMTI2C_REG_SLAVE_CR	0x10
-#define WMTI2C_REG_SLAVE_SR	0x12
-#define WMTI2C_REG_SLAVE_ISR	0x14
-#define WMTI2C_REG_SLAVE_IMR	0x16
-#define WMTI2C_REG_SLAVE_DR	0x18
-#define WMTI2C_REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define WMTI2C_CR_TX_NEXT_ACK		0x0000
-#define WMTI2C_CR_ENABLE		0x0001
-#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
-#define WMTI2C_CR_TX_END		0x0004
-#define WMTI2C_CR_CPU_RDY		0x0008
-#define WMTI2C_SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define WMTI2C_TCR_STANDARD_MODE	0x0000
-#define WMTI2C_TCR_MASTER_WRITE		0x0000
-#define WMTI2C_TCR_HS_MODE		0x2000
-#define WMTI2C_TCR_MASTER_READ		0x4000
-#define WMTI2C_TCR_FAST_MODE		0x8000
-#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define WMTI2C_ISR_NACK_ADDR		0x0001
-#define WMTI2C_ISR_BYTE_END		0x0002
-#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
-#define WMTI2C_ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define WMTI2C_IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
-#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
-#define WMTI2C_CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define WMTI2C_TR_STD			0x0064
-#define WMTI2C_TR_HS			0x0019
-
-/* REG_MCR */
-#define WMTI2C_MCR_APB_96M		7
-#define WMTI2C_MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
-{
-	unsigned long timeout;
-	void __iomem *base = i2c->base;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c->dev,
-					"timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c *i2c)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	int xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, base + WMTI2C_REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(base + WMTI2C_REG_CR);
-		val &= ~WMTI2C_CR_TX_END;
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CSR);
-		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
-				| WMTI2C_CR_ENABLE;
-			writew(val, base + WMTI2C_REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF,
-					base + WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
-					base + WMTI2C_REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	u32 xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	val = readw(base + WMTI2C_REG_CR);
-	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= WMTI2C_CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-
-	writew(val, base + WMTI2C_REG_CR);
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= WMTI2C_TCR_MASTER_READ
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c, pmsg);
-		else
-			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c *i2c = data;
-
-	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
-
-	complete(&i2c->complete);
-
-	return IRQ_HANDLED;
-}
-
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
-{
-	int err;
-	int irq_flags;
-	struct wmt_i2c *i2c;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
-	if (!i2c)
-		return -ENOMEM;
-
-	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c->base))
-		return PTR_ERR(i2c->base);
-
-	if (np) {
-		irq_flags = 0;
-		i2c->irq = irq_of_parse_and_map(np, 0);
-		if (!i2c->irq)
-			return -EINVAL;
-	} else {
-		irq_flags = IRQF_SHARED;
-		i2c->irq = platform_get_irq(pdev, 0);
-		if (i2c->irq < 0)
-			return i2c->irq;
-	}
-
-	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
-					irq_flags, pdev->name, i2c);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c->irq);
-
-	i2c->dev = &pdev->dev;
-	init_completion(&i2c->complete);
-	platform_set_drvdata(pdev, i2c);
-
-	*pi2c = i2c;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
-{
-	int err;
-	void __iomem *base = i2c->base;
-
-	err = clk_prepare_enable(i2c->clk);
-	if (err) {
-		dev_err(i2c->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c->clk, 20000000);
-	if (err) {
-		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c->clk);
-		return err;
-	}
-
-	writew(0, base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-	readw(base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-
-	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS,
-				base + WMTI2C_REG_TR);
-	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD,
-				base + WMTI2C_REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c *i2c;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c);
-	if (err)
-		return err;
-
-	i2c->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c->tcr = WMTI2C_TCR_FAST_MODE;
-
-	adap = &i2c->adapter;
-	i2c_set_adapdata(adap, i2c);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	return devm_i2c_add_adapter(&pdev->dev, &i2c->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.34.1


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

* [PATCH v3 11/12] i2c: via-common: add zhaoxin platform
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (9 preceding siblings ...)
  2023-11-02  2:54 ` [PATCH v3 10/12] i2c: wmt: split out common files Hans Hu
@ 2023-11-02  2:54 ` Hans Hu
  2023-11-02  2:54 ` [PATCH v3 12/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:54 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen


There are some differences between the design of zhaoxin
i2c controller and wmt. Use VIAI2C_PLAT_WMT and VIAI2C_PLAT_ZHAOXIN
to identify the two platforms.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 30 +++++++++++++++++++-------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 ++++++
 2 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 45ac56941bee..0247865cb57a 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -15,6 +15,13 @@ int viai2c_wait_bus_ready(struct viai2c *i2c)
 			dev_warn(i2c->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
+		if (i2c->platform == VIAI2C_PLAT_ZHAOXIN) {
+			u16 tmp = ioread16(i2c->base + VIAI2C_REG_CR);
+
+			iowrite16(tmp | VIAI2C_CR_END_MASK,
+					i2c->base + VIAI2C_REG_CR);
+		}
+
 		msleep(20);
 	}
 
@@ -53,7 +60,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -63,7 +70,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 	reinit_completion(&i2c->complete);
 	writew(tcr_val | pmsg->addr, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -92,8 +99,10 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 		}
 
 		if (xfer_len == pmsg->len) {
-			if (!last)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && last)
+				writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
 					base + VIAI2C_REG_CDR);
@@ -105,7 +114,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 	return 0;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 	u32 xfer_len = 0;
@@ -114,7 +123,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -128,7 +137,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART))
+	    || (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -162,14 +172,15 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if (!(pmsg->flags & I2C_M_NOSTART)
+		   && (i2c->platform == VIAI2C_PLAT_WMT)) {
 			ret = viai2c_wait_bus_ready(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, i == (num - 1));
 	}
@@ -183,6 +194,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!i2c->cmd_status)
+		return IRQ_NONE;
+
 	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index f3dcc609679e..c1b9ccff24e8 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -50,6 +50,7 @@
 
 enum {
 	VIAI2C_PLAT_WMT = 1,
+	VIAI2C_PLAT_ZHAOXIN
 };
 
 struct viai2c {
@@ -62,6 +63,12 @@ struct viai2c {
 	int			irq;
 	u16			cmd_status;
 	u8			platform;
+	u8			addr;
+	u16			tr;
+	u16			mcr;
+	u16			csr;
+	u8			fstp;
+	u8			hrv;
 };
 
 int viai2c_wait_bus_ready(struct viai2c *i2c);
-- 
2.34.1


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

* [PATCH v3 12/12] i2c: add zhaoxin i2c controller driver
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (10 preceding siblings ...)
  2023-11-02  2:54 ` [PATCH v3 11/12] i2c: via-common: add zhaoxin platform Hans Hu
@ 2023-11-02  2:54 ` Hans Hu
  2023-11-08  9:50 ` [PATCH v3 00/12] " Wolfram Sang
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
  13 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-11-02  2:54 UTC (permalink / raw)
  To: andi.shyti, wsa, linux-i2c; +Cc: cobechen

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the "IIC1D17" HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                          |   8 +
 drivers/i2c/busses/Kconfig           |  10 +
 drivers/i2c/busses/Makefile          |   2 +
 drivers/i2c/busses/i2c-zhaoxin-plt.c | 296 +++++++++++++++++++++++++++
 4 files changed, 316 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2894f0777537..a7f75579fca1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9915,6 +9915,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 6644eebedaf3..d04f3ce64952 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -335,6 +335,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+	config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 19262f4d30fe..4faac9dcbce0 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-zhaoxin-plt.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-zhaoxin-plt.c b/drivers/i2c/busses/i2c-zhaoxin-plt.c
new file mode 100644
index 000000000000..08d673eaa406
--- /dev/null
+++ b/drivers/i2c/busses/i2c-zhaoxin-plt.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2021 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/pci.h>
+#include "i2c-viai2c-common.h"
+
+#define ZX_I2C_NAME             "Zhaoxin-I2C"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+#define ZXI2C_FIFO_SIZE		32
+
+/* Structure definition */
+#define zxi2c viai2c
+
+static int zxi2c_fifo_xfer(struct zxi2c *i2c, struct i2c_msg *msg)
+{
+	u16 xfered_len = 0;
+	u16 byte_left = msg->len;
+	u16 tcr_val = i2c->tcr;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+
+	while (byte_left) {
+		u16 i;
+		u8 tmp;
+		int error;
+		u16 xfer_len = min_t(u16, byte_left, ZXI2C_FIFO_SIZE);
+
+		byte_left -= xfer_len;
+
+		/* reset fifo buffer */
+		tmp = ioread8(base + ZXI2C_REG_HCR);
+		iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+		/* set xfer len */
+		if (read) {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HRLR);
+		} else {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HTLR);
+			/* set write data */
+			for (i = 0; i < xfer_len; i++)
+				iowrite8(msg->buf[xfered_len + i],
+						base + ZXI2C_REG_HTDR);
+		}
+
+		/* prepare to stop transmission */
+		if (i2c->hrv && !byte_left) {
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+			iowrite8(tmp, base + VIAI2C_REG_CR);
+		}
+
+		reinit_completion(&i2c->complete);
+
+		if (xfered_len) {
+			/* continue transmission */
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			iowrite8(tmp |= VIAI2C_CR_CPU_RDY,
+					i2c->base + VIAI2C_REG_CR);
+		} else {
+			/* start transmission */
+			tcr_val |= (read ? VIAI2C_TCR_MASTER_READ : 0);
+			writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+		}
+
+		error = viai2c_wait_status(i2c, ZXI2C_IRQ_FIFOEND);
+		if (error)
+			return error;
+
+		/* get the received data */
+		if (read)
+			for (i = 0; i < xfer_len; i++)
+				msg->buf[xfered_len + i] =
+					ioread8(base + ZXI2C_REG_HRDR);
+
+		xfered_len += xfer_len;
+	}
+
+	return 1;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct zxi2c *i2c = (struct zxi2c *)i2c_get_adapdata(adap);
+
+	ret = viai2c_wait_bus_ready(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 &&
+	   (i2c->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND,
+				i2c->base + VIAI2C_REG_IMR);
+
+		ret = zxi2c_fifo_xfer(i2c, msgs);
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE,
+				i2c->base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret < 0)
+			iowrite16(tmp | VIAI2C_CR_END_MASK,
+					i2c->base + VIAI2C_REG_CR);
+		/* make sure the state machine is stopped */
+		usleep_range(1, 2);
+	}
+	/* dis interrupt */
+	iowrite8(0, i2c->base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct zxi2c *i2c)
+{
+	iowrite16(i2c->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(i2c->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct zxi2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
+				params[0], fstp, params[2]);
+		i2c->tr = params[2] | 0xff00;
+	} else {
+		i2c->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	i2c->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0000 1000 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		i2c->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n",
+			i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct zxi2c *i2c;
+	struct pci_dev *pci;
+	struct i2c_adapter *adap;
+
+	error = viai2c_init(pdev, &i2c);
+	if (error)
+		return error;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	i2c->platform = VIAI2C_PLAT_ZHAOXIN;
+	i2c->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->retries = 2;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	pci = to_pci_dev(pdev->dev.parent);
+	snprintf(adap->name, sizeof(adap->name), "%s-%s-%s",
+		ZX_I2C_NAME, dev_name(&pci->dev), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int zxi2c_resume(struct device *dev)
+{
+	struct zxi2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = ZX_I2C_NAME,
+		.acpi_match_table = ACPI_PTR(zxi2c_acpi_match),
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* Re: [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (11 preceding siblings ...)
  2023-11-02  2:54 ` [PATCH v3 12/12] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2023-11-08  9:50 ` Wolfram Sang
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
  13 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-11-08  9:50 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

Hi,

> Due to some corporate and personal delays, I only recently had time

Don't worry, we are glad that you are back.

> to prepare the patch v3. Please kindly review.

Yes, I will have a look, hopefully soon after the merge window is over.
Really cool to see this new version. Most people drop off when I ask
them to refactor their new driver to an existing one. But you made it,
awesome!

All the best,

   Wolfram


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 01/12] i2c: wmt: Reduce redundant: bus busy check
  2023-11-02  2:53 ` [PATCH v3 01/12] i2c: wmt: Reduce redundant: bus busy check Hans Hu
@ 2023-12-22  9:33   ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22  9:33 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Thu, Nov 02, 2023 at 10:53:51AM +0800, Hans Hu wrote:
> Put wmt_i2c_wait_bus_not_busy() in a more appropriate place
> to reduce code redundancy
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Applied to for-next, thanks!


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 02/12] i2c: wmt: Reduce redundant: wait event complete
  2023-11-02  2:53 ` [PATCH v3 02/12] i2c: wmt: Reduce redundant: wait event complete Hans Hu
@ 2023-12-22  9:34   ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22  9:34 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Thu, Nov 02, 2023 at 10:53:52AM +0800, Hans Hu wrote:
> Put the handling of interrupt events in a function class
> to reduce code redundancy.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Applied to for-next, thanks!


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 03/12] i2c: wmt: Reduce redundant: clock mode setting
  2023-11-02  2:53 ` [PATCH v3 03/12] i2c: wmt: Reduce redundant: clock mode setting Hans Hu
@ 2023-12-22  9:36   ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22  9:36 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Thu, Nov 02, 2023 at 10:53:53AM +0800, Hans Hu wrote:
> The frequency setting mode is adjusted to reduce the code redundancy,
> and it is also convenient to share with zhaoxin
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Applied to for-next, thanks!


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 04/12] i2c: wmt: Reduce redundant: REG_CR setting
  2023-11-02  2:53 ` [PATCH v3 04/12] i2c: wmt: Reduce redundant: REG_CR setting Hans Hu
@ 2023-12-22  9:38   ` Wolfram Sang
  2023-12-22 10:15     ` Wolfram Sang
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22  9:38 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Thu, Nov 02, 2023 at 10:53:54AM +0800, Hans Hu wrote:
> These Settings for the same register, REG_CR, 
> can be put together to reduce code redundancy.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Some registers require that you first write a certain value, and only
then can write another value. Have you double checked with datasheets
that these register writes can safely be aggregated?

> ---
>  drivers/i2c/busses/i2c-wmt.c | 35 +++++++++--------------------------
>  1 file changed, 9 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
> index a44ce5fdde8a..d503e85752ea 100644
> --- a/drivers/i2c/busses/i2c-wmt.c
> +++ b/drivers/i2c/busses/i2c-wmt.c
> @@ -144,9 +144,6 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
>  	if (!(pmsg->flags & I2C_M_NOSTART)) {
>  		val = readw(i2c_dev->base + REG_CR);
>  		val &= ~CR_TX_END;
> -		writew(val, i2c_dev->base + REG_CR);
> -
> -		val = readw(i2c_dev->base + REG_CR);
>  		val |= CR_CPU_RDY;
>  		writew(val, i2c_dev->base + REG_CR);
>  	}
> @@ -204,24 +201,15 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
>  	u32 xfer_len = 0;
>  
>  	val = readw(i2c_dev->base + REG_CR);
> -	val &= ~CR_TX_END;
> -	writew(val, i2c_dev->base + REG_CR);
> +	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
>  
> -	val = readw(i2c_dev->base + REG_CR);
> -	val &= ~CR_TX_NEXT_NO_ACK;
> -	writew(val, i2c_dev->base + REG_CR);
> -
> -	if (!(pmsg->flags & I2C_M_NOSTART)) {
> -		val = readw(i2c_dev->base + REG_CR);
> +	if (!(pmsg->flags & I2C_M_NOSTART))
>  		val |= CR_CPU_RDY;
> -		writew(val, i2c_dev->base + REG_CR);
> -	}
>  
> -	if (pmsg->len == 1) {
> -		val = readw(i2c_dev->base + REG_CR);
> +	if (pmsg->len == 1)
>  		val |= CR_TX_NEXT_NO_ACK;
> -		writew(val, i2c_dev->base + REG_CR);
> -	}
> +
> +	writew(val, i2c_dev->base + REG_CR);
>  
>  	reinit_completion(&i2c_dev->complete);
>  
> @@ -243,15 +231,10 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
>  		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
>  		xfer_len++;
>  
> -		if (xfer_len == pmsg->len - 1) {
> -			val = readw(i2c_dev->base + REG_CR);
> -			val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY);
> -			writew(val, i2c_dev->base + REG_CR);
> -		} else {
> -			val = readw(i2c_dev->base + REG_CR);
> -			val |= CR_CPU_RDY;
> -			writew(val, i2c_dev->base + REG_CR);
> -		}
> +		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
> +		if (xfer_len == pmsg->len - 1)
> +			val |= CR_TX_NEXT_NO_ACK;
> +		writew(val, i2c_dev->base + REG_CR);
>  	}
>  
>  	return 0;
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 05/12] i2c: wmt: Reduce redundant: function parameter
  2023-11-02  2:53 ` [PATCH v3 05/12] i2c: wmt: Reduce redundant: function parameter Hans Hu
@ 2023-12-22  9:48   ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22  9:48 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Thu, Nov 02, 2023 at 10:53:55AM +0800, Hans Hu wrote:
> Use more appropriate parameter passing to reduce the amount of code
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> ---

Because I like most cleanups here: applied to for-next, thanks!

But this patch likely reveals a bug in the driver:

> -static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
> -			int last)
> +static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)

It is valid for an I2C transfer, that the last message is a read
message. So, instead of dropping it, I think the read function needs to
handle 'last' as well.

Because this bug is already present in the driver, and I don't want to
make rebasing a next version of this series too difficult, I argue that
we fix it after your changes are included.

Happy hacking!


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 06/12] i2c: wmt: delete .remove_new
  2023-11-02  2:53 ` [PATCH v3 06/12] i2c: wmt: delete .remove_new Hans Hu
@ 2023-12-22  9:51   ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22  9:51 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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


> -	/* Disable interrupts, clock and delete adapter */
> -	writew(0, i2c_dev->base + REG_IMR);
> -	clk_disable_unprepare(i2c_dev->clk);

NACK to this patch. The above lines are very important and need to stay.
It is, in fact, very dangerous to use devm_* and to not take care that
interrupts are disabled before leaving remove().

I'd suggest to simply drop this patch.

> -	i2c_del_adapter(&i2c_dev->adapter);
> +	return devm_i2c_add_adapter(&pdev->dev, &i2c_dev->adapter);
>  }
>  
>  static const struct of_device_id wmt_i2c_dt_ids[] = {
> @@ -402,7 +388,6 @@ static const struct of_device_id wmt_i2c_dt_ids[] = {
>  
>  static struct platform_driver wmt_i2c_driver = {
>  	.probe		= wmt_i2c_probe,
> -	.remove_new	= wmt_i2c_remove,
>  	.driver		= {
>  		.name	= "wmt-i2c",
>  		.of_match_table = wmt_i2c_dt_ids,
> -- 
> 2.34.1
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 04/12] i2c: wmt: Reduce redundant: REG_CR setting
  2023-12-22  9:38   ` Wolfram Sang
@ 2023-12-22 10:15     ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22 10:15 UTC (permalink / raw)
  To: Hans Hu, andi.shyti, linux-i2c, cobechen

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

On Fri, Dec 22, 2023 at 10:38:29AM +0100, Wolfram Sang wrote:
> On Thu, Nov 02, 2023 at 10:53:54AM +0800, Hans Hu wrote:
> > These Settings for the same register, REG_CR, 
> > can be put together to reduce code redundancy.
> > 
> > Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> 
> Some registers require that you first write a certain value, and only
> then can write another value. Have you double checked with datasheets
> that these register writes can safely be aggregated?

I found a WM8505 datasheet and it doesn't say anything about consecutive
writes. And it works on your hardware.

Applied to for-next, thanks!


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init
  2023-11-02  2:53 ` [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2023-12-22 10:26   ` Wolfram Sang
  2023-12-22 10:55     ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22 10:26 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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


> +		irq_flags = IRQF_SHARED;
> +		i2c_dev->irq = platform_get_irq(pdev, 0);
> +		if (i2c_dev->irq < 0)
> +			return i2c_dev->irq;

Doesn't this belong to patch 11 where you introduce the new platform?

Sadly, I can't apply this patch anymore because patch 6 needs to be
dropped.

Could you rebase this series on top of my for-next branch once I pushed
it out later today? This will have the first cleanups already applied.


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init
  2023-12-22 10:26   ` Wolfram Sang
@ 2023-12-22 10:55     ` Hans Hu
  2023-12-22 11:00       ` Wolfram Sang
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-22 10:55 UTC (permalink / raw)
  To: Wolfram Sang, andi.shyti, linux-i2c, cobechen


On 2023/12/22 18:26, Wolfram Sang wrote:
>> +		irq_flags = IRQF_SHARED;
>> +		i2c_dev->irq = platform_get_irq(pdev, 0);
>> +		if (i2c_dev->irq < 0)
>> +			return i2c_dev->irq;
> Doesn't this belong to patch 11 where you introduce the new platform?
>
> Sadly, I can't apply this patch anymore because patch 6 needs to be
> dropped.
>
> Could you rebase this series on top of my for-next branch once I pushed
> it out later today? This will have the first cleanups already applied.
>
Thanks for your review, I will rebase this series on your last for-next 
branch.

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

* Re: [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init
  2023-12-22 10:55     ` Hans Hu
@ 2023-12-22 11:00       ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2023-12-22 11:00 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

> Thanks for your review, I will rebase this series on your last for-next
> branch.

Thanks, I pushed it now.


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* [PATCH v4 0/8] i2c: add zhaoxin i2c controller driver
  2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
                   ` (12 preceding siblings ...)
  2023-11-08  9:50 ` [PATCH v3 00/12] " Wolfram Sang
@ 2023-12-27  4:39 ` Hans Hu
  2023-12-27  4:39   ` [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
                     ` (8 more replies)
  13 siblings, 9 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

In version v4, the patch consists of 8 files. 
This version is based on the latest for-next branch,
with some adjustments as suggested by Wolfram.

Hans Hu (8):
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: rename marcos with prefix WMTI2C_
  i2c: wmt: adjust line length to meet style
  i2c: wmt: split out common files
  i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  i2c: wmt: fix a bug when thread blocked
  i2c: wmt: add platform type VIAI2C_PLAT_WMT
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                            |   8 +
 drivers/i2c/busses/Kconfig             |  10 +
 drivers/i2c/busses/Makefile            |   4 +
 drivers/i2c/busses/i2c-viai2c-common.c | 278 +++++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  79 +++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 139 +++++++++
 drivers/i2c/busses/i2c-wmt.c           | 417 -------------------------
 drivers/i2c/busses/i2c-zhaoxin-plt.c   | 299 ++++++++++++++++++
 8 files changed, 817 insertions(+), 417 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

-- 
2.34.1


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

* [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-27 19:00     ` Wolfram Sang
  2023-12-27  4:39   ` [PATCH v4 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
                     ` (7 subsequent siblings)
  8 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 67 +++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index ec2a8da134e5..e2a8708cd913 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -351,15 +373,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,21 +381,13 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
 	}
 
-	err = i2c_add_adapter(adap);
-	if (err)
-		return err;
-
-	platform_set_drvdata(pdev, i2c_dev);
-
-	return 0;
+	return i2c_add_adapter(adap);
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
-- 
2.34.1


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

* [PATCH v4 2/8] i2c: wmt: rename marcos with prefix WMTI2C_
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
  2023-12-27  4:39   ` [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-27  4:39   ` [PATCH v4 3/8] i2c: wmt: adjust line length to meet style Hans Hu
                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Tweaked a few formatting things: rename marcos with prefix WMTI2C_

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 176 +++++++++++++++++------------------
 1 file changed, 88 insertions(+), 88 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index e2a8708cd913..8b9014a37891 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -20,59 +20,59 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
+#define WMTI2C_REG_CR		0x00
+#define WMTI2C_REG_TCR		0x02
+#define WMTI2C_REG_CSR		0x04
+#define WMTI2C_REG_ISR		0x06
+#define WMTI2C_REG_IMR		0x08
+#define WMTI2C_REG_CDR		0x0A
+#define WMTI2C_REG_TR		0x0C
+#define WMTI2C_REG_MCR		0x0E
+#define WMTI2C_REG_SLAVE_CR	0x10
+#define WMTI2C_REG_SLAVE_SR	0x12
+#define WMTI2C_REG_SLAVE_ISR	0x14
+#define WMTI2C_REG_SLAVE_IMR	0x16
+#define WMTI2C_REG_SLAVE_DR	0x18
+#define WMTI2C_REG_SLAVE_TR	0x1A
 
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define WMTI2C_CR_TX_NEXT_ACK		0x0000
+#define WMTI2C_CR_ENABLE		0x0001
+#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
+#define WMTI2C_CR_TX_END		0x0004
+#define WMTI2C_CR_CPU_RDY		0x0008
+#define WMTI2C_SLAV_MODE_SEL		0x8000
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define WMTI2C_TCR_STANDARD_MODE	0x0000
+#define WMTI2C_TCR_MASTER_WRITE		0x0000
+#define WMTI2C_TCR_HS_MODE		0x2000
+#define WMTI2C_TCR_MASTER_READ		0x4000
+#define WMTI2C_TCR_FAST_MODE		0x8000
+#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define WMTI2C_ISR_NACK_ADDR		0x0001
+#define WMTI2C_ISR_BYTE_END		0x0002
+#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
+#define WMTI2C_ISR_WRITE_ALL		0x0007
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define WMTI2C_IMR_ENABLE_ALL		0x0007
 
 /* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
+#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
+#define WMTI2C_CSR_READY_MASK		0x0002
 
 /* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
 
 /* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
@@ -92,7 +92,7 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	unsigned long timeout;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
@@ -113,10 +113,10 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
@@ -135,28 +135,28 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val &= ~WMTI2C_CR_TX_END;
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -166,25 +166,25 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
+		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
 			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
+			writew(val, i2c_dev->base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+								WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		}
 	}
 
@@ -197,27 +197,27 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= WMTI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c_dev->base + WMTI2C_REG_CR);
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -225,13 +225,13 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -278,8 +278,8 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	struct wmt_i2c_dev *i2c_dev = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
 
 	complete(&i2c_dev->complete);
 
@@ -335,18 +335,18 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c_dev->base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -371,7 +371,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
 
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
@@ -395,7 +395,7 @@ static void wmt_i2c_remove(struct platform_device *pdev)
 	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
+	writew(0, i2c_dev->base + WMTI2C_REG_IMR);
 	clk_disable_unprepare(i2c_dev->clk);
 	i2c_del_adapter(&i2c_dev->adapter);
 }
-- 
2.34.1


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

* [PATCH v4 3/8] i2c: wmt: adjust line length to meet style
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
  2023-12-27  4:39   ` [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
  2023-12-27  4:39   ` [PATCH v4 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-27  4:39   ` [PATCH v4 4/8] i2c: wmt: split out common files Hans Hu
                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Tweaked a few formatting things:
rename wmt_i2c_dev to wmt_i2c, i2c_dev to i2c, etc. 

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 199 ++++++++++++++++++-----------------
 1 file changed, 104 insertions(+), 95 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 8b9014a37891..1b2b1c68c306 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -76,7 +76,7 @@
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct wmt_i2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -87,14 +87,16 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
 {
 	unsigned long timeout;
+	void __iomem *base = i2c->base;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev,
+					"timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -103,31 +105,32 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+static int wmt_check_status(struct wmt_i2c *i2c)
 {
 	int ret = 0;
 	unsigned long wait_result;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+	wait_result = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
+	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
+static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
 			 int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
+	void __iomem *base = i2c->base;
 
 	if (pmsg->len == 0) {
 		/*
@@ -135,69 +138,73 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(0, base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val &= ~WMTI2C_CR_TX_END;
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
-		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(base + WMTI2C_REG_CSR);
+		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
-			writew(val, i2c_dev->base + WMTI2C_REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
+				| WMTI2C_CR_ENABLE;
+			writew(val, base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
+					base + WMTI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
 
-	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val = readw(base + WMTI2C_REG_CR);
 	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
@@ -206,32 +213,33 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	if (pmsg->len == 1)
 		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + WMTI2C_REG_CR);
+	writew(val, base + WMTI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
 			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -244,20 +252,20 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap,
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = wmt_i2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = wmt_i2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
@@ -275,78 +283,79 @@ static const struct i2c_algorithm wmt_i2c_algo = {
 
 static irqreturn_t wmt_i2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct wmt_i2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
+	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
 {
 	int err;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
 {
 	int err;
+	void __iomem *base = i2c->base;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
-	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
+	writew(0, base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+	readw(base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
 
-	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
+	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
 	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -354,34 +363,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = wmt_i2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
+		i2c->tcr = WMTI2C_TCR_FAST_MODE;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
@@ -392,12 +401,12 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 static void wmt_i2c_remove(struct platform_device *pdev)
 {
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + WMTI2C_REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	writew(0, i2c->base + WMTI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.34.1


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

* [PATCH v4 4/8] i2c: wmt: split out common files
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
                     ` (2 preceding siblings ...)
  2023-12-27  4:39   ` [PATCH v4 3/8] i2c: wmt: adjust line length to meet style Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-27  4:39   ` [PATCH v4 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Since the I2C IP of both wmt and zhaoxin come from VIA,
the common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-wmt-plt.c.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/Makefile            |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++
 drivers/i2c/busses/i2c-wmt.c           | 431 -------------------------
 5 files changed, 439 insertions(+), 431 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3757b9391e60..2ac59c585c08 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -120,7 +120,9 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-wmt-plt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
+
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
 i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 000000000000..76058d6853a7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
+{
+	unsigned long timeout;
+	void __iomem *base = i2c->base;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c->dev,
+					"timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+static int wmt_check_status(struct wmt_i2c *i2c)
+{
+	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
+		ret = -EIO;
+
+	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+	struct wmt_i2c *i2c = data;
+
+	/* save the status and write-clear it */
+	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
+
+	complete(&i2c->complete);
+
+	return IRQ_HANDLED;
+}
+
+static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
+			 int last)
+{
+	u16 val, tcr_val = i2c->tcr;
+	int ret;
+	int xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, base + WMTI2C_REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(base + WMTI2C_REG_CR);
+		val &= ~WMTI2C_CR_TX_END;
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	reinit_completion(&i2c->complete);
+
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+
+	writew(tcr_val, base + WMTI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c);
+		if (ret)
+			return ret;
+
+		xfer_len++;
+
+		val = readw(base + WMTI2C_REG_CSR);
+		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
+				| WMTI2C_CR_ENABLE;
+			writew(val, base + WMTI2C_REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (last != 1)
+				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
+					base + WMTI2C_REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c->tcr;
+	int ret;
+	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	val = readw(base + WMTI2C_REG_CR);
+	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= WMTI2C_CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+
+	writew(val, base + WMTI2C_REG_CR);
+
+	reinit_completion(&i2c->complete);
+
+	tcr_val |= WMTI2C_TCR_MASTER_READ
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+
+	writew(tcr_val, base + WMTI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c);
+		if (ret)
+			return ret;
+
+		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	return 0;
+}
+
+int wmt_i2c_xfer(struct i2c_adapter *adap,
+			struct i2c_msg msgs[],
+			int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = wmt_i2c_read(i2c, pmsg);
+		else
+			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
+{
+	int err;
+	struct wmt_i2c *i2c;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
+
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+					0, pdev->name, i2c);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c->irq);
+
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
+
+	*pi2c = i2c;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 000000000000..e57da0dc68a5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+/* REG_CR Bit fields */
+#define WMTI2C_REG_CR		0x00
+#define WMTI2C_CR_TX_NEXT_ACK		0x0000
+#define WMTI2C_CR_ENABLE		0x0001
+#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
+#define WMTI2C_CR_TX_END		0x0004
+#define WMTI2C_CR_CPU_RDY		0x0008
+
+/* REG_TCR Bit fields */
+#define WMTI2C_REG_TCR		0x02
+#define WMTI2C_TCR_STANDARD_MODE	0x0000
+#define WMTI2C_TCR_MASTER_WRITE		0x0000
+#define WMTI2C_TCR_HS_MODE		0x2000
+#define WMTI2C_TCR_MASTER_READ		0x4000
+#define WMTI2C_TCR_FAST_MODE		0x8000
+#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
+
+/* REG_CSR Bit fields */
+#define WMTI2C_REG_CSR		0x04
+#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
+#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
+#define WMTI2C_CSR_READY_MASK		0x0002
+
+/* REG_ISR Bit fields */
+#define WMTI2C_REG_ISR		0x06
+#define WMTI2C_ISR_NACK_ADDR		0x0001
+#define WMTI2C_ISR_BYTE_END		0x0002
+#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
+#define WMTI2C_ISR_WRITE_ALL		0x0007
+
+/* REG_IMR Bit fields */
+#define WMTI2C_REG_IMR		0x08
+#define WMTI2C_IMR_ENABLE_ALL		0x0007
+
+#define WMTI2C_REG_CDR		0x0A
+#define WMTI2C_REG_TR		0x0C
+#define WMTI2C_REG_MCR		0x0E
+
+struct wmt_i2c {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+};
+
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
new file mode 100644
index 000000000000..e0ffccf8a40a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+/* REG_TR */
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
+
+/* REG_MCR */
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= wmt_i2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
+{
+	int err;
+	void __iomem *base = i2c->base;
+
+	err = clk_prepare_enable(i2c->clk);
+	if (err) {
+		dev_err(i2c->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c->clk, 20000000);
+	if (err) {
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
+		return err;
+	}
+
+	writew(0, base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+	readw(base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+
+	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
+	else
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c *i2c;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = wmt_i2c_init(pdev, &i2c);
+	if (err)
+		return err;
+
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+		i2c->tcr = WMTI2C_TCR_FAST_MODE;
+
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	return i2c_add_adapter(adap);
+}
+
+static void wmt_i2c_remove(struct platform_device *pdev)
+{
+	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
+
+	/* Disable interrupts, clock and delete adapter */
+	writew(0, i2c->base + WMTI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.remove_new	= wmt_i2c_remove,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index 1b2b1c68c306..000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,431 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define WMTI2C_REG_CR		0x00
-#define WMTI2C_REG_TCR		0x02
-#define WMTI2C_REG_CSR		0x04
-#define WMTI2C_REG_ISR		0x06
-#define WMTI2C_REG_IMR		0x08
-#define WMTI2C_REG_CDR		0x0A
-#define WMTI2C_REG_TR		0x0C
-#define WMTI2C_REG_MCR		0x0E
-#define WMTI2C_REG_SLAVE_CR	0x10
-#define WMTI2C_REG_SLAVE_SR	0x12
-#define WMTI2C_REG_SLAVE_ISR	0x14
-#define WMTI2C_REG_SLAVE_IMR	0x16
-#define WMTI2C_REG_SLAVE_DR	0x18
-#define WMTI2C_REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define WMTI2C_CR_TX_NEXT_ACK		0x0000
-#define WMTI2C_CR_ENABLE		0x0001
-#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
-#define WMTI2C_CR_TX_END		0x0004
-#define WMTI2C_CR_CPU_RDY		0x0008
-#define WMTI2C_SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define WMTI2C_TCR_STANDARD_MODE	0x0000
-#define WMTI2C_TCR_MASTER_WRITE		0x0000
-#define WMTI2C_TCR_HS_MODE		0x2000
-#define WMTI2C_TCR_MASTER_READ		0x4000
-#define WMTI2C_TCR_FAST_MODE		0x8000
-#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define WMTI2C_ISR_NACK_ADDR		0x0001
-#define WMTI2C_ISR_BYTE_END		0x0002
-#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
-#define WMTI2C_ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define WMTI2C_IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
-#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
-#define WMTI2C_CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define WMTI2C_TR_STD			0x0064
-#define WMTI2C_TR_HS			0x0019
-
-/* REG_MCR */
-#define WMTI2C_MCR_APB_96M		7
-#define WMTI2C_MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
-{
-	unsigned long timeout;
-	void __iomem *base = i2c->base;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c->dev,
-					"timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c *i2c)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	int xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, base + WMTI2C_REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(base + WMTI2C_REG_CR);
-		val &= ~WMTI2C_CR_TX_END;
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CSR);
-		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
-				| WMTI2C_CR_ENABLE;
-			writew(val, base + WMTI2C_REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF,
-					base + WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
-					base + WMTI2C_REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	u32 xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	val = readw(base + WMTI2C_REG_CR);
-	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= WMTI2C_CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-
-	writew(val, base + WMTI2C_REG_CR);
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= WMTI2C_TCR_MASTER_READ
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c, pmsg);
-		else
-			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c *i2c = data;
-
-	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
-
-	complete(&i2c->complete);
-
-	return IRQ_HANDLED;
-}
-
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
-{
-	int err;
-	struct wmt_i2c *i2c;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
-	if (!i2c)
-		return -ENOMEM;
-
-	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c->base))
-		return PTR_ERR(i2c->base);
-
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
-
-	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
-					0, pdev->name, i2c);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c->irq);
-
-	i2c->dev = &pdev->dev;
-	init_completion(&i2c->complete);
-	platform_set_drvdata(pdev, i2c);
-
-	*pi2c = i2c;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
-{
-	int err;
-	void __iomem *base = i2c->base;
-
-	err = clk_prepare_enable(i2c->clk);
-	if (err) {
-		dev_err(i2c->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c->clk, 20000000);
-	if (err) {
-		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c->clk);
-		return err;
-	}
-
-	writew(0, base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-	readw(base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-
-	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
-	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c *i2c;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c);
-	if (err)
-		return err;
-
-	i2c->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c->tcr = WMTI2C_TCR_FAST_MODE;
-
-	adap = &i2c->adapter;
-	i2c_set_adapdata(adap, i2c);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	return i2c_add_adapter(adap);
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c->base + WMTI2C_REG_IMR);
-	clk_disable_unprepare(i2c->clk);
-	i2c_del_adapter(&i2c->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.34.1


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

* [PATCH v4 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
                     ` (3 preceding siblings ...)
  2023-12-27  4:39   ` [PATCH v4 4/8] i2c: wmt: split out common files Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-27  4:39   ` [PATCH v4 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Since the I2C IP of both wmt and zhaoxin come from VIA.
So, rename common register, function and variable's name
to VIAI2C_ and viai2c_.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 118 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |  60 ++++++-------
 drivers/i2c/busses/i2c-wmt-plt.c       |  30 ++++---
 3 files changed, 105 insertions(+), 103 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 76058d6853a7..60a4d4ccaf12 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,15 +2,15 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
+static int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
 	unsigned long timeout;
 	void __iomem *base = i2c->base;
 
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+	timeout = jiffies + VIAI2C_TIMEOUT;
+	while (!(readw(base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(i2c->dev,
 					"timeout waiting for bus ready\n");
@@ -22,7 +22,7 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
 	return 0;
 }
 
-static int wmt_check_status(struct wmt_i2c *i2c)
+static int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
 	unsigned long wait_result;
@@ -32,29 +32,29 @@ static int wmt_check_status(struct wmt_i2c *i2c)
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
+	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
+static irqreturn_t viai2c_isr(int irq, void *data)
 {
-	struct wmt_i2c *i2c = data;
+	struct viai2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 			 int last)
 {
 	u16 val, tcr_val = i2c->tcr;
@@ -68,143 +68,143 @@ static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, base + WMTI2C_REG_CDR);
+		writew(0, base + VIAI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(base + WMTI2C_REG_CR);
-		val &= ~WMTI2C_CR_TX_END;
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	reinit_completion(&i2c->complete);
 
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (VIAI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & VIAI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
+		ret = viai2c_wait_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(base + WMTI2C_REG_CSR);
-		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+		val = readw(base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
 			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
-				| WMTI2C_CR_ENABLE;
-			writew(val, base + WMTI2C_REG_CR);
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY
+				| VIAI2C_CR_ENABLE;
+			writew(val, base + VIAI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
-					base + WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
-					base + WMTI2C_REG_CR);
+					base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
+					base + VIAI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
 	void __iomem *base = i2c->base;
 
-	val = readw(base + WMTI2C_REG_CR);
-	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
+	val = readw(base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= WMTI2C_CR_CPU_RDY;
+		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		val |= VIAI2C_CR_RX_END;
 
-	writew(val, base + WMTI2C_REG_CR);
+	writew(val, base + VIAI2C_REG_CR);
 
 	reinit_completion(&i2c->complete);
 
-	tcr_val |= WMTI2C_TCR_MASTER_READ
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+	tcr_val |= VIAI2C_TCR_MASTER_READ
+		| (pmsg->addr & VIAI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
+		ret = viai2c_wait_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(base + VIAI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, base + WMTI2C_REG_CR);
+			val |= VIAI2C_CR_RX_END;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	return 0;
 }
 
-int wmt_i2c_xfer(struct i2c_adapter *adap,
+int viai2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg msgs[],
 			int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
+	struct viai2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c);
+			ret = viai2c_wait_bus_ready(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
+			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 {
 	int err;
-	struct wmt_i2c *i2c;
+	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
 	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
@@ -219,7 +219,7 @@ int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
 	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
 					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index e57da0dc68a5..f171f81e4d0f 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -12,44 +12,44 @@
 #include <linux/platform_device.h>
 
 /* REG_CR Bit fields */
-#define WMTI2C_REG_CR		0x00
-#define WMTI2C_CR_TX_NEXT_ACK		0x0000
-#define WMTI2C_CR_ENABLE		0x0001
-#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
-#define WMTI2C_CR_TX_END		0x0004
-#define WMTI2C_CR_CPU_RDY		0x0008
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
 
 /* REG_TCR Bit fields */
-#define WMTI2C_REG_TCR		0x02
-#define WMTI2C_TCR_STANDARD_MODE	0x0000
-#define WMTI2C_TCR_MASTER_WRITE		0x0000
-#define WMTI2C_TCR_HS_MODE		0x2000
-#define WMTI2C_TCR_MASTER_READ		0x4000
-#define WMTI2C_TCR_FAST_MODE		0x8000
-#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_MASTER_WRITE		0x0000
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_MASTER_READ		BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+#define VIAI2C_TCR_SLAVE_ADDR_MASK	GENMASK(6, 0)
 
 /* REG_CSR Bit fields */
-#define WMTI2C_REG_CSR		0x04
-#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
-#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
-#define WMTI2C_CSR_READY_MASK		0x0002
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
 
 /* REG_ISR Bit fields */
-#define WMTI2C_REG_ISR		0x06
-#define WMTI2C_ISR_NACK_ADDR		0x0001
-#define WMTI2C_ISR_BYTE_END		0x0002
-#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
-#define WMTI2C_ISR_WRITE_ALL		0x0007
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
 
 /* REG_IMR Bit fields */
-#define WMTI2C_REG_IMR		0x08
-#define WMTI2C_IMR_ENABLE_ALL		0x0007
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
 
-#define WMTI2C_REG_CDR		0x0A
-#define WMTI2C_REG_TR		0x0C
-#define WMTI2C_REG_MCR		0x0E
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
 
-struct wmt_i2c {
+struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -60,7 +60,7 @@ struct wmt_i2c {
 	u16			cmd_status;
 };
 
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
index e0ffccf8a40a..8f506888cff7 100644
--- a/drivers/i2c/busses/i2c-wmt-plt.c
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -22,13 +22,15 @@
 #define WMTI2C_MCR_APB_96M		7
 #define WMTI2C_MCR_APB_166M		12
 
+#define wmt_i2c				viai2c
+
 static u32 wmt_i2c_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
 }
 
 static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
+	.master_xfer	= viai2c_xfer,
 	.functionality	= wmt_i2c_func,
 };
 
@@ -50,18 +52,18 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
 		return err;
 	}
 
-	writew(0, base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-	readw(base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(0, base + VIAI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+	readw(base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
 
-	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + VIAI2C_REG_TR);
 	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + VIAI2C_REG_TR);
 
 	return 0;
 }
@@ -74,7 +76,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
@@ -86,7 +88,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c->tcr = WMTI2C_TCR_FAST_MODE;
+		i2c->tcr = VIAI2C_TCR_FAST;
 
 	adap = &i2c->adapter;
 	i2c_set_adapdata(adap, i2c);
@@ -110,7 +112,7 @@ static void wmt_i2c_remove(struct platform_device *pdev)
 	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c->base + WMTI2C_REG_IMR);
+	writew(0, i2c->base + VIAI2C_REG_IMR);
 	clk_disable_unprepare(i2c->clk);
 	i2c_del_adapter(&i2c->adapter);
 }
-- 
2.34.1


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

* [PATCH v4 6/8] i2c: wmt: fix a bug when thread blocked
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
                     ` (4 preceding siblings ...)
  2023-12-27  4:39   ` [PATCH v4 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-27  4:39   ` [PATCH v4 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
                     ` (2 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

During each byte access, the host performs clock stretching.
In this case, the thread may be interrupted by preemption,
resulting in a long stretching time.
However, some touchpad can only tolerate host clock stretching
of no more than 200 ms. We reduce the impact of this through
a retransmission mechanism.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 37 +++++++++++++++++++++-----
 drivers/i2c/busses/i2c-viai2c-common.h |  2 ++
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 60a4d4ccaf12..e5eca10efedc 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,7 +2,8 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
+#define VIAI2C_STRETCHING_TIMEOUT	200
 
 static int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
@@ -25,12 +26,35 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
 static int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
-	unsigned long wait_result;
+	unsigned long time_left;
+	unsigned long delta_ms;
+
+	time_left = wait_for_completion_timeout(&i2c->complete,
+						VIAI2C_TIMEOUT);
+	if (!time_left) {
+		dev_err(i2c->dev, "bus transfer timeout\n");
+		return -EIO;
+	}
 
-	wait_result = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
+	/*
+	 * During each byte access, the host performs clock stretching.
+	 * In this case, the thread may be interrupted by preemption,
+	 * resulting in a long stretching time.
+	 * However, some touchpad can only tolerate host clock stretching
+	 * of no more than 200 ms. We reduce the impact of this through
+	 * a retransmission mechanism.
+	 */
+	local_irq_disable();
+	i2c->to = ktime_get();
+	delta_ms = ktime_to_ms(ktime_sub(i2c->to, i2c->ti));
+	if (delta_ms > VIAI2C_STRETCHING_TIMEOUT) {
+		local_irq_enable();
+		dev_warn(i2c->dev, "thread blocked more than %ldms\n",
+				delta_ms);
+		return -EAGAIN;
+	}
+	i2c->ti = i2c->to;
+	local_irq_enable();
 
 	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
@@ -184,6 +208,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	int ret = 0;
 	struct viai2c *i2c = i2c_get_adapdata(adap);
 
+	i2c->to = i2c->ti = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index f171f81e4d0f..73a88398d763 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -58,6 +58,8 @@ struct viai2c {
 	u16			tcr;
 	int			irq;
 	u16			cmd_status;
+	ktime_t			ti;
+	ktime_t			to;
 };
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-- 
2.34.1


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

* [PATCH v4 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
                     ` (5 preceding siblings ...)
  2023-12-27  4:39   ` [PATCH v4 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-27  4:39   ` [PATCH v4 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Enumeration variables are added to differentiate between different platforms

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 34 ++++++++++++++++----------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 +++++-
 drivers/i2c/busses/i2c-wmt-plt.c       |  2 +-
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index e5eca10efedc..56c538653da1 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -78,8 +78,7 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
-			 int last)
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
@@ -97,7 +96,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -111,7 +110,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -138,7 +137,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 		}
 
 		if (xfer_len == pmsg->len) {
-			if (last != 1)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
@@ -161,7 +160,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -176,7 +175,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -211,7 +210,8 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	i2c->to = i2c->ti = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if ((i2c->platform == VIAI2C_PLAT_WMT) 
+		   && !(pmsg->flags & I2C_M_NOSTART)) {
 			ret = viai2c_wait_bus_ready(i2c);
 			if (ret < 0)
 				return ret;
@@ -226,9 +226,10 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	return (ret < 0) ? ret : i;
 }
 
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 {
 	int err;
+	int irq_flags;
 	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
@@ -240,12 +241,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 	if (IS_ERR(i2c->base))
 		return PTR_ERR(i2c->base);
 
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
+	if (plat == VIAI2C_PLAT_WMT) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				"wrong platform type\n");
+
+	i2c->platform = plat;
 
 	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
-					0, pdev->name, i2c);
+					irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
 				"failed to request irq %i\n", i2c->irq);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 73a88398d763..39c0c12326a7 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -49,6 +49,10 @@
 #define VIAI2C_REG_TR		0x0C
 #define VIAI2C_REG_MCR		0x0E
 
+enum {
+	VIAI2C_PLAT_WMT = 1,
+};
+
 struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
@@ -60,9 +64,10 @@ struct viai2c {
 	u16			cmd_status;
 	ktime_t			ti;
 	ktime_t			to;
+	u8			platform;
 };
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
index 8f506888cff7..6afb830eeb40 100644
--- a/drivers/i2c/busses/i2c-wmt-plt.c
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -76,7 +76,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = viai2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
 	if (err)
 		return err;
 
-- 
2.34.1


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

* [PATCH v4 8/8] i2c: add zhaoxin i2c controller driver
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
                     ` (6 preceding siblings ...)
  2023-12-27  4:39   ` [PATCH v4 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2023-12-27  4:39   ` Hans Hu
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-27  4:39 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the "IIC1D17" HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                            |   8 +
 drivers/i2c/busses/Kconfig             |  10 +
 drivers/i2c/busses/Makefile            |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c |  21 +-
 drivers/i2c/busses/i2c-viai2c-common.h |   6 +
 drivers/i2c/busses/i2c-zhaoxin-plt.c   | 299 +++++++++++++++++++++++++
 6 files changed, 341 insertions(+), 5 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9104430e148e..c2c914f6a1ec 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10023,6 +10023,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 28eb48dd5b32..6ccc9f858c90 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -336,6 +336,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 2ac59c585c08..1d2d7e9e576e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-zhaoxin-plt.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 56c538653da1..94cd6cfee7ed 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -5,7 +5,7 @@
 #define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
 #define VIAI2C_STRETCHING_TIMEOUT	200
 
-static int viai2c_wait_bus_ready(struct viai2c *i2c)
+int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
 	unsigned long timeout;
 	void __iomem *base = i2c->base;
@@ -23,7 +23,7 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
 	return 0;
 }
 
-static int viai2c_wait_status(struct viai2c *i2c)
+int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
 	unsigned long time_left;
@@ -71,6 +71,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!i2c->cmd_status)
+		return IRQ_NONE;
+
 	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
@@ -139,6 +142,8 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 		if (xfer_len == pmsg->len) {
 			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && last)
+				writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
 					base + VIAI2C_REG_CDR);
@@ -150,7 +155,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 	return 0;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
@@ -175,7 +180,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART))
+           || (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -218,7 +224,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
@@ -246,6 +252,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 		i2c->irq = irq_of_parse_and_map(np, 0);
 		if (!i2c->irq)
 			return -EINVAL;
+	} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	} else
 		return dev_err_probe(&pdev->dev, -EINVAL,
 				"wrong platform type\n");
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 39c0c12326a7..e7a08943460f 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -51,6 +51,7 @@
 
 enum {
 	VIAI2C_PLAT_WMT = 1,
+	VIAI2C_PLAT_ZHAOXIN
 };
 
 struct viai2c {
@@ -65,8 +66,13 @@ struct viai2c {
 	ktime_t			ti;
 	ktime_t			to;
 	u8			platform;
+	u8			hrv;
+	u16			tr;
+	u16			mcr;
 };
 
+int viai2c_wait_status(struct viai2c *i2c);
+int viai2c_wait_bus_ready(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
diff --git a/drivers/i2c/busses/i2c-zhaoxin-plt.c b/drivers/i2c/busses/i2c-zhaoxin-plt.c
new file mode 100644
index 000000000000..409fadf35f9d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-zhaoxin-plt.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2021 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include "i2c-viai2c-common.h"
+
+#define ZX_I2C_NAME             "i2c_zhaoxin"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+#define ZXI2C_FIFO_SIZE		32
+
+/* Structure definition */
+#define zxi2c viai2c
+
+static int zxi2c_fifo_xfer(struct zxi2c *i2c, struct i2c_msg *msg)
+{
+	u16 xfered_len = 0;
+	u16 byte_left = msg->len;
+	u16 tcr_val = i2c->tcr;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+
+	i2c->ti = ktime_get();
+	while (byte_left) {
+		u16 i;
+		u8 tmp;
+		int error;
+		u16 xfer_len = min_t(u16, byte_left, ZXI2C_FIFO_SIZE);
+
+		byte_left -= xfer_len;
+
+		/* reset fifo buffer */
+		tmp = ioread8(base + ZXI2C_REG_HCR);
+		iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+		/* set xfer len */
+		if (read) {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HRLR);
+		} else {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HTLR);
+			/* set write data */
+			for (i = 0; i < xfer_len; i++)
+				iowrite8(msg->buf[xfered_len + i],
+						base + ZXI2C_REG_HTDR);
+		}
+
+		/* prepare to stop transmission */
+		if (i2c->hrv && !byte_left) {
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+			iowrite8(tmp, base + VIAI2C_REG_CR);
+		}
+
+		reinit_completion(&i2c->complete);
+
+		if (xfered_len) {
+			/* continue transmission */
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			iowrite8(tmp |= VIAI2C_CR_CPU_RDY,
+					i2c->base + VIAI2C_REG_CR);
+		} else {
+			/* start transmission */
+			tcr_val |= (read ? VIAI2C_TCR_MASTER_READ : 0);
+			writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+		}
+
+		error = viai2c_wait_status(i2c);
+		if (error)
+			return error;
+
+		/* get the received data */
+		if (read)
+			for (i = 0; i < xfer_len; i++)
+				msg->buf[xfered_len + i] =
+					ioread8(base + ZXI2C_REG_HRDR);
+
+		xfered_len += xfer_len;
+	}
+
+	return 1;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct zxi2c *i2c = (struct zxi2c *)i2c_get_adapdata(adap);
+
+	ret = viai2c_wait_bus_ready(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 &&
+	   (i2c->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND,
+				i2c->base + VIAI2C_REG_IMR);
+
+		i2c->ti = i2c->to = ktime_get();
+		ret = zxi2c_fifo_xfer(i2c, msgs);
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE,
+				i2c->base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret < 0)
+			iowrite16(tmp | VIAI2C_CR_END_MASK,
+					i2c->base + VIAI2C_REG_CR);
+		/* make sure the state machine is stopped */
+		usleep_range(1, 2);
+	}
+	/* dis interrupt */
+	iowrite8(0, i2c->base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct zxi2c *i2c)
+{
+	iowrite16(i2c->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(i2c->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct zxi2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
+				params[0], fstp, params[2]);
+		i2c->tr = params[2] | 0xff00;
+	} else {
+		i2c->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	i2c->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0000 1000 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		i2c->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n",
+			i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct zxi2c *i2c;
+	struct pci_dev *pci;
+	struct i2c_adapter *adap;
+
+	error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
+	if (error)
+		return error;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	i2c->platform = VIAI2C_PLAT_ZHAOXIN;
+	i2c->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->retries = 2;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	pci = to_pci_dev(pdev->dev.parent);
+	snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
+		dev_name(&pci->dev), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int zxi2c_resume(struct device *dev)
+{
+	struct zxi2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = ZX_I2C_NAME,
+		.acpi_match_table = zxi2c_acpi_match,
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* Re: [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init
  2023-12-27  4:39   ` [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2023-12-27 19:00     ` Wolfram Sang
  2023-12-28  2:05       ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2023-12-27 19:00 UTC (permalink / raw)
  To: Hans Hu; +Cc: linux-i2c, andi.shyti, cobechen

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

On Wed, Dec 27, 2023 at 12:39:44PM +0800, Hans Hu wrote:
> Some common initialization actions are put in the function
> wmt_i2c_init(), which is convenient to share with zhaoxin.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

I get a build error:

  CC      drivers/i2c/busses/i2c-wmt.o
drivers/i2c/busses/i2c-wmt.c:289:5: error: no previous prototype for ‘wmt_i2c_init’ [-Werror=missing-prototypes]
  289 | int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
      |     ^~~~~~~~~~~~

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init
  2023-12-27 19:00     ` Wolfram Sang
@ 2023-12-28  2:05       ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  2:05 UTC (permalink / raw)
  To: Wolfram Sang, linux-i2c, andi.shyti, cobechen


On 2023/12/28 03:00, Wolfram Sang wrote:
> On Wed, Dec 27, 2023 at 12:39:44PM +0800, Hans Hu wrote:
>> Some common initialization actions are put in the function
>> wmt_i2c_init(), which is convenient to share with zhaoxin.
>>
>> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> I get a build error:
>
>    CC      drivers/i2c/busses/i2c-wmt.o
> drivers/i2c/busses/i2c-wmt.c:289:5: error: no previous prototype for ‘wmt_i2c_init’ [-Werror=missing-prototypes]
>    289 | int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
>        |     ^~~~~~~~~~~~


Sorry, I only checked after the last V4 patch using sparse/cocci/smatch. 
Fixed V5 will be re-sent within an hour.


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

* [PATCH v5 0/8] i2c: add zhaoxin i2c controller driver
  2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
                     ` (7 preceding siblings ...)
  2023-12-27  4:39   ` [PATCH v4 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2023-12-28  3:17   ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
                       ` (8 more replies)
  8 siblings, 9 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

In version v4, the patch consists of 8 files.
This version is based on the latest for-next branch,
with some adjustments as suggested by Wolfram.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Hans Hu (8):
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: rename marcos with prefix WMTI2C_
  i2c: wmt: adjust line length to meet style
  i2c: wmt: split out common files
  i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  i2c: wmt: fix a bug when thread blocked
  i2c: wmt: add platform type VIAI2C_PLAT_WMT
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                            |  10 +-
 drivers/i2c/busses/Kconfig             |  10 +
 drivers/i2c/busses/Makefile            |   4 +
 drivers/i2c/busses/i2c-viai2c-common.c | 278 +++++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  79 +++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 139 +++++++++
 drivers/i2c/busses/i2c-wmt.c           | 417 -------------------------
 drivers/i2c/busses/i2c-zhaoxin-plt.c   | 298 ++++++++++++++++++
 8 files changed, 817 insertions(+), 418 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

-- 
2.34.1


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

* [PATCH v5 1/8] i2c: wmt: create wmt_i2c_init for general init
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
                       ` (7 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

v4->v5:
	add previous prototype 'static' for wmt_i2c_init().

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 67 +++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index ec2a8da134e5..f1888f100d83 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -351,15 +373,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,21 +381,13 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
 	}
 
-	err = i2c_add_adapter(adap);
-	if (err)
-		return err;
-
-	platform_set_drvdata(pdev, i2c_dev);
-
-	return 0;
+	return i2c_add_adapter(adap);
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
-- 
2.34.1


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

* [PATCH v5 2/8] i2c: wmt: rename marcos with prefix WMTI2C_
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
  2023-12-28  3:17     ` [PATCH v5 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 3/8] i2c: wmt: adjust line length to meet style Hans Hu
                       ` (6 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Tweaked a few formatting things: rename marcos with prefix WMTI2C_

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 176 +++++++++++++++++------------------
 1 file changed, 88 insertions(+), 88 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index f1888f100d83..95d739fde34f 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -20,59 +20,59 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
+#define WMTI2C_REG_CR		0x00
+#define WMTI2C_REG_TCR		0x02
+#define WMTI2C_REG_CSR		0x04
+#define WMTI2C_REG_ISR		0x06
+#define WMTI2C_REG_IMR		0x08
+#define WMTI2C_REG_CDR		0x0A
+#define WMTI2C_REG_TR		0x0C
+#define WMTI2C_REG_MCR		0x0E
+#define WMTI2C_REG_SLAVE_CR	0x10
+#define WMTI2C_REG_SLAVE_SR	0x12
+#define WMTI2C_REG_SLAVE_ISR	0x14
+#define WMTI2C_REG_SLAVE_IMR	0x16
+#define WMTI2C_REG_SLAVE_DR	0x18
+#define WMTI2C_REG_SLAVE_TR	0x1A
 
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define WMTI2C_CR_TX_NEXT_ACK		0x0000
+#define WMTI2C_CR_ENABLE		0x0001
+#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
+#define WMTI2C_CR_TX_END		0x0004
+#define WMTI2C_CR_CPU_RDY		0x0008
+#define WMTI2C_SLAV_MODE_SEL		0x8000
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define WMTI2C_TCR_STANDARD_MODE	0x0000
+#define WMTI2C_TCR_MASTER_WRITE		0x0000
+#define WMTI2C_TCR_HS_MODE		0x2000
+#define WMTI2C_TCR_MASTER_READ		0x4000
+#define WMTI2C_TCR_FAST_MODE		0x8000
+#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define WMTI2C_ISR_NACK_ADDR		0x0001
+#define WMTI2C_ISR_BYTE_END		0x0002
+#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
+#define WMTI2C_ISR_WRITE_ALL		0x0007
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define WMTI2C_IMR_ENABLE_ALL		0x0007
 
 /* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
+#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
+#define WMTI2C_CSR_READY_MASK		0x0002
 
 /* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
 
 /* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
@@ -92,7 +92,7 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	unsigned long timeout;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
@@ -113,10 +113,10 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
@@ -135,28 +135,28 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val &= ~WMTI2C_CR_TX_END;
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -166,25 +166,25 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
+		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
 			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
+			writew(val, i2c_dev->base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+								WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		}
 	}
 
@@ -197,27 +197,27 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= WMTI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c_dev->base + WMTI2C_REG_CR);
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -225,13 +225,13 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -278,8 +278,8 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	struct wmt_i2c_dev *i2c_dev = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
 
 	complete(&i2c_dev->complete);
 
@@ -335,18 +335,18 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c_dev->base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -371,7 +371,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
 
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
@@ -395,7 +395,7 @@ static void wmt_i2c_remove(struct platform_device *pdev)
 	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
+	writew(0, i2c_dev->base + WMTI2C_REG_IMR);
 	clk_disable_unprepare(i2c_dev->clk);
 	i2c_del_adapter(&i2c_dev->adapter);
 }
-- 
2.34.1


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

* [PATCH v5 3/8] i2c: wmt: adjust line length to meet style
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
  2023-12-28  3:17     ` [PATCH v5 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
  2023-12-28  3:17     ` [PATCH v5 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 4/8] i2c: wmt: split out common files Hans Hu
                       ` (5 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

v4->v5:
	add previous prototype 'static' for wmt_i2c_init().

Tweaked a few formatting things:
rename wmt_i2c_dev to wmt_i2c, i2c_dev to i2c, etc. 

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 199 ++++++++++++++++++-----------------
 1 file changed, 104 insertions(+), 95 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 95d739fde34f..76fba4ffa126 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -76,7 +76,7 @@
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct wmt_i2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -87,14 +87,16 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
 {
 	unsigned long timeout;
+	void __iomem *base = i2c->base;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev,
+					"timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -103,31 +105,32 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+static int wmt_check_status(struct wmt_i2c *i2c)
 {
 	int ret = 0;
 	unsigned long wait_result;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+	wait_result = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
+	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
+static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
 			 int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
+	void __iomem *base = i2c->base;
 
 	if (pmsg->len == 0) {
 		/*
@@ -135,69 +138,73 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(0, base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val &= ~WMTI2C_CR_TX_END;
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
-		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(base + WMTI2C_REG_CSR);
+		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
-			writew(val, i2c_dev->base + WMTI2C_REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
+				| WMTI2C_CR_ENABLE;
+			writew(val, base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
+					base + WMTI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
 
-	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val = readw(base + WMTI2C_REG_CR);
 	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
@@ -206,32 +213,33 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	if (pmsg->len == 1)
 		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + WMTI2C_REG_CR);
+	writew(val, base + WMTI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
 			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -244,20 +252,20 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap,
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = wmt_i2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = wmt_i2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
@@ -275,78 +283,79 @@ static const struct i2c_algorithm wmt_i2c_algo = {
 
 static irqreturn_t wmt_i2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct wmt_i2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
+	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
 {
 	int err;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
 {
 	int err;
+	void __iomem *base = i2c->base;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
-	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
+	writew(0, base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+	readw(base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
 
-	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
+	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
 	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -354,34 +363,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = wmt_i2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
+		i2c->tcr = WMTI2C_TCR_FAST_MODE;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
@@ -392,12 +401,12 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 static void wmt_i2c_remove(struct platform_device *pdev)
 {
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + WMTI2C_REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	writew(0, i2c->base + WMTI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.34.1


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

* [PATCH v5 4/8] i2c: wmt: split out common files
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
                       ` (2 preceding siblings ...)
  2023-12-28  3:17     ` [PATCH v5 3/8] i2c: wmt: adjust line length to meet style Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
                       ` (4 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Since the I2C IP of both wmt and zhaoxin come from VIA,
the common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-wmt-plt.c.

The MAINTAINERS information will added in patch 0008.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                            |   2 +-
 drivers/i2c/busses/Makefile            |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++
 drivers/i2c/busses/i2c-wmt.c           | 431 -------------------------
 6 files changed, 440 insertions(+), 432 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9104430e148e..c3005c2c9dd2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2988,7 +2988,7 @@ S:	Orphan
 F:	Documentation/devicetree/bindings/i2c/i2c-wmt.txt
 F:	arch/arm/mach-vt8500/
 F:	drivers/clocksource/timer-vt8500.c
-F:	drivers/i2c/busses/i2c-wmt.c
+F:	drivers/i2c/busses/i2c-wmt-plt.c
 F:	drivers/mmc/host/wmt-sdmmc.c
 F:	drivers/pwm/pwm-vt8500.c
 F:	drivers/rtc/rtc-vt8500.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3757b9391e60..2ac59c585c08 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -120,7 +120,9 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-wmt-plt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
+
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
 i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 000000000000..76058d6853a7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
+{
+	unsigned long timeout;
+	void __iomem *base = i2c->base;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c->dev,
+					"timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+static int wmt_check_status(struct wmt_i2c *i2c)
+{
+	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
+		ret = -EIO;
+
+	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+	struct wmt_i2c *i2c = data;
+
+	/* save the status and write-clear it */
+	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
+
+	complete(&i2c->complete);
+
+	return IRQ_HANDLED;
+}
+
+static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
+			 int last)
+{
+	u16 val, tcr_val = i2c->tcr;
+	int ret;
+	int xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, base + WMTI2C_REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(base + WMTI2C_REG_CR);
+		val &= ~WMTI2C_CR_TX_END;
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	reinit_completion(&i2c->complete);
+
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+
+	writew(tcr_val, base + WMTI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c);
+		if (ret)
+			return ret;
+
+		xfer_len++;
+
+		val = readw(base + WMTI2C_REG_CSR);
+		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
+				| WMTI2C_CR_ENABLE;
+			writew(val, base + WMTI2C_REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (last != 1)
+				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
+					base + WMTI2C_REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c->tcr;
+	int ret;
+	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	val = readw(base + WMTI2C_REG_CR);
+	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= WMTI2C_CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+
+	writew(val, base + WMTI2C_REG_CR);
+
+	reinit_completion(&i2c->complete);
+
+	tcr_val |= WMTI2C_TCR_MASTER_READ
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+
+	writew(tcr_val, base + WMTI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c);
+		if (ret)
+			return ret;
+
+		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	return 0;
+}
+
+int wmt_i2c_xfer(struct i2c_adapter *adap,
+			struct i2c_msg msgs[],
+			int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = wmt_i2c_read(i2c, pmsg);
+		else
+			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
+{
+	int err;
+	struct wmt_i2c *i2c;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
+
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+					0, pdev->name, i2c);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c->irq);
+
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
+
+	*pi2c = i2c;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 000000000000..e57da0dc68a5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+/* REG_CR Bit fields */
+#define WMTI2C_REG_CR		0x00
+#define WMTI2C_CR_TX_NEXT_ACK		0x0000
+#define WMTI2C_CR_ENABLE		0x0001
+#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
+#define WMTI2C_CR_TX_END		0x0004
+#define WMTI2C_CR_CPU_RDY		0x0008
+
+/* REG_TCR Bit fields */
+#define WMTI2C_REG_TCR		0x02
+#define WMTI2C_TCR_STANDARD_MODE	0x0000
+#define WMTI2C_TCR_MASTER_WRITE		0x0000
+#define WMTI2C_TCR_HS_MODE		0x2000
+#define WMTI2C_TCR_MASTER_READ		0x4000
+#define WMTI2C_TCR_FAST_MODE		0x8000
+#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
+
+/* REG_CSR Bit fields */
+#define WMTI2C_REG_CSR		0x04
+#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
+#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
+#define WMTI2C_CSR_READY_MASK		0x0002
+
+/* REG_ISR Bit fields */
+#define WMTI2C_REG_ISR		0x06
+#define WMTI2C_ISR_NACK_ADDR		0x0001
+#define WMTI2C_ISR_BYTE_END		0x0002
+#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
+#define WMTI2C_ISR_WRITE_ALL		0x0007
+
+/* REG_IMR Bit fields */
+#define WMTI2C_REG_IMR		0x08
+#define WMTI2C_IMR_ENABLE_ALL		0x0007
+
+#define WMTI2C_REG_CDR		0x0A
+#define WMTI2C_REG_TR		0x0C
+#define WMTI2C_REG_MCR		0x0E
+
+struct wmt_i2c {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+};
+
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
new file mode 100644
index 000000000000..e0ffccf8a40a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+/* REG_TR */
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
+
+/* REG_MCR */
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= wmt_i2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
+{
+	int err;
+	void __iomem *base = i2c->base;
+
+	err = clk_prepare_enable(i2c->clk);
+	if (err) {
+		dev_err(i2c->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c->clk, 20000000);
+	if (err) {
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
+		return err;
+	}
+
+	writew(0, base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+	readw(base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+
+	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
+	else
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c *i2c;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = wmt_i2c_init(pdev, &i2c);
+	if (err)
+		return err;
+
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+		i2c->tcr = WMTI2C_TCR_FAST_MODE;
+
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	return i2c_add_adapter(adap);
+}
+
+static void wmt_i2c_remove(struct platform_device *pdev)
+{
+	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
+
+	/* Disable interrupts, clock and delete adapter */
+	writew(0, i2c->base + WMTI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.remove_new	= wmt_i2c_remove,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index 76fba4ffa126..000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,431 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define WMTI2C_REG_CR		0x00
-#define WMTI2C_REG_TCR		0x02
-#define WMTI2C_REG_CSR		0x04
-#define WMTI2C_REG_ISR		0x06
-#define WMTI2C_REG_IMR		0x08
-#define WMTI2C_REG_CDR		0x0A
-#define WMTI2C_REG_TR		0x0C
-#define WMTI2C_REG_MCR		0x0E
-#define WMTI2C_REG_SLAVE_CR	0x10
-#define WMTI2C_REG_SLAVE_SR	0x12
-#define WMTI2C_REG_SLAVE_ISR	0x14
-#define WMTI2C_REG_SLAVE_IMR	0x16
-#define WMTI2C_REG_SLAVE_DR	0x18
-#define WMTI2C_REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define WMTI2C_CR_TX_NEXT_ACK		0x0000
-#define WMTI2C_CR_ENABLE		0x0001
-#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
-#define WMTI2C_CR_TX_END		0x0004
-#define WMTI2C_CR_CPU_RDY		0x0008
-#define WMTI2C_SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define WMTI2C_TCR_STANDARD_MODE	0x0000
-#define WMTI2C_TCR_MASTER_WRITE		0x0000
-#define WMTI2C_TCR_HS_MODE		0x2000
-#define WMTI2C_TCR_MASTER_READ		0x4000
-#define WMTI2C_TCR_FAST_MODE		0x8000
-#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define WMTI2C_ISR_NACK_ADDR		0x0001
-#define WMTI2C_ISR_BYTE_END		0x0002
-#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
-#define WMTI2C_ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define WMTI2C_IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
-#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
-#define WMTI2C_CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define WMTI2C_TR_STD			0x0064
-#define WMTI2C_TR_HS			0x0019
-
-/* REG_MCR */
-#define WMTI2C_MCR_APB_96M		7
-#define WMTI2C_MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
-{
-	unsigned long timeout;
-	void __iomem *base = i2c->base;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c->dev,
-					"timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c *i2c)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	int xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, base + WMTI2C_REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(base + WMTI2C_REG_CR);
-		val &= ~WMTI2C_CR_TX_END;
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CSR);
-		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
-				| WMTI2C_CR_ENABLE;
-			writew(val, base + WMTI2C_REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF,
-					base + WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
-					base + WMTI2C_REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	u32 xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	val = readw(base + WMTI2C_REG_CR);
-	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= WMTI2C_CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-
-	writew(val, base + WMTI2C_REG_CR);
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= WMTI2C_TCR_MASTER_READ
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c, pmsg);
-		else
-			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c *i2c = data;
-
-	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
-
-	complete(&i2c->complete);
-
-	return IRQ_HANDLED;
-}
-
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
-{
-	int err;
-	struct wmt_i2c *i2c;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
-	if (!i2c)
-		return -ENOMEM;
-
-	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c->base))
-		return PTR_ERR(i2c->base);
-
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
-
-	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
-					0, pdev->name, i2c);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c->irq);
-
-	i2c->dev = &pdev->dev;
-	init_completion(&i2c->complete);
-	platform_set_drvdata(pdev, i2c);
-
-	*pi2c = i2c;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
-{
-	int err;
-	void __iomem *base = i2c->base;
-
-	err = clk_prepare_enable(i2c->clk);
-	if (err) {
-		dev_err(i2c->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c->clk, 20000000);
-	if (err) {
-		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c->clk);
-		return err;
-	}
-
-	writew(0, base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-	readw(base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-
-	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
-	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c *i2c;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c);
-	if (err)
-		return err;
-
-	i2c->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c->tcr = WMTI2C_TCR_FAST_MODE;
-
-	adap = &i2c->adapter;
-	i2c_set_adapdata(adap, i2c);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	return i2c_add_adapter(adap);
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c->base + WMTI2C_REG_IMR);
-	clk_disable_unprepare(i2c->clk);
-	i2c_del_adapter(&i2c->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.34.1


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

* [PATCH v5 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
                       ` (3 preceding siblings ...)
  2023-12-28  3:17     ` [PATCH v5 4/8] i2c: wmt: split out common files Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
                       ` (3 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Since the I2C IP of both wmt and zhaoxin come from VIA.
So, rename common register, function and variable's name
to VIAI2C_ and viai2c_.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 118 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |  60 ++++++-------
 drivers/i2c/busses/i2c-wmt-plt.c       |  30 ++++---
 3 files changed, 105 insertions(+), 103 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 76058d6853a7..60a4d4ccaf12 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,15 +2,15 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
+static int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
 	unsigned long timeout;
 	void __iomem *base = i2c->base;
 
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+	timeout = jiffies + VIAI2C_TIMEOUT;
+	while (!(readw(base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(i2c->dev,
 					"timeout waiting for bus ready\n");
@@ -22,7 +22,7 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
 	return 0;
 }
 
-static int wmt_check_status(struct wmt_i2c *i2c)
+static int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
 	unsigned long wait_result;
@@ -32,29 +32,29 @@ static int wmt_check_status(struct wmt_i2c *i2c)
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
+	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
+static irqreturn_t viai2c_isr(int irq, void *data)
 {
-	struct wmt_i2c *i2c = data;
+	struct viai2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 			 int last)
 {
 	u16 val, tcr_val = i2c->tcr;
@@ -68,143 +68,143 @@ static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, base + WMTI2C_REG_CDR);
+		writew(0, base + VIAI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(base + WMTI2C_REG_CR);
-		val &= ~WMTI2C_CR_TX_END;
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	reinit_completion(&i2c->complete);
 
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (VIAI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & VIAI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
+		ret = viai2c_wait_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(base + WMTI2C_REG_CSR);
-		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+		val = readw(base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
 			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
-				| WMTI2C_CR_ENABLE;
-			writew(val, base + WMTI2C_REG_CR);
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY
+				| VIAI2C_CR_ENABLE;
+			writew(val, base + VIAI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
-					base + WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
-					base + WMTI2C_REG_CR);
+					base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
+					base + VIAI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
 	void __iomem *base = i2c->base;
 
-	val = readw(base + WMTI2C_REG_CR);
-	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
+	val = readw(base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= WMTI2C_CR_CPU_RDY;
+		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		val |= VIAI2C_CR_RX_END;
 
-	writew(val, base + WMTI2C_REG_CR);
+	writew(val, base + VIAI2C_REG_CR);
 
 	reinit_completion(&i2c->complete);
 
-	tcr_val |= WMTI2C_TCR_MASTER_READ
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+	tcr_val |= VIAI2C_TCR_MASTER_READ
+		| (pmsg->addr & VIAI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
+		ret = viai2c_wait_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(base + VIAI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, base + WMTI2C_REG_CR);
+			val |= VIAI2C_CR_RX_END;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	return 0;
 }
 
-int wmt_i2c_xfer(struct i2c_adapter *adap,
+int viai2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg msgs[],
 			int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
+	struct viai2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c);
+			ret = viai2c_wait_bus_ready(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
+			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 {
 	int err;
-	struct wmt_i2c *i2c;
+	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
 	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
@@ -219,7 +219,7 @@ int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
 	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
 					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index e57da0dc68a5..f171f81e4d0f 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -12,44 +12,44 @@
 #include <linux/platform_device.h>
 
 /* REG_CR Bit fields */
-#define WMTI2C_REG_CR		0x00
-#define WMTI2C_CR_TX_NEXT_ACK		0x0000
-#define WMTI2C_CR_ENABLE		0x0001
-#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
-#define WMTI2C_CR_TX_END		0x0004
-#define WMTI2C_CR_CPU_RDY		0x0008
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
 
 /* REG_TCR Bit fields */
-#define WMTI2C_REG_TCR		0x02
-#define WMTI2C_TCR_STANDARD_MODE	0x0000
-#define WMTI2C_TCR_MASTER_WRITE		0x0000
-#define WMTI2C_TCR_HS_MODE		0x2000
-#define WMTI2C_TCR_MASTER_READ		0x4000
-#define WMTI2C_TCR_FAST_MODE		0x8000
-#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_MASTER_WRITE		0x0000
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_MASTER_READ		BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+#define VIAI2C_TCR_SLAVE_ADDR_MASK	GENMASK(6, 0)
 
 /* REG_CSR Bit fields */
-#define WMTI2C_REG_CSR		0x04
-#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
-#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
-#define WMTI2C_CSR_READY_MASK		0x0002
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
 
 /* REG_ISR Bit fields */
-#define WMTI2C_REG_ISR		0x06
-#define WMTI2C_ISR_NACK_ADDR		0x0001
-#define WMTI2C_ISR_BYTE_END		0x0002
-#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
-#define WMTI2C_ISR_WRITE_ALL		0x0007
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
 
 /* REG_IMR Bit fields */
-#define WMTI2C_REG_IMR		0x08
-#define WMTI2C_IMR_ENABLE_ALL		0x0007
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
 
-#define WMTI2C_REG_CDR		0x0A
-#define WMTI2C_REG_TR		0x0C
-#define WMTI2C_REG_MCR		0x0E
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
 
-struct wmt_i2c {
+struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -60,7 +60,7 @@ struct wmt_i2c {
 	u16			cmd_status;
 };
 
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
index e0ffccf8a40a..8f506888cff7 100644
--- a/drivers/i2c/busses/i2c-wmt-plt.c
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -22,13 +22,15 @@
 #define WMTI2C_MCR_APB_96M		7
 #define WMTI2C_MCR_APB_166M		12
 
+#define wmt_i2c				viai2c
+
 static u32 wmt_i2c_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
 }
 
 static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
+	.master_xfer	= viai2c_xfer,
 	.functionality	= wmt_i2c_func,
 };
 
@@ -50,18 +52,18 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
 		return err;
 	}
 
-	writew(0, base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-	readw(base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(0, base + VIAI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+	readw(base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
 
-	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + VIAI2C_REG_TR);
 	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + VIAI2C_REG_TR);
 
 	return 0;
 }
@@ -74,7 +76,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
@@ -86,7 +88,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c->tcr = WMTI2C_TCR_FAST_MODE;
+		i2c->tcr = VIAI2C_TCR_FAST;
 
 	adap = &i2c->adapter;
 	i2c_set_adapdata(adap, i2c);
@@ -110,7 +112,7 @@ static void wmt_i2c_remove(struct platform_device *pdev)
 	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c->base + WMTI2C_REG_IMR);
+	writew(0, i2c->base + VIAI2C_REG_IMR);
 	clk_disable_unprepare(i2c->clk);
 	i2c_del_adapter(&i2c->adapter);
 }
-- 
2.34.1


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

* [PATCH v5 6/8] i2c: wmt: fix a bug when thread blocked
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
                       ` (4 preceding siblings ...)
  2023-12-28  3:17     ` [PATCH v5 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
                       ` (2 subsequent siblings)
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

During each byte access, the host performs clock stretching.
In this case, the thread may be interrupted by preemption,
resulting in a long stretching time.

However, some touchpad can only tolerate host clock stretching
of no more than 200 ms. We reduce the impact of this through
a retransmission mechanism.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 37 +++++++++++++++++++++-----
 drivers/i2c/busses/i2c-viai2c-common.h |  2 ++
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 60a4d4ccaf12..e5eca10efedc 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,7 +2,8 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
+#define VIAI2C_STRETCHING_TIMEOUT	200
 
 static int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
@@ -25,12 +26,35 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
 static int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
-	unsigned long wait_result;
+	unsigned long time_left;
+	unsigned long delta_ms;
+
+	time_left = wait_for_completion_timeout(&i2c->complete,
+						VIAI2C_TIMEOUT);
+	if (!time_left) {
+		dev_err(i2c->dev, "bus transfer timeout\n");
+		return -EIO;
+	}
 
-	wait_result = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
+	/*
+	 * During each byte access, the host performs clock stretching.
+	 * In this case, the thread may be interrupted by preemption,
+	 * resulting in a long stretching time.
+	 * However, some touchpad can only tolerate host clock stretching
+	 * of no more than 200 ms. We reduce the impact of this through
+	 * a retransmission mechanism.
+	 */
+	local_irq_disable();
+	i2c->to = ktime_get();
+	delta_ms = ktime_to_ms(ktime_sub(i2c->to, i2c->ti));
+	if (delta_ms > VIAI2C_STRETCHING_TIMEOUT) {
+		local_irq_enable();
+		dev_warn(i2c->dev, "thread blocked more than %ldms\n",
+				delta_ms);
+		return -EAGAIN;
+	}
+	i2c->ti = i2c->to;
+	local_irq_enable();
 
 	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
@@ -184,6 +208,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	int ret = 0;
 	struct viai2c *i2c = i2c_get_adapdata(adap);
 
+	i2c->to = i2c->ti = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index f171f81e4d0f..73a88398d763 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -58,6 +58,8 @@ struct viai2c {
 	u16			tcr;
 	int			irq;
 	u16			cmd_status;
+	ktime_t			ti;
+	ktime_t			to;
 };
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-- 
2.34.1


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

* [PATCH v5 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
                       ` (5 preceding siblings ...)
  2023-12-28  3:17     ` [PATCH v5 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-28  3:17     ` [PATCH v5 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
  8 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Enumeration variables are added to differentiate between different platforms.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 34 ++++++++++++++++----------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 +++++-
 drivers/i2c/busses/i2c-wmt-plt.c       |  2 +-
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index e5eca10efedc..930f4c5c1797 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -78,8 +78,7 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
-			 int last)
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
@@ -97,7 +96,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -111,7 +110,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -138,7 +137,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 		}
 
 		if (xfer_len == pmsg->len) {
-			if (last != 1)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
@@ -161,7 +160,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -176,7 +175,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -211,7 +210,8 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	i2c->to = i2c->ti = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if ((i2c->platform == VIAI2C_PLAT_WMT)
+		   && !(pmsg->flags & I2C_M_NOSTART)) {
 			ret = viai2c_wait_bus_ready(i2c);
 			if (ret < 0)
 				return ret;
@@ -226,9 +226,10 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	return (ret < 0) ? ret : i;
 }
 
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 {
 	int err;
+	int irq_flags;
 	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
@@ -240,12 +241,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 	if (IS_ERR(i2c->base))
 		return PTR_ERR(i2c->base);
 
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
+	if (plat == VIAI2C_PLAT_WMT) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				"wrong platform type\n");
+
+	i2c->platform = plat;
 
 	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
-					0, pdev->name, i2c);
+					irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
 				"failed to request irq %i\n", i2c->irq);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 73a88398d763..6d210e562c9a 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -49,6 +49,10 @@
 #define VIAI2C_REG_TR		0x0C
 #define VIAI2C_REG_MCR		0x0E
 
+enum {
+	VIAI2C_PLAT_WMT = 1,
+};
+
 struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
@@ -60,9 +64,10 @@ struct viai2c {
 	u16			cmd_status;
 	ktime_t			ti;
 	ktime_t			to;
+	int			platform;
 };
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
index 8f506888cff7..6afb830eeb40 100644
--- a/drivers/i2c/busses/i2c-wmt-plt.c
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -76,7 +76,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = viai2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
 	if (err)
 		return err;
 
-- 
2.34.1


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

* [PATCH v5 8/8] i2c: add zhaoxin i2c controller driver
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
                       ` (6 preceding siblings ...)
  2023-12-28  3:17     ` [PATCH v5 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2023-12-28  3:17     ` Hans Hu
  2023-12-29  5:17       ` kernel test robot
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
  8 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-28  3:17 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the "IIC1D17" HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                            |   8 +
 drivers/i2c/busses/Kconfig             |  10 +
 drivers/i2c/busses/Makefile            |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c |  21 +-
 drivers/i2c/busses/i2c-viai2c-common.h |   6 +
 drivers/i2c/busses/i2c-zhaoxin-plt.c   | 298 +++++++++++++++++++++++++
 6 files changed, 340 insertions(+), 5 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c3005c2c9dd2..aa1a7f314b41 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10023,6 +10023,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 28eb48dd5b32..6ccc9f858c90 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -336,6 +336,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 2ac59c585c08..1d2d7e9e576e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-zhaoxin-plt.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 930f4c5c1797..5e31c5efd10e 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -5,7 +5,7 @@
 #define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
 #define VIAI2C_STRETCHING_TIMEOUT	200
 
-static int viai2c_wait_bus_ready(struct viai2c *i2c)
+int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
 	unsigned long timeout;
 	void __iomem *base = i2c->base;
@@ -23,7 +23,7 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
 	return 0;
 }
 
-static int viai2c_wait_status(struct viai2c *i2c)
+int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
 	unsigned long time_left;
@@ -71,6 +71,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!i2c->cmd_status)
+		return IRQ_NONE;
+
 	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
@@ -139,6 +142,8 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 		if (xfer_len == pmsg->len) {
 			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && last)
+				writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
 					base + VIAI2C_REG_CDR);
@@ -150,7 +155,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 	return 0;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
@@ -175,7 +180,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART))
+	   || (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -218,7 +224,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
@@ -246,6 +252,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 		i2c->irq = irq_of_parse_and_map(np, 0);
 		if (!i2c->irq)
 			return -EINVAL;
+	} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	} else
 		return dev_err_probe(&pdev->dev, -EINVAL,
 				"wrong platform type\n");
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 6d210e562c9a..bcff7026e2b8 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -51,6 +51,7 @@
 
 enum {
 	VIAI2C_PLAT_WMT = 1,
+	VIAI2C_PLAT_ZHAOXIN
 };
 
 struct viai2c {
@@ -65,8 +66,13 @@ struct viai2c {
 	ktime_t			ti;
 	ktime_t			to;
 	int			platform;
+	u8			hrv;
+	u16			tr;
+	u16			mcr;
 };
 
+int viai2c_wait_status(struct viai2c *i2c);
+int viai2c_wait_bus_ready(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
diff --git a/drivers/i2c/busses/i2c-zhaoxin-plt.c b/drivers/i2c/busses/i2c-zhaoxin-plt.c
new file mode 100644
index 000000000000..f9417677c480
--- /dev/null
+++ b/drivers/i2c/busses/i2c-zhaoxin-plt.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2021 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include "i2c-viai2c-common.h"
+
+#define ZX_I2C_NAME             "i2c_zhaoxin"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+#define ZXI2C_FIFO_SIZE		32
+
+/* Structure definition */
+#define zxi2c viai2c
+
+static int zxi2c_fifo_xfer(struct zxi2c *i2c, struct i2c_msg *msg)
+{
+	u16 xfered_len = 0;
+	u16 byte_left = msg->len;
+	u16 tcr_val = i2c->tcr;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+
+	i2c->ti = ktime_get();
+	while (byte_left) {
+		u16 i;
+		u8 tmp;
+		int error;
+		u16 xfer_len = min_t(u16, byte_left, ZXI2C_FIFO_SIZE);
+
+		byte_left -= xfer_len;
+
+		/* reset fifo buffer */
+		tmp = ioread8(base + ZXI2C_REG_HCR);
+		iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+		/* set xfer len */
+		if (read) {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HRLR);
+		} else {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HTLR);
+			/* set write data */
+			for (i = 0; i < xfer_len; i++)
+				iowrite8(msg->buf[xfered_len + i],
+						base + ZXI2C_REG_HTDR);
+		}
+
+		/* prepare to stop transmission */
+		if (i2c->hrv && !byte_left) {
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+			iowrite8(tmp, base + VIAI2C_REG_CR);
+		}
+
+		reinit_completion(&i2c->complete);
+
+		if (xfered_len) {
+			/* continue transmission */
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			iowrite8(tmp |= VIAI2C_CR_CPU_RDY,
+					i2c->base + VIAI2C_REG_CR);
+		} else {
+			/* start transmission */
+			tcr_val |= (read ? VIAI2C_TCR_MASTER_READ : 0);
+			writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+		}
+
+		error = viai2c_wait_status(i2c);
+		if (error)
+			return error;
+
+		/* get the received data */
+		if (read)
+			for (i = 0; i < xfer_len; i++)
+				msg->buf[xfered_len + i] =
+					ioread8(base + ZXI2C_REG_HRDR);
+
+		xfered_len += xfer_len;
+	}
+
+	return 1;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct zxi2c *i2c = (struct zxi2c *)i2c_get_adapdata(adap);
+
+	ret = viai2c_wait_bus_ready(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 &&
+	   (i2c->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND,
+				i2c->base + VIAI2C_REG_IMR);
+
+		i2c->ti = i2c->to = ktime_get();
+		ret = zxi2c_fifo_xfer(i2c, msgs);
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE,
+				i2c->base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret < 0)
+			iowrite16(tmp | VIAI2C_CR_END_MASK,
+					i2c->base + VIAI2C_REG_CR);
+		/* make sure the state machine is stopped */
+		usleep_range(1, 2);
+	}
+	/* dis interrupt */
+	iowrite8(0, i2c->base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct zxi2c *i2c)
+{
+	iowrite16(i2c->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(i2c->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct zxi2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
+				params[0], fstp, params[2]);
+		i2c->tr = params[2] | 0xff00;
+	} else {
+		i2c->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	i2c->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0000 1000 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		i2c->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n",
+			i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct zxi2c *i2c;
+	struct pci_dev *pci;
+	struct i2c_adapter *adap;
+
+	error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
+	if (error)
+		return error;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	i2c->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->retries = 2;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	pci = to_pci_dev(pdev->dev.parent);
+	snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
+		dev_name(&pci->dev), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int zxi2c_resume(struct device *dev)
+{
+	struct zxi2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = ZX_I2C_NAME,
+		.acpi_match_table = zxi2c_acpi_match,
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* Re: [PATCH v5 8/8] i2c: add zhaoxin i2c controller driver
  2023-12-28  3:17     ` [PATCH v5 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2023-12-29  5:17       ` kernel test robot
  0 siblings, 0 replies; 133+ messages in thread
From: kernel test robot @ 2023-12-29  5:17 UTC (permalink / raw)
  To: Hans Hu, wsa, linux-i2c; +Cc: oe-kbuild-all, andi.shyti, cobechen, hanshu-oc

Hi Hans,

kernel test robot noticed the following build warnings:

[auto build test WARNING on wsa/i2c/for-next]
[cannot apply to linus/master v6.7-rc7 next-20231220]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Hans-Hu/i2c-wmt-create-wmt_i2c_init-for-general-init/20231228-112208
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-next
patch link:    https://lore.kernel.org/r/efbdee3ccae776a8f45d3ea5e28fdee334a3c07b.1703733126.git.hanshu-oc%40zhaoxin.com
patch subject: [PATCH v5 8/8] i2c: add zhaoxin i2c controller driver
config: loongarch-randconfig-r081-20231229 (https://download.01.org/0day-ci/archive/20231229/202312291225.cWVt6YF9-lkp@intel.com/config)
compiler: loongarch64-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231229/202312291225.cWVt6YF9-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202312291225.cWVt6YF9-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/i2c/busses/i2c-zhaoxin-plt.c:265:12: warning: 'zxi2c_resume' defined but not used [-Wunused-function]
     265 | static int zxi2c_resume(struct device *dev)
         |            ^~~~~~~~~~~~


vim +/zxi2c_resume +265 drivers/i2c/busses/i2c-zhaoxin-plt.c

   264	
 > 265	static int zxi2c_resume(struct device *dev)
   266	{
   267		struct zxi2c *i2c = dev_get_drvdata(dev);
   268	
   269		iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
   270		zxi2c_set_bus_speed(i2c);
   271	
   272		return 0;
   273	}
   274	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

* [PATCH v6 0/8] i2c: add zhaoxin i2c controller driver
  2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
                       ` (7 preceding siblings ...)
  2023-12-28  3:17     ` [PATCH v5 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2023-12-29  6:30     ` Hans Hu
  2023-12-29  6:30       ` [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
                         ` (9 more replies)
  8 siblings, 10 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

v5->v6:
	fix build warnning reported by kernel test robot
v4->v5:
	fix some build errors.

In version v4, the patch consists of 8 files.
This version is based on the latest for-next branch,
with some adjustments as suggested by Wolfram.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Hans Hu (8):
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: rename marcos with prefix WMTI2C_
  i2c: wmt: adjust line length to meet style
  i2c: wmt: split out common files
  i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  i2c: wmt: fix a bug when thread blocked
  i2c: wmt: add platform type VIAI2C_PLAT_WMT
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                            |  10 +-
 drivers/i2c/busses/Kconfig             |  10 +
 drivers/i2c/busses/Makefile            |   4 +
 drivers/i2c/busses/i2c-viai2c-common.c | 278 +++++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  79 +++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 139 +++++++++
 drivers/i2c/busses/i2c-wmt.c           | 417 -------------------------
 drivers/i2c/busses/i2c-zhaoxin-plt.c   | 298 ++++++++++++++++++
 8 files changed, 817 insertions(+), 418 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

-- 
2.34.1


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

* [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2024-01-03 12:56         ` Andi Shyti
  2023-12-29  6:30       ` [PATCH v6 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
                         ` (8 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

v4->v5:
	add previous prototype 'static' for wmt_i2c_init().

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 67 +++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index ec2a8da134e5..f1888f100d83 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -351,15 +373,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,21 +381,13 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
 	}
 
-	err = i2c_add_adapter(adap);
-	if (err)
-		return err;
-
-	platform_set_drvdata(pdev, i2c_dev);
-
-	return 0;
+	return i2c_add_adapter(adap);
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
-- 
2.34.1


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

* [PATCH v6 2/8] i2c: wmt: rename marcos with prefix WMTI2C_
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
  2023-12-29  6:30       ` [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2024-01-03 13:29         ` Andi Shyti
  2023-12-29  6:30       ` [PATCH v6 3/8] i2c: wmt: adjust line length to meet style Hans Hu
                         ` (7 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Tweaked a few formatting things: rename marcos with prefix WMTI2C_

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 176 +++++++++++++++++------------------
 1 file changed, 88 insertions(+), 88 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index f1888f100d83..95d739fde34f 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -20,59 +20,59 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
+#define WMTI2C_REG_CR		0x00
+#define WMTI2C_REG_TCR		0x02
+#define WMTI2C_REG_CSR		0x04
+#define WMTI2C_REG_ISR		0x06
+#define WMTI2C_REG_IMR		0x08
+#define WMTI2C_REG_CDR		0x0A
+#define WMTI2C_REG_TR		0x0C
+#define WMTI2C_REG_MCR		0x0E
+#define WMTI2C_REG_SLAVE_CR	0x10
+#define WMTI2C_REG_SLAVE_SR	0x12
+#define WMTI2C_REG_SLAVE_ISR	0x14
+#define WMTI2C_REG_SLAVE_IMR	0x16
+#define WMTI2C_REG_SLAVE_DR	0x18
+#define WMTI2C_REG_SLAVE_TR	0x1A
 
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define WMTI2C_CR_TX_NEXT_ACK		0x0000
+#define WMTI2C_CR_ENABLE		0x0001
+#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
+#define WMTI2C_CR_TX_END		0x0004
+#define WMTI2C_CR_CPU_RDY		0x0008
+#define WMTI2C_SLAV_MODE_SEL		0x8000
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define WMTI2C_TCR_STANDARD_MODE	0x0000
+#define WMTI2C_TCR_MASTER_WRITE		0x0000
+#define WMTI2C_TCR_HS_MODE		0x2000
+#define WMTI2C_TCR_MASTER_READ		0x4000
+#define WMTI2C_TCR_FAST_MODE		0x8000
+#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define WMTI2C_ISR_NACK_ADDR		0x0001
+#define WMTI2C_ISR_BYTE_END		0x0002
+#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
+#define WMTI2C_ISR_WRITE_ALL		0x0007
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define WMTI2C_IMR_ENABLE_ALL		0x0007
 
 /* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
+#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
+#define WMTI2C_CSR_READY_MASK		0x0002
 
 /* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
 
 /* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
@@ -92,7 +92,7 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	unsigned long timeout;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
@@ -113,10 +113,10 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
@@ -135,28 +135,28 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val &= ~WMTI2C_CR_TX_END;
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -166,25 +166,25 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
+		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
 			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
+			writew(val, i2c_dev->base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+								WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
 		}
 	}
 
@@ -197,27 +197,27 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= WMTI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c_dev->base + WMTI2C_REG_CR);
 
 	reinit_completion(&i2c_dev->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
@@ -225,13 +225,13 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -278,8 +278,8 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	struct wmt_i2c_dev *i2c_dev = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
 
 	complete(&i2c_dev->complete);
 
@@ -335,18 +335,18 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c_dev->base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -371,7 +371,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
 
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
@@ -395,7 +395,7 @@ static void wmt_i2c_remove(struct platform_device *pdev)
 	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
+	writew(0, i2c_dev->base + WMTI2C_REG_IMR);
 	clk_disable_unprepare(i2c_dev->clk);
 	i2c_del_adapter(&i2c_dev->adapter);
 }
-- 
2.34.1


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

* [PATCH v6 3/8] i2c: wmt: adjust line length to meet style
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
  2023-12-29  6:30       ` [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
  2023-12-29  6:30       ` [PATCH v6 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2024-01-03 16:52         ` Andi Shyti
  2023-12-29  6:30       ` [PATCH v6 4/8] i2c: wmt: split out common files Hans Hu
                         ` (6 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

v4->v5:
	add previous prototype 'static' for wmt_i2c_init().

Tweaked a few formatting things:
rename wmt_i2c_dev to wmt_i2c, i2c_dev to i2c, etc. 

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 199 ++++++++++++++++++-----------------
 1 file changed, 104 insertions(+), 95 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 95d739fde34f..76fba4ffa126 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -76,7 +76,7 @@
 
 #define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct wmt_i2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -87,14 +87,16 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
 {
 	unsigned long timeout;
+	void __iomem *base = i2c->base;
 
 	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev,
+					"timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -103,31 +105,32 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+static int wmt_check_status(struct wmt_i2c *i2c)
 {
 	int ret = 0;
 	unsigned long wait_result;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+	wait_result = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_NACK_ADDR)
+	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
+static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
 			 int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
+	void __iomem *base = i2c->base;
 
 	if (pmsg->len == 0) {
 		/*
@@ -135,69 +138,73 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(0, base + WMTI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + WMTI2C_REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val &= ~WMTI2C_CR_TX_END;
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CSR);
-		if ((val & WMTI2C_CSR_RCV_ACK_MASK) == WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(base + WMTI2C_REG_CSR);
+		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE;
-			writew(val, i2c_dev->base + WMTI2C_REG_CR);
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
+				| WMTI2C_CR_ENABLE;
+			writew(val, base + WMTI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
+					base + WMTI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
 
-	val = readw(i2c_dev->base + WMTI2C_REG_CR);
+	val = readw(base + WMTI2C_REG_CR);
 	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
@@ -206,32 +213,33 @@ static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
 	if (pmsg->len == 1)
 		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
 
-	writew(val, i2c_dev->base + WMTI2C_REG_CR);
+	writew(val, base + WMTI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= WMTI2C_TCR_MASTER_READ | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+	tcr_val |= WMTI2C_TCR_MASTER_READ
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + WMTI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + WMTI2C_REG_CR);
+		val = readw(base + WMTI2C_REG_CR);
 		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = wmt_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + WMTI2C_REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
 			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + WMTI2C_REG_CR);
+		writew(val, base + WMTI2C_REG_CR);
 	}
 
 	return 0;
@@ -244,20 +252,20 @@ static int wmt_i2c_xfer(struct i2c_adapter *adap,
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = wmt_i2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = wmt_i2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
@@ -275,78 +283,79 @@ static const struct i2c_algorithm wmt_i2c_algo = {
 
 static irqreturn_t wmt_i2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct wmt_i2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + WMTI2C_REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + WMTI2C_REG_ISR);
+	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
 {
 	int err;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
 {
 	int err;
+	void __iomem *base = i2c->base;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, i2c_dev->base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, i2c_dev->base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, i2c_dev->base + WMTI2C_REG_CR);
-	readw(i2c_dev->base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, i2c_dev->base + WMTI2C_REG_ISR);
+	writew(0, base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+	readw(base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
 
-	if (i2c_dev->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, i2c_dev->base + WMTI2C_REG_TR);
+	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
 	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, i2c_dev->base + WMTI2C_REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
 
 	return 0;
 }
@@ -354,34 +363,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct wmt_i2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = wmt_i2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = WMTI2C_TCR_FAST_MODE;
+		i2c->tcr = WMTI2C_TCR_FAST_MODE;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
@@ -392,12 +401,12 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 static void wmt_i2c_remove(struct platform_device *pdev)
 {
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + WMTI2C_REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	writew(0, i2c->base + WMTI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.34.1


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

* [PATCH v6 4/8] i2c: wmt: split out common files
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
                         ` (2 preceding siblings ...)
  2023-12-29  6:30       ` [PATCH v6 3/8] i2c: wmt: adjust line length to meet style Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2024-01-03 17:21         ` Andi Shyti
  2023-12-29  6:30       ` [PATCH v6 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
                         ` (5 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Since the I2C IP of both wmt and zhaoxin come from VIA,
the common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-wmt-plt.c.

The MAINTAINERS information will added in patch 0008.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                            |   2 +-
 drivers/i2c/busses/Makefile            |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
 drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++
 drivers/i2c/busses/i2c-wmt.c           | 431 -------------------------
 6 files changed, 440 insertions(+), 432 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-wmt-plt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9104430e148e..c3005c2c9dd2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2988,7 +2988,7 @@ S:	Orphan
 F:	Documentation/devicetree/bindings/i2c/i2c-wmt.txt
 F:	arch/arm/mach-vt8500/
 F:	drivers/clocksource/timer-vt8500.c
-F:	drivers/i2c/busses/i2c-wmt.c
+F:	drivers/i2c/busses/i2c-wmt-plt.c
 F:	drivers/mmc/host/wmt-sdmmc.c
 F:	drivers/pwm/pwm-vt8500.c
 F:	drivers/rtc/rtc-vt8500.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3757b9391e60..2ac59c585c08 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -120,7 +120,9 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-wmt-plt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
+
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
 i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 000000000000..76058d6853a7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,234 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
+{
+	unsigned long timeout;
+	void __iomem *base = i2c->base;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c->dev,
+					"timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+static int wmt_check_status(struct wmt_i2c *i2c)
+{
+	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
+		ret = -EIO;
+
+	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+	struct wmt_i2c *i2c = data;
+
+	/* save the status and write-clear it */
+	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
+
+	complete(&i2c->complete);
+
+	return IRQ_HANDLED;
+}
+
+static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
+			 int last)
+{
+	u16 val, tcr_val = i2c->tcr;
+	int ret;
+	int xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, base + WMTI2C_REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(base + WMTI2C_REG_CR);
+		val &= ~WMTI2C_CR_TX_END;
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	reinit_completion(&i2c->complete);
+
+	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+
+	writew(tcr_val, base + WMTI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c);
+		if (ret)
+			return ret;
+
+		xfer_len++;
+
+		val = readw(base + WMTI2C_REG_CSR);
+		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
+				| WMTI2C_CR_ENABLE;
+			writew(val, base + WMTI2C_REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (last != 1)
+				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF,
+					base + WMTI2C_REG_CDR);
+			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
+					base + WMTI2C_REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c->tcr;
+	int ret;
+	u32 xfer_len = 0;
+	void __iomem *base = i2c->base;
+
+	val = readw(base + WMTI2C_REG_CR);
+	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= WMTI2C_CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+
+	writew(val, base + WMTI2C_REG_CR);
+
+	reinit_completion(&i2c->complete);
+
+	tcr_val |= WMTI2C_TCR_MASTER_READ
+		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+
+	writew(tcr_val, base + WMTI2C_REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(base + WMTI2C_REG_CR);
+		val |= WMTI2C_CR_CPU_RDY;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c);
+		if (ret)
+			return ret;
+
+		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		writew(val, base + WMTI2C_REG_CR);
+	}
+
+	return 0;
+}
+
+int wmt_i2c_xfer(struct i2c_adapter *adap,
+			struct i2c_msg msgs[],
+			int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = wmt_i2c_read(i2c, pmsg);
+		else
+			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
+{
+	int err;
+	struct wmt_i2c *i2c;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
+
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+					0, pdev->name, i2c);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c->irq);
+
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
+
+	*pi2c = i2c;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 000000000000..e57da0dc68a5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+/* REG_CR Bit fields */
+#define WMTI2C_REG_CR		0x00
+#define WMTI2C_CR_TX_NEXT_ACK		0x0000
+#define WMTI2C_CR_ENABLE		0x0001
+#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
+#define WMTI2C_CR_TX_END		0x0004
+#define WMTI2C_CR_CPU_RDY		0x0008
+
+/* REG_TCR Bit fields */
+#define WMTI2C_REG_TCR		0x02
+#define WMTI2C_TCR_STANDARD_MODE	0x0000
+#define WMTI2C_TCR_MASTER_WRITE		0x0000
+#define WMTI2C_TCR_HS_MODE		0x2000
+#define WMTI2C_TCR_MASTER_READ		0x4000
+#define WMTI2C_TCR_FAST_MODE		0x8000
+#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
+
+/* REG_CSR Bit fields */
+#define WMTI2C_REG_CSR		0x04
+#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
+#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
+#define WMTI2C_CSR_READY_MASK		0x0002
+
+/* REG_ISR Bit fields */
+#define WMTI2C_REG_ISR		0x06
+#define WMTI2C_ISR_NACK_ADDR		0x0001
+#define WMTI2C_ISR_BYTE_END		0x0002
+#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
+#define WMTI2C_ISR_WRITE_ALL		0x0007
+
+/* REG_IMR Bit fields */
+#define WMTI2C_REG_IMR		0x08
+#define WMTI2C_IMR_ENABLE_ALL		0x0007
+
+#define WMTI2C_REG_CDR		0x0A
+#define WMTI2C_REG_TR		0x0C
+#define WMTI2C_REG_MCR		0x0E
+
+struct wmt_i2c {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+};
+
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
new file mode 100644
index 000000000000..e0ffccf8a40a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+/* REG_TR */
+#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define WMTI2C_TR_STD			0x0064
+#define WMTI2C_TR_HS			0x0019
+
+/* REG_MCR */
+#define WMTI2C_MCR_APB_96M		7
+#define WMTI2C_MCR_APB_166M		12
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= wmt_i2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
+{
+	int err;
+	void __iomem *base = i2c->base;
+
+	err = clk_prepare_enable(i2c->clk);
+	if (err) {
+		dev_err(i2c->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c->clk, 20000000);
+	if (err) {
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
+		return err;
+	}
+
+	writew(0, base + WMTI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
+	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+	readw(base + WMTI2C_REG_CSR);		/* read clear */
+	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+
+	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
+	else
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c *i2c;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = wmt_i2c_init(pdev, &i2c);
+	if (err)
+		return err;
+
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+		i2c->tcr = WMTI2C_TCR_FAST_MODE;
+
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	return i2c_add_adapter(adap);
+}
+
+static void wmt_i2c_remove(struct platform_device *pdev)
+{
+	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
+
+	/* Disable interrupts, clock and delete adapter */
+	writew(0, i2c->base + WMTI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.remove_new	= wmt_i2c_remove,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index 76fba4ffa126..000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,431 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define WMTI2C_REG_CR		0x00
-#define WMTI2C_REG_TCR		0x02
-#define WMTI2C_REG_CSR		0x04
-#define WMTI2C_REG_ISR		0x06
-#define WMTI2C_REG_IMR		0x08
-#define WMTI2C_REG_CDR		0x0A
-#define WMTI2C_REG_TR		0x0C
-#define WMTI2C_REG_MCR		0x0E
-#define WMTI2C_REG_SLAVE_CR	0x10
-#define WMTI2C_REG_SLAVE_SR	0x12
-#define WMTI2C_REG_SLAVE_ISR	0x14
-#define WMTI2C_REG_SLAVE_IMR	0x16
-#define WMTI2C_REG_SLAVE_DR	0x18
-#define WMTI2C_REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define WMTI2C_CR_TX_NEXT_ACK		0x0000
-#define WMTI2C_CR_ENABLE		0x0001
-#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
-#define WMTI2C_CR_TX_END		0x0004
-#define WMTI2C_CR_CPU_RDY		0x0008
-#define WMTI2C_SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define WMTI2C_TCR_STANDARD_MODE	0x0000
-#define WMTI2C_TCR_MASTER_WRITE		0x0000
-#define WMTI2C_TCR_HS_MODE		0x2000
-#define WMTI2C_TCR_MASTER_READ		0x4000
-#define WMTI2C_TCR_FAST_MODE		0x8000
-#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define WMTI2C_ISR_NACK_ADDR		0x0001
-#define WMTI2C_ISR_BYTE_END		0x0002
-#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
-#define WMTI2C_ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define WMTI2C_IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
-#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
-#define WMTI2C_CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define WMTI2C_SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define WMTI2C_TR_STD			0x0064
-#define WMTI2C_TR_HS			0x0019
-
-/* REG_MCR */
-#define WMTI2C_MCR_APB_96M		7
-#define WMTI2C_MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
-{
-	unsigned long timeout;
-	void __iomem *base = i2c->base;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c->dev,
-					"timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c *i2c)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	int xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, base + WMTI2C_REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(base + WMTI2C_REG_CR);
-		val &= ~WMTI2C_CR_TX_END;
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CSR);
-		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
-				| WMTI2C_CR_ENABLE;
-			writew(val, base + WMTI2C_REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF,
-					base + WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
-					base + WMTI2C_REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	u32 xfer_len = 0;
-	void __iomem *base = i2c->base;
-
-	val = readw(base + WMTI2C_REG_CR);
-	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= WMTI2C_CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-
-	writew(val, base + WMTI2C_REG_CR);
-
-	reinit_completion(&i2c->complete);
-
-	tcr_val |= WMTI2C_TCR_MASTER_READ
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, base + WMTI2C_REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, base + WMTI2C_REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c, pmsg);
-		else
-			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c *i2c = data;
-
-	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
-
-	complete(&i2c->complete);
-
-	return IRQ_HANDLED;
-}
-
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
-{
-	int err;
-	struct wmt_i2c *i2c;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
-	if (!i2c)
-		return -ENOMEM;
-
-	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c->base))
-		return PTR_ERR(i2c->base);
-
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
-
-	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
-					0, pdev->name, i2c);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c->irq);
-
-	i2c->dev = &pdev->dev;
-	init_completion(&i2c->complete);
-	platform_set_drvdata(pdev, i2c);
-
-	*pi2c = i2c;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
-{
-	int err;
-	void __iomem *base = i2c->base;
-
-	err = clk_prepare_enable(i2c->clk);
-	if (err) {
-		dev_err(i2c->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c->clk, 20000000);
-	if (err) {
-		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c->clk);
-		return err;
-	}
-
-	writew(0, base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-	readw(base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-
-	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
-	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c *i2c;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c);
-	if (err)
-		return err;
-
-	i2c->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c->tcr = WMTI2C_TCR_FAST_MODE;
-
-	adap = &i2c->adapter;
-	i2c_set_adapdata(adap, i2c);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	return i2c_add_adapter(adap);
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c->base + WMTI2C_REG_IMR);
-	clk_disable_unprepare(i2c->clk);
-	i2c_del_adapter(&i2c->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.34.1


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

* [PATCH v6 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
                         ` (3 preceding siblings ...)
  2023-12-29  6:30       ` [PATCH v6 4/8] i2c: wmt: split out common files Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2024-01-03 18:45         ` Andi Shyti
  2023-12-29  6:30       ` [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
                         ` (4 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Since the I2C IP of both wmt and zhaoxin come from VIA.
So, rename common register, function and variable's name
to VIAI2C_ and viai2c_.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 118 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |  60 ++++++-------
 drivers/i2c/busses/i2c-wmt-plt.c       |  30 ++++---
 3 files changed, 105 insertions(+), 103 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 76058d6853a7..60a4d4ccaf12 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,15 +2,15 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
+static int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
 	unsigned long timeout;
 	void __iomem *base = i2c->base;
 
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
+	timeout = jiffies + VIAI2C_TIMEOUT;
+	while (!(readw(base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
 			dev_warn(i2c->dev,
 					"timeout waiting for bus ready\n");
@@ -22,7 +22,7 @@ static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
 	return 0;
 }
 
-static int wmt_check_status(struct wmt_i2c *i2c)
+static int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
 	unsigned long wait_result;
@@ -32,29 +32,29 @@ static int wmt_check_status(struct wmt_i2c *i2c)
 	if (!wait_result)
 		return -ETIMEDOUT;
 
-	if (i2c->cmd_status & WMTI2C_ISR_NACK_ADDR)
+	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c->cmd_status & WMTI2C_ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
+static irqreturn_t viai2c_isr(int irq, void *data)
 {
-	struct wmt_i2c *i2c = data;
+	struct viai2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + WMTI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + WMTI2C_REG_ISR);
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 			 int last)
 {
 	u16 val, tcr_val = i2c->tcr;
@@ -68,143 +68,143 @@ static int wmt_i2c_write(struct wmt_i2c *i2c, struct i2c_msg *pmsg,
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, base + WMTI2C_REG_CDR);
+		writew(0, base + VIAI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, base + WMTI2C_REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(base + WMTI2C_REG_CR);
-		val &= ~WMTI2C_CR_TX_END;
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	reinit_completion(&i2c->complete);
 
-	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
+	tcr_val |= (VIAI2C_TCR_MASTER_WRITE
+		| (pmsg->addr & VIAI2C_TCR_SLAVE_ADDR_MASK));
 
-	writew(tcr_val, base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
+		ret = viai2c_wait_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(base + WMTI2C_REG_CSR);
-		if (val & WMTI2C_CSR_RCV_NOT_ACK) {
+		val = readw(base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
 			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = WMTI2C_CR_TX_END | WMTI2C_CR_CPU_RDY
-				| WMTI2C_CR_ENABLE;
-			writew(val, base + WMTI2C_REG_CR);
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY
+				| VIAI2C_CR_ENABLE;
+			writew(val, base + VIAI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
+				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
-					base + WMTI2C_REG_CDR);
-			writew(WMTI2C_CR_CPU_RDY | WMTI2C_CR_ENABLE,
-					base + WMTI2C_REG_CR);
+					base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
+					base + VIAI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
 	void __iomem *base = i2c->base;
 
-	val = readw(base + WMTI2C_REG_CR);
-	val &= ~(WMTI2C_CR_TX_END | WMTI2C_CR_TX_NEXT_NO_ACK);
+	val = readw(base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= WMTI2C_CR_CPU_RDY;
+		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= WMTI2C_CR_TX_NEXT_NO_ACK;
+		val |= VIAI2C_CR_RX_END;
 
-	writew(val, base + WMTI2C_REG_CR);
+	writew(val, base + VIAI2C_REG_CR);
 
 	reinit_completion(&i2c->complete);
 
-	tcr_val |= WMTI2C_TCR_MASTER_READ
-		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK);
+	tcr_val |= VIAI2C_TCR_MASTER_READ
+		| (pmsg->addr & VIAI2C_TCR_SLAVE_ADDR_MASK);
 
-	writew(tcr_val, base + WMTI2C_REG_TCR);
+	writew(tcr_val, base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(base + WMTI2C_REG_CR);
-		val |= WMTI2C_CR_CPU_RDY;
-		writew(val, base + WMTI2C_REG_CR);
+		val = readw(base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c);
+		ret = viai2c_wait_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(base + WMTI2C_REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(base + VIAI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(base + WMTI2C_REG_CR) | WMTI2C_CR_CPU_RDY;
+		val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= WMTI2C_CR_TX_NEXT_NO_ACK;
-		writew(val, base + WMTI2C_REG_CR);
+			val |= VIAI2C_CR_RX_END;
+		writew(val, base + VIAI2C_REG_CR);
 	}
 
 	return 0;
 }
 
-int wmt_i2c_xfer(struct i2c_adapter *adap,
+int viai2c_xfer(struct i2c_adapter *adap,
 			struct i2c_msg msgs[],
 			int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c *i2c = i2c_get_adapdata(adap);
+	struct viai2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c);
+			ret = viai2c_wait_bus_ready(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c, pmsg, (i + 1) == num);
+			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 {
 	int err;
-	struct wmt_i2c *i2c;
+	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
 	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
@@ -219,7 +219,7 @@ int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c)
 	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr,
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
 					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index e57da0dc68a5..f171f81e4d0f 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -12,44 +12,44 @@
 #include <linux/platform_device.h>
 
 /* REG_CR Bit fields */
-#define WMTI2C_REG_CR		0x00
-#define WMTI2C_CR_TX_NEXT_ACK		0x0000
-#define WMTI2C_CR_ENABLE		0x0001
-#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
-#define WMTI2C_CR_TX_END		0x0004
-#define WMTI2C_CR_CPU_RDY		0x0008
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
 
 /* REG_TCR Bit fields */
-#define WMTI2C_REG_TCR		0x02
-#define WMTI2C_TCR_STANDARD_MODE	0x0000
-#define WMTI2C_TCR_MASTER_WRITE		0x0000
-#define WMTI2C_TCR_HS_MODE		0x2000
-#define WMTI2C_TCR_MASTER_READ		0x4000
-#define WMTI2C_TCR_FAST_MODE		0x8000
-#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_MASTER_WRITE		0x0000
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_MASTER_READ		BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+#define VIAI2C_TCR_SLAVE_ADDR_MASK	GENMASK(6, 0)
 
 /* REG_CSR Bit fields */
-#define WMTI2C_REG_CSR		0x04
-#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
-#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
-#define WMTI2C_CSR_READY_MASK		0x0002
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
 
 /* REG_ISR Bit fields */
-#define WMTI2C_REG_ISR		0x06
-#define WMTI2C_ISR_NACK_ADDR		0x0001
-#define WMTI2C_ISR_BYTE_END		0x0002
-#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
-#define WMTI2C_ISR_WRITE_ALL		0x0007
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
 
 /* REG_IMR Bit fields */
-#define WMTI2C_REG_IMR		0x08
-#define WMTI2C_IMR_ENABLE_ALL		0x0007
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
 
-#define WMTI2C_REG_CDR		0x0A
-#define WMTI2C_REG_TR		0x0C
-#define WMTI2C_REG_MCR		0x0E
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
 
-struct wmt_i2c {
+struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -60,7 +60,7 @@ struct wmt_i2c {
 	u16			cmd_status;
 };
 
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
index e0ffccf8a40a..8f506888cff7 100644
--- a/drivers/i2c/busses/i2c-wmt-plt.c
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -22,13 +22,15 @@
 #define WMTI2C_MCR_APB_96M		7
 #define WMTI2C_MCR_APB_166M		12
 
+#define wmt_i2c				viai2c
+
 static u32 wmt_i2c_func(struct i2c_adapter *adap)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
 }
 
 static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
+	.master_xfer	= viai2c_xfer,
 	.functionality	= wmt_i2c_func,
 };
 
@@ -50,18 +52,18 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c *i2c)
 		return err;
 	}
 
-	writew(0, base + WMTI2C_REG_CR);
-	writew(WMTI2C_MCR_APB_166M, base + WMTI2C_REG_MCR);
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
-	writew(WMTI2C_IMR_ENABLE_ALL, base + WMTI2C_REG_IMR);
-	writew(WMTI2C_CR_ENABLE, base + WMTI2C_REG_CR);
-	readw(base + WMTI2C_REG_CSR);		/* read clear */
-	writew(WMTI2C_ISR_WRITE_ALL, base + WMTI2C_REG_ISR);
+	writew(0, base + VIAI2C_REG_CR);
+	writew(WMTI2C_MCR_APB_166M, base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+	readw(base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, base + VIAI2C_REG_ISR);
 
-	if (i2c->tcr == WMTI2C_TCR_FAST_MODE)
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + WMTI2C_REG_TR);
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_HS, base + VIAI2C_REG_TR);
 	else
-		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + WMTI2C_REG_TR);
+		writew(WMTI2C_SCL_TIMEOUT(128) | WMTI2C_TR_STD, base + VIAI2C_REG_TR);
 
 	return 0;
 }
@@ -74,7 +76,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
@@ -86,7 +88,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c->tcr = WMTI2C_TCR_FAST_MODE;
+		i2c->tcr = VIAI2C_TCR_FAST;
 
 	adap = &i2c->adapter;
 	i2c_set_adapdata(adap, i2c);
@@ -110,7 +112,7 @@ static void wmt_i2c_remove(struct platform_device *pdev)
 	struct wmt_i2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c->base + WMTI2C_REG_IMR);
+	writew(0, i2c->base + VIAI2C_REG_IMR);
 	clk_disable_unprepare(i2c->clk);
 	i2c_del_adapter(&i2c->adapter);
 }
-- 
2.34.1


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

* [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
                         ` (4 preceding siblings ...)
  2023-12-29  6:30       ` [PATCH v6 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2024-01-03 19:39         ` Andi Shyti
  2023-12-29  6:30       ` [PATCH v6 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
                         ` (3 subsequent siblings)
  9 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

During each byte access, the host performs clock stretching.
In this case, the thread may be interrupted by preemption,
resulting in a long stretching time.

However, some touchpad can only tolerate host clock stretching
of no more than 200 ms. We reduce the impact of this through
a retransmission mechanism.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 37 +++++++++++++++++++++-----
 drivers/i2c/busses/i2c-viai2c-common.h |  2 ++
 2 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 60a4d4ccaf12..e5eca10efedc 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,7 +2,8 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
+#define VIAI2C_STRETCHING_TIMEOUT	200
 
 static int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
@@ -25,12 +26,35 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
 static int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
-	unsigned long wait_result;
+	unsigned long time_left;
+	unsigned long delta_ms;
+
+	time_left = wait_for_completion_timeout(&i2c->complete,
+						VIAI2C_TIMEOUT);
+	if (!time_left) {
+		dev_err(i2c->dev, "bus transfer timeout\n");
+		return -EIO;
+	}
 
-	wait_result = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
+	/*
+	 * During each byte access, the host performs clock stretching.
+	 * In this case, the thread may be interrupted by preemption,
+	 * resulting in a long stretching time.
+	 * However, some touchpad can only tolerate host clock stretching
+	 * of no more than 200 ms. We reduce the impact of this through
+	 * a retransmission mechanism.
+	 */
+	local_irq_disable();
+	i2c->to = ktime_get();
+	delta_ms = ktime_to_ms(ktime_sub(i2c->to, i2c->ti));
+	if (delta_ms > VIAI2C_STRETCHING_TIMEOUT) {
+		local_irq_enable();
+		dev_warn(i2c->dev, "thread blocked more than %ldms\n",
+				delta_ms);
+		return -EAGAIN;
+	}
+	i2c->ti = i2c->to;
+	local_irq_enable();
 
 	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
@@ -184,6 +208,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	int ret = 0;
 	struct viai2c *i2c = i2c_get_adapdata(adap);
 
+	i2c->to = i2c->ti = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index f171f81e4d0f..73a88398d763 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -58,6 +58,8 @@ struct viai2c {
 	u16			tcr;
 	int			irq;
 	u16			cmd_status;
+	ktime_t			ti;
+	ktime_t			to;
 };
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-- 
2.34.1


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

* [PATCH v6 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
                         ` (5 preceding siblings ...)
  2023-12-29  6:30       ` [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2023-12-29  6:30       ` [PATCH v6 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
                         ` (2 subsequent siblings)
  9 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Enumeration variables are added to differentiate between different platforms.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 34 ++++++++++++++++----------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 +++++-
 drivers/i2c/busses/i2c-wmt-plt.c       |  2 +-
 3 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index e5eca10efedc..930f4c5c1797 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -78,8 +78,7 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
-			 int last)
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
@@ -97,7 +96,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 		writew(pmsg->buf[0] & 0xFF, base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -111,7 +110,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -138,7 +137,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg,
 		}
 
 		if (xfer_len == pmsg->len) {
-			if (last != 1)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
@@ -161,7 +160,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -176,7 +175,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -211,7 +210,8 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	i2c->to = i2c->ti = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if ((i2c->platform == VIAI2C_PLAT_WMT)
+		   && !(pmsg->flags & I2C_M_NOSTART)) {
 			ret = viai2c_wait_bus_ready(i2c);
 			if (ret < 0)
 				return ret;
@@ -226,9 +226,10 @@ int viai2c_xfer(struct i2c_adapter *adap,
 	return (ret < 0) ? ret : i;
 }
 
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 {
 	int err;
+	int irq_flags;
 	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
@@ -240,12 +241,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 	if (IS_ERR(i2c->base))
 		return PTR_ERR(i2c->base);
 
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
+	if (plat == VIAI2C_PLAT_WMT) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				"wrong platform type\n");
+
+	i2c->platform = plat;
 
 	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
-					0, pdev->name, i2c);
+					irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
 				"failed to request irq %i\n", i2c->irq);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 73a88398d763..6d210e562c9a 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -49,6 +49,10 @@
 #define VIAI2C_REG_TR		0x0C
 #define VIAI2C_REG_MCR		0x0E
 
+enum {
+	VIAI2C_PLAT_WMT = 1,
+};
+
 struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
@@ -60,9 +64,10 @@ struct viai2c {
 	u16			cmd_status;
 	ktime_t			ti;
 	ktime_t			to;
+	int			platform;
 };
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
index 8f506888cff7..6afb830eeb40 100644
--- a/drivers/i2c/busses/i2c-wmt-plt.c
+++ b/drivers/i2c/busses/i2c-wmt-plt.c
@@ -76,7 +76,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = viai2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
 	if (err)
 		return err;
 
-- 
2.34.1


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

* [PATCH v6 8/8] i2c: add zhaoxin i2c controller driver
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
                         ` (6 preceding siblings ...)
  2023-12-29  6:30       ` [PATCH v6 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2023-12-29  6:30       ` Hans Hu
  2024-01-03 20:02         ` Andi Shyti
  2024-01-03 20:03       ` [PATCH v6 0/8] " Andi Shyti
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
  9 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2023-12-29  6:30 UTC (permalink / raw)
  To: wsa, linux-i2c; +Cc: andi.shyti, cobechen, hanshu-oc

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the "IIC1D17" HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                            |   8 +
 drivers/i2c/busses/Kconfig             |  10 +
 drivers/i2c/busses/Makefile            |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c |  21 +-
 drivers/i2c/busses/i2c-viai2c-common.h |   6 +
 drivers/i2c/busses/i2c-zhaoxin-plt.c   | 298 +++++++++++++++++++++++++
 6 files changed, 340 insertions(+), 5 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-zhaoxin-plt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c3005c2c9dd2..aa1a7f314b41 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10023,6 +10023,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 28eb48dd5b32..6ccc9f858c90 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -336,6 +336,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 2ac59c585c08..1d2d7e9e576e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-zhaoxin-plt.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 930f4c5c1797..5e31c5efd10e 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -5,7 +5,7 @@
 #define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
 #define VIAI2C_STRETCHING_TIMEOUT	200
 
-static int viai2c_wait_bus_ready(struct viai2c *i2c)
+int viai2c_wait_bus_ready(struct viai2c *i2c)
 {
 	unsigned long timeout;
 	void __iomem *base = i2c->base;
@@ -23,7 +23,7 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
 	return 0;
 }
 
-static int viai2c_wait_status(struct viai2c *i2c)
+int viai2c_wait_status(struct viai2c *i2c)
 {
 	int ret = 0;
 	unsigned long time_left;
@@ -71,6 +71,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!i2c->cmd_status)
+		return IRQ_NONE;
+
 	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
@@ -139,6 +142,8 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 		if (xfer_len == pmsg->len) {
 			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && last)
+				writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF,
 					base + VIAI2C_REG_CDR);
@@ -150,7 +155,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, bool last)
 	return 0;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
@@ -175,7 +180,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, base + VIAI2C_REG_TCR);
 
-	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART))
+	   || (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, base + VIAI2C_REG_CR);
@@ -218,7 +224,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
@@ -246,6 +252,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 		i2c->irq = irq_of_parse_and_map(np, 0);
 		if (!i2c->irq)
 			return -EINVAL;
+	} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	} else
 		return dev_err_probe(&pdev->dev, -EINVAL,
 				"wrong platform type\n");
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 6d210e562c9a..bcff7026e2b8 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -51,6 +51,7 @@
 
 enum {
 	VIAI2C_PLAT_WMT = 1,
+	VIAI2C_PLAT_ZHAOXIN
 };
 
 struct viai2c {
@@ -65,8 +66,13 @@ struct viai2c {
 	ktime_t			ti;
 	ktime_t			to;
 	int			platform;
+	u8			hrv;
+	u16			tr;
+	u16			mcr;
 };
 
+int viai2c_wait_status(struct viai2c *i2c);
+int viai2c_wait_bus_ready(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
diff --git a/drivers/i2c/busses/i2c-zhaoxin-plt.c b/drivers/i2c/busses/i2c-zhaoxin-plt.c
new file mode 100644
index 000000000000..110a575df201
--- /dev/null
+++ b/drivers/i2c/busses/i2c-zhaoxin-plt.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2021 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include "i2c-viai2c-common.h"
+
+#define ZX_I2C_NAME             "i2c_zhaoxin"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+#define ZXI2C_FIFO_SIZE		32
+
+/* Structure definition */
+#define zxi2c viai2c
+
+static int zxi2c_fifo_xfer(struct zxi2c *i2c, struct i2c_msg *msg)
+{
+	u16 xfered_len = 0;
+	u16 byte_left = msg->len;
+	u16 tcr_val = i2c->tcr;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+
+	i2c->ti = ktime_get();
+	while (byte_left) {
+		u16 i;
+		u8 tmp;
+		int error;
+		u16 xfer_len = min_t(u16, byte_left, ZXI2C_FIFO_SIZE);
+
+		byte_left -= xfer_len;
+
+		/* reset fifo buffer */
+		tmp = ioread8(base + ZXI2C_REG_HCR);
+		iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+		/* set xfer len */
+		if (read) {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HRLR);
+		} else {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HTLR);
+			/* set write data */
+			for (i = 0; i < xfer_len; i++)
+				iowrite8(msg->buf[xfered_len + i],
+						base + ZXI2C_REG_HTDR);
+		}
+
+		/* prepare to stop transmission */
+		if (i2c->hrv && !byte_left) {
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+			iowrite8(tmp, base + VIAI2C_REG_CR);
+		}
+
+		reinit_completion(&i2c->complete);
+
+		if (xfered_len) {
+			/* continue transmission */
+			tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+			iowrite8(tmp |= VIAI2C_CR_CPU_RDY,
+					i2c->base + VIAI2C_REG_CR);
+		} else {
+			/* start transmission */
+			tcr_val |= (read ? VIAI2C_TCR_MASTER_READ : 0);
+			writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+		}
+
+		error = viai2c_wait_status(i2c);
+		if (error)
+			return error;
+
+		/* get the received data */
+		if (read)
+			for (i = 0; i < xfer_len; i++)
+				msg->buf[xfered_len + i] =
+					ioread8(base + ZXI2C_REG_HRDR);
+
+		xfered_len += xfer_len;
+	}
+
+	return 1;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct zxi2c *i2c = (struct zxi2c *)i2c_get_adapdata(adap);
+
+	ret = viai2c_wait_bus_ready(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(i2c->base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 &&
+	   (i2c->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND,
+				i2c->base + VIAI2C_REG_IMR);
+
+		i2c->ti = i2c->to = ktime_get();
+		ret = zxi2c_fifo_xfer(i2c, msgs);
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, i2c->base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, i2c->base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE,
+				i2c->base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret < 0)
+			iowrite16(tmp | VIAI2C_CR_END_MASK,
+					i2c->base + VIAI2C_REG_CR);
+		/* make sure the state machine is stopped */
+		usleep_range(1, 2);
+	}
+	/* dis interrupt */
+	iowrite8(0, i2c->base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct zxi2c *i2c)
+{
+	iowrite16(i2c->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(i2c->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct zxi2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
+				params[0], fstp, params[2]);
+		i2c->tr = params[2] | 0xff00;
+	} else {
+		i2c->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	i2c->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0000 1000 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		i2c->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n",
+			i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct zxi2c *i2c;
+	struct pci_dev *pci;
+	struct i2c_adapter *adap;
+
+	error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
+	if (error)
+		return error;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	i2c->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->retries = 2;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	pci = to_pci_dev(pdev->dev.parent);
+	snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
+		dev_name(&pci->dev), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int __maybe_unused zxi2c_resume(struct device *dev)
+{
+	struct zxi2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = ZX_I2C_NAME,
+		.acpi_match_table = zxi2c_acpi_match,
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* Re: [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init
  2023-12-29  6:30       ` [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2024-01-03 12:56         ` Andi Shyti
  2024-01-04  1:44           ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 12:56 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

On Fri, Dec 29, 2023 at 02:30:32PM +0800, Hans Hu wrote:
> v4->v5:
> 	add previous prototype 'static' for wmt_i2c_init().
> 
> Some common initialization actions are put in the function
> wmt_i2c_init(), which is convenient to share with zhaoxin.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> ---
>  drivers/i2c/busses/i2c-wmt.c | 67 +++++++++++++++++++-----------------
>  1 file changed, 36 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
> index ec2a8da134e5..f1888f100d83 100644
> --- a/drivers/i2c/busses/i2c-wmt.c
> +++ b/drivers/i2c/busses/i2c-wmt.c
> @@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> +static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)

looks good, I would rather make this a 

   static struct wmt_i2c_dev *wmt_i2c_init(struct platform_device *pdev)
   {
	struct wmt_i2c_dev *i2c_dev;
   	...
	return i2c_dev;
   }

kind of function and call it as:

   i2c_dev = wmt_i2c_init(...);
   if (IS_ERR(i2c_dev))
   	return ERR_PTR(i2c_dev);

Not a binding comment. It just looks nicer; in that case I would
call the function wmt_i2c_dev_alloc().

In any case:

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>

Andi

> +{
> +	int err;
> +	struct wmt_i2c_dev *i2c_dev;
> +	struct device_node *np = pdev->dev.of_node;
> +
> +	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
> +	if (!i2c_dev)
> +		return -ENOMEM;
> +
> +	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
> +	if (IS_ERR(i2c_dev->base))
> +		return PTR_ERR(i2c_dev->base);
> +
> +	i2c_dev->irq = irq_of_parse_and_map(np, 0);
> +	if (!i2c_dev->irq)
> +		return -EINVAL;
> +
> +	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
> +					0, pdev->name, i2c_dev);
> +	if (err)
> +		return dev_err_probe(&pdev->dev, err,
> +				"failed to request irq %i\n", i2c_dev->irq);
> +
> +	i2c_dev->dev = &pdev->dev;
> +	init_completion(&i2c_dev->complete);
> +	platform_set_drvdata(pdev, i2c_dev);
> +
> +	*pi2c_dev = i2c_dev;
> +	return 0;
> +}
> +
>  static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
>  {
>  	int err;
> @@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
>  	int err;
>  	u32 clk_rate;
>  
> -	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
> -	if (!i2c_dev)
> -		return -ENOMEM;
> -
> -	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
> -	if (IS_ERR(i2c_dev->base))
> -		return PTR_ERR(i2c_dev->base);
> -
> -	i2c_dev->irq = irq_of_parse_and_map(np, 0);
> -	if (!i2c_dev->irq) {
> -		dev_err(&pdev->dev, "irq missing or invalid\n");
> -		return -EINVAL;
> -	}
> +	err = wmt_i2c_init(pdev, &i2c_dev);
> +	if (err)
> +		return err;
>  
>  	i2c_dev->clk = of_clk_get(np, 0);
>  	if (IS_ERR(i2c_dev->clk)) {
> @@ -351,15 +373,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
>  	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
>  		i2c_dev->tcr = TCR_FAST_MODE;
>  
> -	i2c_dev->dev = &pdev->dev;
> -
> -	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
> -							"i2c", i2c_dev);
> -	if (err) {
> -		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
> -		return err;
> -	}
> -
>  	adap = &i2c_dev->adapter;
>  	i2c_set_adapdata(adap, i2c_dev);
>  	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
> @@ -368,21 +381,13 @@ static int wmt_i2c_probe(struct platform_device *pdev)
>  	adap->dev.parent = &pdev->dev;
>  	adap->dev.of_node = pdev->dev.of_node;
>  
> -	init_completion(&i2c_dev->complete);
> -
>  	err = wmt_i2c_reset_hardware(i2c_dev);
>  	if (err) {
>  		dev_err(&pdev->dev, "error initializing hardware\n");
>  		return err;
>  	}
>  
> -	err = i2c_add_adapter(adap);
> -	if (err)
> -		return err;
> -
> -	platform_set_drvdata(pdev, i2c_dev);
> -
> -	return 0;
> +	return i2c_add_adapter(adap);
>  }
>  
>  static void wmt_i2c_remove(struct platform_device *pdev)
> -- 
> 2.34.1
> 

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

* Re: [PATCH v6 2/8] i2c: wmt: rename marcos with prefix WMTI2C_
  2023-12-29  6:30       ` [PATCH v6 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
@ 2024-01-03 13:29         ` Andi Shyti
  0 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 13:29 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

On Fri, Dec 29, 2023 at 02:30:33PM +0800, Hans Hu wrote:
> Tweaked a few formatting things: rename marcos with prefix WMTI2C_

You say "a few" but then list only one.

> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

looks correct, though:

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>

Andi

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

* Re: [PATCH v6 3/8] i2c: wmt: adjust line length to meet style
  2023-12-29  6:30       ` [PATCH v6 3/8] i2c: wmt: adjust line length to meet style Hans Hu
@ 2024-01-03 16:52         ` Andi Shyti
  2024-01-04  1:49           ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 16:52 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

in case you are going to resend this series, you could think
about these improvements.

On Fri, Dec 29, 2023 at 02:30:34PM +0800, Hans Hu wrote:
> v4->v5:
> 	add previous prototype 'static' for wmt_i2c_init().

please, put the changelog at the end of the commit log.

Where is the changelog from v1?

> Tweaked a few formatting things:
> rename wmt_i2c_dev to wmt_i2c, i2c_dev to i2c, etc. 

Please just list the renames, you are not doing formatting
improvements here.

> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

...

> -static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
> +static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
>  {
>  	unsigned long timeout;
> +	void __iomem *base = i2c->base;

this change and similar below, are not listed in the commit log.

>  
>  	timeout = jiffies + WMT_I2C_TIMEOUT;
> -	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
> +	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
>  		if (time_after(jiffies, timeout)) {
> -			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
> +			dev_warn(i2c->dev,
> +					"timeout waiting for bus ready\n");

with /i2c_dev/i2c/ you don't need to break the line anymore (BTW,
now 100 character lines are allowed, however not encouraged).

>  			return -EBUSY;
>  		}
>  		msleep(20);

...

> -	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
> +	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
> +		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));

this change is not listed in the commit log and please, remember,
the new 100 characters rule which makes these changes
unnecessary).

Andi

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

* Re: [PATCH v6 4/8] i2c: wmt: split out common files
  2023-12-29  6:30       ` [PATCH v6 4/8] i2c: wmt: split out common files Hans Hu
@ 2024-01-03 17:21         ` Andi Shyti
  2024-01-04  2:04           ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 17:21 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

On Fri, Dec 29, 2023 at 02:30:35PM +0800, Hans Hu wrote:
> Since the I2C IP of both wmt and zhaoxin come from VIA,

/come/comes/

> the common driver is named as i2c-viai2c-common.c.
> Old i2c-wmt.c renamed to i2c-wmt-plt.c.
> 
> The MAINTAINERS information will added in patch 0008.

when the patch is applied there is no knowledge anymore of the
patch sequence, please put these comments after the '---' section
or make it generic: "The MAINTAINERS file will be updated
accordingly in upcoming commits"

> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> ---
>  MAINTAINERS                            |   2 +-
>  drivers/i2c/busses/Makefile            |   2 +
>  drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
>  drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
>  drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++

'plt' stands for?

Everything else looks correct.

Andi

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

* Re: [PATCH v6 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  2023-12-29  6:30       ` [PATCH v6 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
@ 2024-01-03 18:45         ` Andi Shyti
  2024-01-04  2:12           ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 18:45 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

On Fri, Dec 29, 2023 at 02:30:36PM +0800, Hans Hu wrote:
> Since the I2C IP of both wmt and zhaoxin come from VIA.
> So, rename common register, function and variable's name
> to VIAI2C_ and viai2c_.

this commit is not really clear. Can we write something like:

"The I2C IP for both wmt and zhaoxin originates from VIA. Rename
common registers, functions, and variable names to follow the
VIAI2C_ and viai2c_ naming conventions for consistency and
clarity."

> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

[...]

> -#define WMTI2C_REG_CR		0x00
> -#define WMTI2C_CR_TX_NEXT_ACK		0x0000
> -#define WMTI2C_CR_ENABLE		0x0001
> -#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
> -#define WMTI2C_CR_TX_END		0x0004
> -#define WMTI2C_CR_CPU_RDY		0x0008
> +#define VIAI2C_REG_CR		0x00
> +#define VIAI2C_CR_ENABLE		BIT(0)
> +#define VIAI2C_CR_RX_END		BIT(1)
> +#define VIAI2C_CR_TX_END		BIT(2)
> +#define VIAI2C_CR_CPU_RDY		BIT(3)
> +#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
>  
>  /* REG_TCR Bit fields */
> -#define WMTI2C_REG_TCR		0x02
> -#define WMTI2C_TCR_STANDARD_MODE	0x0000
> -#define WMTI2C_TCR_MASTER_WRITE		0x0000
> -#define WMTI2C_TCR_HS_MODE		0x2000
> -#define WMTI2C_TCR_MASTER_READ		0x4000
> -#define WMTI2C_TCR_FAST_MODE		0x8000
> -#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
> +#define VIAI2C_REG_TCR		0x02
> +#define VIAI2C_TCR_MASTER_WRITE		0x0000
> +#define VIAI2C_TCR_HS_MODE		BIT(13)
> +#define VIAI2C_TCR_MASTER_READ		BIT(14)
> +#define VIAI2C_TCR_FAST			BIT(15)
> +#define VIAI2C_TCR_SLAVE_ADDR_MASK	GENMASK(6, 0)
>  
>  /* REG_CSR Bit fields */
> -#define WMTI2C_REG_CSR		0x04
> -#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
> -#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
> -#define WMTI2C_CSR_READY_MASK		0x0002
> +#define VIAI2C_REG_CSR		0x04
> +#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
> +#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
> +#define VIAI2C_CSR_READY_MASK		BIT(1)
>  
>  /* REG_ISR Bit fields */
> -#define WMTI2C_REG_ISR		0x06
> -#define WMTI2C_ISR_NACK_ADDR		0x0001
> -#define WMTI2C_ISR_BYTE_END		0x0002
> -#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
> -#define WMTI2C_ISR_WRITE_ALL		0x0007
> +#define VIAI2C_REG_ISR		0x06
> +#define VIAI2C_ISR_NACK_ADDR		BIT(0)
> +#define VIAI2C_ISR_BYTE_END		BIT(1)
> +#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
> +#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
>  
>  /* REG_IMR Bit fields */
> -#define WMTI2C_REG_IMR		0x08
> -#define WMTI2C_IMR_ENABLE_ALL		0x0007
> +#define VIAI2C_REG_IMR		0x08
> +#define VIAI2C_IMR_BYTE			BIT(1)
> +#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
>  
> -#define WMTI2C_REG_CDR		0x0A
> -#define WMTI2C_REG_TR		0x0C
> -#define WMTI2C_REG_MCR		0x0E
> +#define VIAI2C_REG_CDR		0x0A
> +#define VIAI2C_REG_TR		0x0C
> +#define VIAI2C_REG_MCR		0x0E

These defines have been changed twice in this series. The patches
should be rearranged in order to avoid this.

I Wolfram is not against, I'm OK with letting it slip this time.

> -struct wmt_i2c {
> +struct viai2c {
>  	struct i2c_adapter	adapter;
>  	struct completion	complete;
>  	struct device		*dev;
> @@ -60,7 +60,7 @@ struct wmt_i2c {
>  	u16			cmd_status;
>  };
>  
> -int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
> -int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
> +int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
> +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
>  
>  #endif
> diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
> index e0ffccf8a40a..8f506888cff7 100644
> --- a/drivers/i2c/busses/i2c-wmt-plt.c
> +++ b/drivers/i2c/busses/i2c-wmt-plt.c
> @@ -22,13 +22,15 @@
>  #define WMTI2C_MCR_APB_96M		7
>  #define WMTI2C_MCR_APB_166M		12
>  
> +#define wmt_i2c				viai2c

no, please, do not redefine types. Besides This looks a bit
dangerous and reckless to me :-)

Andi

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

* Re: [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked
  2023-12-29  6:30       ` [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2024-01-03 19:39         ` Andi Shyti
  2024-01-04  2:30           ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 19:39 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

[...]

>  static int viai2c_wait_bus_ready(struct viai2c *i2c)
>  {
> @@ -25,12 +26,35 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
>  static int viai2c_wait_status(struct viai2c *i2c)
>  {
>  	int ret = 0;
> -	unsigned long wait_result;
> +	unsigned long time_left;
> +	unsigned long delta_ms;
> +
> +	time_left = wait_for_completion_timeout(&i2c->complete,
> +						VIAI2C_TIMEOUT);
> +	if (!time_left) {
> +		dev_err(i2c->dev, "bus transfer timeout\n");
> +		return -EIO;
> +	}
>  
> -	wait_result = wait_for_completion_timeout(&i2c->complete,
> -						msecs_to_jiffies(500));
> -	if (!wait_result)
> -		return -ETIMEDOUT;

this change is unrelated. Why are you changing the timeout here
from 500 to 1000?

> +	/*
> +	 * During each byte access, the host performs clock stretching.
> +	 * In this case, the thread may be interrupted by preemption,
> +	 * resulting in a long stretching time.
> +	 * However, some touchpad can only tolerate host clock stretching
> +	 * of no more than 200 ms. We reduce the impact of this through
> +	 * a retransmission mechanism.
> +	 */

is the hardware sending the stretching on its own?

> +	local_irq_disable();
> +	i2c->to = ktime_get();
> +	delta_ms = ktime_to_ms(ktime_sub(i2c->to, i2c->ti));
> +	if (delta_ms > VIAI2C_STRETCHING_TIMEOUT) {
> +		local_irq_enable();
> +		dev_warn(i2c->dev, "thread blocked more than %ldms\n",
> +				delta_ms);
> +		return -EAGAIN;
> +	}
> +	i2c->ti = i2c->to;
> +	local_irq_enable();
>  
>  	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
>  		ret = -EIO;
> @@ -184,6 +208,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
>  	int ret = 0;
>  	struct viai2c *i2c = i2c_get_adapdata(adap);
>  
> +	i2c->to = i2c->ti = ktime_get();
>  	for (i = 0; ret >= 0 && i < num; i++) {
>  		pmsg = &msgs[i];
>  		if (!(pmsg->flags & I2C_M_NOSTART)) {
> diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
> index f171f81e4d0f..73a88398d763 100644
> --- a/drivers/i2c/busses/i2c-viai2c-common.h
> +++ b/drivers/i2c/busses/i2c-viai2c-common.h
> @@ -58,6 +58,8 @@ struct viai2c {
>  	u16			tcr;
>  	int			irq;
>  	u16			cmd_status;
> +	ktime_t			ti;
> +	ktime_t			to;

don't these need some arbitration?

Andi

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

* Re: [PATCH v6 8/8] i2c: add zhaoxin i2c controller driver
  2023-12-29  6:30       ` [PATCH v6 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2024-01-03 20:02         ` Andi Shyti
  2024-01-04  2:40           ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 20:02 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

[...]

> --- a/drivers/i2c/busses/i2c-viai2c-common.c
> +++ b/drivers/i2c/busses/i2c-viai2c-common.c
> @@ -5,7 +5,7 @@
>  #define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
>  #define VIAI2C_STRETCHING_TIMEOUT	200
>  
> -static int viai2c_wait_bus_ready(struct viai2c *i2c)
> +int viai2c_wait_bus_ready(struct viai2c *i2c)

no, please, choose the rigth prototype at the beginning, don't
double change things in the same series.

>  {
>  	unsigned long timeout;
>  	void __iomem *base = i2c->base;
> @@ -23,7 +23,7 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
>  	return 0;
>  }
>  
> -static int viai2c_wait_status(struct viai2c *i2c)
> +int viai2c_wait_status(struct viai2c *i2c)
>  {
>  	int ret = 0;
>  	unsigned long time_left;
> @@ -71,6 +71,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
>  
>  	/* save the status and write-clear it */
>  	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
> +	if (!i2c->cmd_status)
> +		return IRQ_NONE;
> +

is this change related to this patch? can you put this at the
beginning?

Andi

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

* Re: [PATCH v6 0/8] i2c: add zhaoxin i2c controller driver
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
                         ` (7 preceding siblings ...)
  2023-12-29  6:30       ` [PATCH v6 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2024-01-03 20:03       ` Andi Shyti
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
  9 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-01-03 20:03 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

On Fri, Dec 29, 2023 at 02:30:31PM +0800, Hans Hu wrote:
> v5->v6:
> 	fix build warnning reported by kernel test robot
> v4->v5:
> 	fix some build errors.

Where is the full log?

Andi

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

* Re: [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init
  2024-01-03 12:56         ` Andi Shyti
@ 2024-01-04  1:44           ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-01-04  1:44 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen


On 2024/1/3 20:56, Andi Shyti wrote:
> Hi Hans,
>
> On Fri, Dec 29, 2023 at 02:30:32PM +0800, Hans Hu wrote:
>> v4->v5:
>> 	add previous prototype 'static' for wmt_i2c_init().
>>
>> Some common initialization actions are put in the function
>> wmt_i2c_init(), which is convenient to share with zhaoxin.
>>
>> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
>> ---
>>   drivers/i2c/busses/i2c-wmt.c | 67 +++++++++++++++++++-----------------
>>   1 file changed, 36 insertions(+), 31 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
>> index ec2a8da134e5..f1888f100d83 100644
>> --- a/drivers/i2c/busses/i2c-wmt.c
>> +++ b/drivers/i2c/busses/i2c-wmt.c
>> @@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
>>   	return IRQ_HANDLED;
>>   }
>>   
>> +static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
> looks good, I would rather make this a
>
>     static struct wmt_i2c_dev *wmt_i2c_init(struct platform_device *pdev)
>     {
> 	struct wmt_i2c_dev *i2c_dev;
>     	...
> 	return i2c_dev;
>     }
>
> kind of function and call it as:
>
>     i2c_dev = wmt_i2c_init(...);
>     if (IS_ERR(i2c_dev))
>     	return ERR_PTR(i2c_dev);
>
> Not a binding comment. It just looks nicer; in that case I would
> call the function wmt_i2c_dev_alloc().


OK, will change it.


> In any case:
>
> Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
>
> Andi
>

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

* Re: [PATCH v6 3/8] i2c: wmt: adjust line length to meet style
  2024-01-03 16:52         ` Andi Shyti
@ 2024-01-04  1:49           ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-01-04  1:49 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen


On 2024/1/4 00:52, Andi Shyti wrote:
> Hi Hans,
>
> in case you are going to resend this series, you could think
> about these improvements.


Ok, will think about all of these


Hans


> On Fri, Dec 29, 2023 at 02:30:34PM +0800, Hans Hu wrote:
>> v4->v5:
>> 	add previous prototype 'static' for wmt_i2c_init().
> please, put the changelog at the end of the commit log.
>
> Where is the changelog from v1?
>
>> Tweaked a few formatting things:
>> rename wmt_i2c_dev to wmt_i2c, i2c_dev to i2c, etc.
> Please just list the renames, you are not doing formatting
> improvements here.
>
>> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> ...
>
>> -static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
>> +static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c *i2c)
>>   {
>>   	unsigned long timeout;
>> +	void __iomem *base = i2c->base;
> this change and similar below, are not listed in the commit log.
>
>>   
>>   	timeout = jiffies + WMT_I2C_TIMEOUT;
>> -	while (!(readw(i2c_dev->base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
>> +	while (!(readw(base + WMTI2C_REG_CSR) & WMTI2C_CSR_READY_MASK)) {
>>   		if (time_after(jiffies, timeout)) {
>> -			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
>> +			dev_warn(i2c->dev,
>> +					"timeout waiting for bus ready\n");
> with /i2c_dev/i2c/ you don't need to break the line anymore (BTW,
> now 100 character lines are allowed, however not encouraged).
>
>>   			return -EBUSY;
>>   		}
>>   		msleep(20);
> ...
>
>> -	tcr_val |= (WMTI2C_TCR_MASTER_WRITE | (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
>> +	tcr_val |= (WMTI2C_TCR_MASTER_WRITE
>> +		| (pmsg->addr & WMTI2C_TCR_SLAVE_ADDR_MASK));
> this change is not listed in the commit log and please, remember,
> the new 100 characters rule which makes these changes
> unnecessary).
>
> Andi

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

* Re: [PATCH v6 4/8] i2c: wmt: split out common files
  2024-01-03 17:21         ` Andi Shyti
@ 2024-01-04  2:04           ` Hans Hu
  2024-01-04  9:22             ` Andi Shyti
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-04  2:04 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen


On 2024/1/4 01:21, Andi Shyti wrote:
> Hi Hans,
>
> On Fri, Dec 29, 2023 at 02:30:35PM +0800, Hans Hu wrote:
>> Since the I2C IP of both wmt and zhaoxin come from VIA,
> /come/comes/
>
>> the common driver is named as i2c-viai2c-common.c.
>> Old i2c-wmt.c renamed to i2c-wmt-plt.c.
>>
>> The MAINTAINERS information will added in patch 0008.
> when the patch is applied there is no knowledge anymore of the
> patch sequence, please put these comments after the '---' section
> or make it generic: "The MAINTAINERS file will be updated
> accordingly in upcoming commits"


ok, will change this.


>> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
>> ---
>>   MAINTAINERS                            |   2 +-
>>   drivers/i2c/busses/Makefile            |   2 +
>>   drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
>>   drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
>>   drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++
> 'plt' stands for?


'plt' is short for 'platform', since it is not suitable,

do you think it is better to change it to 'i2c-wmt-platform.c' or 
'i2c-viai2c-wmt.c' ?


Hans

>
> Everything else looks correct.
>
> Andi

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

* Re: [PATCH v6 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_
  2024-01-03 18:45         ` Andi Shyti
@ 2024-01-04  2:12           ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-01-04  2:12 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen


On 2024/1/4 02:45, Andi Shyti wrote:
> Hi Hans,
>
> On Fri, Dec 29, 2023 at 02:30:36PM +0800, Hans Hu wrote:
>> Since the I2C IP of both wmt and zhaoxin come from VIA.
>> So, rename common register, function and variable's name
>> to VIAI2C_ and viai2c_.
> this commit is not really clear. Can we write something like:
>
> "The I2C IP for both wmt and zhaoxin originates from VIA. Rename
> common registers, functions, and variable names to follow the
> VIAI2C_ and viai2c_ naming conventions for consistency and
> clarity."


ok, will change this.


>> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> [...]
>
>> -#define WMTI2C_REG_CR		0x00
>> -#define WMTI2C_CR_TX_NEXT_ACK		0x0000
>> -#define WMTI2C_CR_ENABLE		0x0001
>> -#define WMTI2C_CR_TX_NEXT_NO_ACK	0x0002
>> -#define WMTI2C_CR_TX_END		0x0004
>> -#define WMTI2C_CR_CPU_RDY		0x0008
>> +#define VIAI2C_REG_CR		0x00
>> +#define VIAI2C_CR_ENABLE		BIT(0)
>> +#define VIAI2C_CR_RX_END		BIT(1)
>> +#define VIAI2C_CR_TX_END		BIT(2)
>> +#define VIAI2C_CR_CPU_RDY		BIT(3)
>> +#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
>>   
>>   /* REG_TCR Bit fields */
>> -#define WMTI2C_REG_TCR		0x02
>> -#define WMTI2C_TCR_STANDARD_MODE	0x0000
>> -#define WMTI2C_TCR_MASTER_WRITE		0x0000
>> -#define WMTI2C_TCR_HS_MODE		0x2000
>> -#define WMTI2C_TCR_MASTER_READ		0x4000
>> -#define WMTI2C_TCR_FAST_MODE		0x8000
>> -#define WMTI2C_TCR_SLAVE_ADDR_MASK	0x007F
>> +#define VIAI2C_REG_TCR		0x02
>> +#define VIAI2C_TCR_MASTER_WRITE		0x0000
>> +#define VIAI2C_TCR_HS_MODE		BIT(13)
>> +#define VIAI2C_TCR_MASTER_READ		BIT(14)
>> +#define VIAI2C_TCR_FAST			BIT(15)
>> +#define VIAI2C_TCR_SLAVE_ADDR_MASK	GENMASK(6, 0)
>>   
>>   /* REG_CSR Bit fields */
>> -#define WMTI2C_REG_CSR		0x04
>> -#define WMTI2C_CSR_RCV_NOT_ACK		0x0001
>> -#define WMTI2C_CSR_RCV_ACK_MASK		0x0001
>> -#define WMTI2C_CSR_READY_MASK		0x0002
>> +#define VIAI2C_REG_CSR		0x04
>> +#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
>> +#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
>> +#define VIAI2C_CSR_READY_MASK		BIT(1)
>>   
>>   /* REG_ISR Bit fields */
>> -#define WMTI2C_REG_ISR		0x06
>> -#define WMTI2C_ISR_NACK_ADDR		0x0001
>> -#define WMTI2C_ISR_BYTE_END		0x0002
>> -#define WMTI2C_ISR_SCL_TIMEOUT		0x0004
>> -#define WMTI2C_ISR_WRITE_ALL		0x0007
>> +#define VIAI2C_REG_ISR		0x06
>> +#define VIAI2C_ISR_NACK_ADDR		BIT(0)
>> +#define VIAI2C_ISR_BYTE_END		BIT(1)
>> +#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
>> +#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
>>   
>>   /* REG_IMR Bit fields */
>> -#define WMTI2C_REG_IMR		0x08
>> -#define WMTI2C_IMR_ENABLE_ALL		0x0007
>> +#define VIAI2C_REG_IMR		0x08
>> +#define VIAI2C_IMR_BYTE			BIT(1)
>> +#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
>>   
>> -#define WMTI2C_REG_CDR		0x0A
>> -#define WMTI2C_REG_TR		0x0C
>> -#define WMTI2C_REG_MCR		0x0E
>> +#define VIAI2C_REG_CDR		0x0A
>> +#define VIAI2C_REG_TR		0x0C
>> +#define VIAI2C_REG_MCR		0x0E
> These defines have been changed twice in this series. The patches
> should be rearranged in order to avoid this.
>
> I Wolfram is not against, I'm OK with letting it slip this time.


I also realize that repetition is not good,
I only did this in the hope that patches would be easier to review.


>> -struct wmt_i2c {
>> +struct viai2c {
>>   	struct i2c_adapter	adapter;
>>   	struct completion	complete;
>>   	struct device		*dev;
>> @@ -60,7 +60,7 @@ struct wmt_i2c {
>>   	u16			cmd_status;
>>   };
>>   
>> -int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
>> -int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c **pi2c);
>> +int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
>> +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
>>   
>>   #endif
>> diff --git a/drivers/i2c/busses/i2c-wmt-plt.c b/drivers/i2c/busses/i2c-wmt-plt.c
>> index e0ffccf8a40a..8f506888cff7 100644
>> --- a/drivers/i2c/busses/i2c-wmt-plt.c
>> +++ b/drivers/i2c/busses/i2c-wmt-plt.c
>> @@ -22,13 +22,15 @@
>>   #define WMTI2C_MCR_APB_96M		7
>>   #define WMTI2C_MCR_APB_166M		12
>>   
>> +#define wmt_i2c				viai2c
> no, please, do not redefine types. Besides This looks a bit
> dangerous and reckless to me :-)


ok, will use viai2c directly.


>
> Andi

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

* Re: [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked
  2024-01-03 19:39         ` Andi Shyti
@ 2024-01-04  2:30           ` Hans Hu
  2024-01-04  9:18             ` Andi Shyti
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-04  2:30 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen


On 2024/1/4 03:39, Andi Shyti wrote:
> Hi Hans,
>
> [...]
>
>>   static int viai2c_wait_bus_ready(struct viai2c *i2c)
>>   {
>> @@ -25,12 +26,35 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
>>   static int viai2c_wait_status(struct viai2c *i2c)
>>   {
>>   	int ret = 0;
>> -	unsigned long wait_result;
>> +	unsigned long time_left;
>> +	unsigned long delta_ms;
>> +
>> +	time_left = wait_for_completion_timeout(&i2c->complete,
>> +						VIAI2C_TIMEOUT);
>> +	if (!time_left) {
>> +		dev_err(i2c->dev, "bus transfer timeout\n");
>> +		return -EIO;
>> +	}
>>   
>> -	wait_result = wait_for_completion_timeout(&i2c->complete,
>> -						msecs_to_jiffies(500));
>> -	if (!wait_result)
>> -		return -ETIMEDOUT;
> this change is unrelated. Why are you changing the timeout here
> from 500 to 1000?


it does unrelated, will drop it.


>> +	/*
>> +	 * During each byte access, the host performs clock stretching.
>> +	 * In this case, the thread may be interrupted by preemption,
>> +	 * resulting in a long stretching time.
>> +	 * However, some touchpad can only tolerate host clock stretching
>> +	 * of no more than 200 ms. We reduce the impact of this through
>> +	 * a retransmission mechanism.
>> +	 */
> is the hardware sending the stretching on its own?
>

Yes, controller will handle it.


>> +	local_irq_disable();
>> +	i2c->to = ktime_get();
>> +	delta_ms = ktime_to_ms(ktime_sub(i2c->to, i2c->ti));
>> +	if (delta_ms > VIAI2C_STRETCHING_TIMEOUT) {
>> +		local_irq_enable();
>> +		dev_warn(i2c->dev, "thread blocked more than %ldms\n",
>> +				delta_ms);
>> +		return -EAGAIN;
>> +	}
>> +	i2c->ti = i2c->to;
>> +	local_irq_enable();
>>   
>>   	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
>>   		ret = -EIO;
>> @@ -184,6 +208,7 @@ int viai2c_xfer(struct i2c_adapter *adap,
>>   	int ret = 0;
>>   	struct viai2c *i2c = i2c_get_adapdata(adap);
>>   
>> +	i2c->to = i2c->ti = ktime_get();
>>   	for (i = 0; ret >= 0 && i < num; i++) {
>>   		pmsg = &msgs[i];
>>   		if (!(pmsg->flags & I2C_M_NOSTART)) {
>> diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
>> index f171f81e4d0f..73a88398d763 100644
>> --- a/drivers/i2c/busses/i2c-viai2c-common.h
>> +++ b/drivers/i2c/busses/i2c-viai2c-common.h
>> @@ -58,6 +58,8 @@ struct viai2c {
>>   	u16			tcr;
>>   	int			irq;
>>   	u16			cmd_status;
>> +	ktime_t			ti;
>> +	ktime_t			to;
> don't these need some arbitration?
>
> Andi


I don't think it needs to be arbitration.
the controllers are independent of each other,
each access is locked using __i2c_lock_bus_helper().
Am I missing something?


Hans



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

* Re: [PATCH v6 8/8] i2c: add zhaoxin i2c controller driver
  2024-01-03 20:02         ` Andi Shyti
@ 2024-01-04  2:40           ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-01-04  2:40 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen


On 2024/1/4 04:02, Andi Shyti wrote:
> Hi Hans,
>
> [...]
>
>> --- a/drivers/i2c/busses/i2c-viai2c-common.c
>> +++ b/drivers/i2c/busses/i2c-viai2c-common.c
>> @@ -5,7 +5,7 @@
>>   #define VIAI2C_TIMEOUT			(msecs_to_jiffies(1000))
>>   #define VIAI2C_STRETCHING_TIMEOUT	200
>>   
>> -static int viai2c_wait_bus_ready(struct viai2c *i2c)
>> +int viai2c_wait_bus_ready(struct viai2c *i2c)
> no, please, choose the rigth prototype at the beginning, don't
> double change things in the same series.


ok, I will review my patch more carefully.


>>   {
>>   	unsigned long timeout;
>>   	void __iomem *base = i2c->base;
>> @@ -23,7 +23,7 @@ static int viai2c_wait_bus_ready(struct viai2c *i2c)
>>   	return 0;
>>   }
>>   
>> -static int viai2c_wait_status(struct viai2c *i2c)
>> +int viai2c_wait_status(struct viai2c *i2c)
>>   {
>>   	int ret = 0;
>>   	unsigned long time_left;
>> @@ -71,6 +71,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
>>   
>>   	/* save the status and write-clear it */
>>   	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
>> +	if (!i2c->cmd_status)
>> +		return IRQ_NONE;
>> +
> is this change related to this patch? can you put this at the
> beginning?
>
> Andi


The original wmt driver does not have this, maybe I should use
'if (i2c->platform == VIAI2C_PLAT_ZHAOXIN &&! i2c->cmd_status)' instead?


Hans


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

* Re: [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked
  2024-01-04  2:30           ` Hans Hu
@ 2024-01-04  9:18             ` Andi Shyti
  2024-01-04 10:02               ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-04  9:18 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

...

> > > @@ -58,6 +58,8 @@ struct viai2c {
> > >   	u16			tcr;
> > >   	int			irq;
> > >   	u16			cmd_status;
> > > +	ktime_t			ti;
> > > +	ktime_t			to;
> > don't these need some arbitration?
> > 
> 
> I don't think it needs to be arbitration.
> the controllers are independent of each other,
> each access is locked using __i2c_lock_bus_helper().
> Am I missing something?

no, it's fine, it's me who missed that. Do you mind writing a
comment?

Thanks,
Andi

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

* Re: [PATCH v6 4/8] i2c: wmt: split out common files
  2024-01-04  2:04           ` Hans Hu
@ 2024-01-04  9:22             ` Andi Shyti
  2024-01-04  9:45               ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-01-04  9:22 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

> > >   MAINTAINERS                            |   2 +-
> > >   drivers/i2c/busses/Makefile            |   2 +
> > >   drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
> > >   drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
> > >   drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++
> > 'plt' stands for?
> 
> 
> 'plt' is short for 'platform', since it is not suitable,

it's suitable, sure... but not immediately understandable. Your
choice if you want to change it.

> do you think it is better to change it to 'i2c-wmt-platform.c' or
> 'i2c-viai2c-wmt.c' ?

I would rename things to:

i2c-via-wmt.c
i2c-via-common.c
i2c-via-zhaoxin.c

But of course it's not binding.

Andi

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

* Re: [PATCH v6 4/8] i2c: wmt: split out common files
  2024-01-04  9:22             ` Andi Shyti
@ 2024-01-04  9:45               ` Hans Hu
  2024-01-04 12:36                 ` Andi Shyti
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-04  9:45 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen

Hi Andi,


On 2024/1/4 17:22, Andi Shyti wrote:
> Hi Hans,
>
>>>>    MAINTAINERS                            |   2 +-
>>>>    drivers/i2c/busses/Makefile            |   2 +
>>>>    drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
>>>>    drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
>>>>    drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++
>>> 'plt' stands for?
>>
>> 'plt' is short for 'platform', since it is not suitable,
> it's suitable, sure... but not immediately understandable. Your
> choice if you want to change it.
>
>> do you think it is better to change it to 'i2c-wmt-platform.c' or
>> 'i2c-viai2c-wmt.c' ?
> I would rename things to:
>
> i2c-via-wmt.c
> i2c-via-common.c
> i2c-via-zhaoxin.c
>
> But of course it's not binding.


if so, I choose to 'i2c-viai2c-*.c', because there's already a driver 
called 'i2c-via.c'.


Hans,

> Andi

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

* Re: [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked
  2024-01-04  9:18             ` Andi Shyti
@ 2024-01-04 10:02               ` Hans Hu
  2024-01-04 12:37                 ` Andi Shyti
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-04 10:02 UTC (permalink / raw)
  To: Andi Shyti; +Cc: wsa, linux-i2c, cobechen

Hi Andi,


On 2024/1/4 17:18, Andi Shyti wrote:
> Hi Hans,
>
> ...
>
>>>> @@ -58,6 +58,8 @@ struct viai2c {
>>>>    	u16			tcr;
>>>>    	int			irq;
>>>>    	u16			cmd_status;
>>>> +	ktime_t			ti;
>>>> +	ktime_t			to;
>>> don't these need some arbitration?
>>>
>> I don't think it needs to be arbitration.
>> the controllers are independent of each other,
>> each access is locked using __i2c_lock_bus_helper().
>> Am I missing something?
> no, it's fine, it's me who missed that. Do you mind writing a
> comment?


ok, will add a comment like below:
+    /*
+     * During each byte access, the host performs clock stretching.
+     * In this case, the thread may be interrupted by preemption,
+     * resulting in a long stretching time.
+     *
+     * However, some touchpad can only tolerate host clock stretching
+     * of no more than 200 ms. We reduce the impact of this through
+     * a retransmission mechanism.
+     *
+     * Since __i2c_lock_bus_helper() is used to ensure that the
+     * current access will not be interrupted by the other access,
+     * We don't need to worry about arbitration anymore.
+     *
+     */
+    local_irq_disable();
+    i2c->to = ktime_get();


Hans



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

* Re: [PATCH v6 4/8] i2c: wmt: split out common files
  2024-01-04  9:45               ` Hans Hu
@ 2024-01-04 12:36                 ` Andi Shyti
  0 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-01-04 12:36 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

> > > > >    MAINTAINERS                            |   2 +-
> > > > >    drivers/i2c/busses/Makefile            |   2 +
> > > > >    drivers/i2c/busses/i2c-viai2c-common.c | 234 ++++++++++++++
> > > > >    drivers/i2c/busses/i2c-viai2c-common.h |  66 ++++
> > > > >    drivers/i2c/busses/i2c-wmt-plt.c       | 137 ++++++++
> > > > 'plt' stands for?
> > > 
> > > 'plt' is short for 'platform', since it is not suitable,
> > it's suitable, sure... but not immediately understandable. Your
> > choice if you want to change it.
> > 
> > > do you think it is better to change it to 'i2c-wmt-platform.c' or
> > > 'i2c-viai2c-wmt.c' ?
> > I would rename things to:
> > 
> > i2c-via-wmt.c
> > i2c-via-common.c
> > i2c-via-zhaoxin.c
> > 
> > But of course it's not binding.
> 
> 
> if so, I choose to 'i2c-viai2c-*.c', because there's already a driver called
> 'i2c-via.c'.

ack!

Andi

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

* Re: [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked
  2024-01-04 10:02               ` Hans Hu
@ 2024-01-04 12:37                 ` Andi Shyti
  0 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-01-04 12:37 UTC (permalink / raw)
  To: Hans Hu; +Cc: wsa, linux-i2c, cobechen

Hi Hans,

> > > > > @@ -58,6 +58,8 @@ struct viai2c {
> > > > >    	u16			tcr;
> > > > >    	int			irq;
> > > > >    	u16			cmd_status;
> > > > > +	ktime_t			ti;
> > > > > +	ktime_t			to;
> > > > don't these need some arbitration?
> > > > 
> > > I don't think it needs to be arbitration.
> > > the controllers are independent of each other,
> > > each access is locked using __i2c_lock_bus_helper().
> > > Am I missing something?
> > no, it's fine, it's me who missed that. Do you mind writing a
> > comment?
> 
> 
> ok, will add a comment like below:
> +    /*
> +     * During each byte access, the host performs clock stretching.
> +     * In this case, the thread may be interrupted by preemption,
> +     * resulting in a long stretching time.
> +     *
> +     * However, some touchpad can only tolerate host clock stretching
> +     * of no more than 200 ms. We reduce the impact of this through
> +     * a retransmission mechanism.
> +     *
> +     * Since __i2c_lock_bus_helper() is used to ensure that the
> +     * current access will not be interrupted by the other access,
> +     * We don't need to worry about arbitration anymore.
> +     *
> +     */
> +    local_irq_disable();
> +    i2c->to = ktime_get();

ack!

Andi

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

* [PATCH v7 0/6] i2c: add zhaoxin i2c controller driver
  2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
                         ` (8 preceding siblings ...)
  2024-01-03 20:03       ` [PATCH v6 0/8] " Andi Shyti
@ 2024-01-05  7:51       ` Hans Hu
  2024-01-05  7:51         ` [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
                           ` (6 more replies)
  9 siblings, 7 replies; 133+ messages in thread
From: Hans Hu @ 2024-01-05  7:51 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen

v6->v7:
	* adjust the patch sequence
	* put those renaming related patches in 1 patch file
	* rename i2c-*-plt.c to i2c-viai2c-*.c
	* Some other adjustments suggested by Andi
	For more details, see the comment in each patch please.
	Link: https://lore.kernel.org/all/cover.1703830854.git.hanshu-oc@zhaoxin.com/

v5->v6:
	* fix build warnning reported by kernel test robot.
	  Link: https://lore.kernel.org/all/202312291225.cWVt6YF9-lkp@intel.com/
	Link: https://lore.kernel.org/all/cover.1703733126.git.hanshu-oc@zhaoxin.com/

v4->v5:
	* fix 1 build error.
	  Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
	Link: https://lore.kernel.org/all/cover.1703647471.git.hanshu-oc@zhaoxin.com/

v3->v4:
	* Some adjustments as suggested by Wolfram.
	* rebase patch on top of for-next branch.
	Link: https://lore.kernel.org/all/cover.1698889581.git.hanshu-oc@zhaoxin.com/

v2->v3:
	* Split the number of patches from 2 to 12. Make it easier to review.
	Link: https://lore.kernel.org/all/cover.1691999569.git.hanshu-oc@zhaoxin.com/

v1->v2:
	* Fixed some bugs I found myself.
	Link: https://lore.kernel.org/all/cover.1691030850.git.hanshu-oc@zhaoxin.com/

Old version:
	This patch has already gone through a round of reviews.
	Compared with the first round, the main difference of this
	round of patch is the use of i2c-wmt driver.
	Link: https://lore.kernel.org/all/20230614094858.317652-1-hanshu-oc@zhaoxin.com/

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>


Hans Hu (6):
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: split out common files
  i2c: wmt: rename something
  i2c: wmt: fix a bug when thread blocked
  i2c: wmt: add platform type VIAI2C_PLAT_WMT
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                             |  10 +-
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   3 +
 drivers/i2c/busses/i2c-viai2c-common.c  | 267 +++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h  |  81 +++++
 drivers/i2c/busses/i2c-viai2c-wmt.c     | 143 ++++++++
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 282 ++++++++++++++++
 drivers/i2c/busses/i2c-wmt.c            | 417 ------------------------
 8 files changed, 795 insertions(+), 418 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

-- 
2.34.1


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

* [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
@ 2024-01-05  7:51         ` Hans Hu
  2024-01-15 15:17           ` Krzysztof Kozlowski
  2024-02-21 12:10           ` Wolfram Sang
  2024-01-05  7:51         ` [PATCH v7 2/6] i2c: wmt: split out common files Hans Hu
                           ` (5 subsequent siblings)
  6 siblings, 2 replies; 133+ messages in thread
From: Hans Hu @ 2024-01-05  7:51 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen

v5->v7:
	nothing changed.
v4->v5:
	add previous prototype 'static' for wmt_i2c_init().
	Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 67 +++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index ec2a8da134e5..f1888f100d83 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -351,15 +373,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,21 +381,13 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
 	}
 
-	err = i2c_add_adapter(adap);
-	if (err)
-		return err;
-
-	platform_set_drvdata(pdev, i2c_dev);
-
-	return 0;
+	return i2c_add_adapter(adap);
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
-- 
2.34.1


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

* [PATCH v7 2/6] i2c: wmt: split out common files
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
  2024-01-05  7:51         ` [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2024-01-05  7:51         ` Hans Hu
  2024-02-21 12:19           ` Wolfram Sang
  2024-01-05  7:51         ` [PATCH v7 3/6] i2c: wmt: rename something Hans Hu
                           ` (4 subsequent siblings)
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-05  7:51 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen

v6->v7:
	1. adjust the patch sequence: move the split file patch to the front
	2. rename i2c-wmt-plt.c to i2c-viai2c-wmt.c
	3. remove '#define wmt_i2c viai2c', use viai2c directly
	Link: https://lore.kernel.org/all/1871ceb5c3d6804c6a7f7a38327919861985c066.1703830854.git.hanshu-oc@zhaoxin.com/

Since the I2C IP of both wmt and zhaoxin originates from VIA,
it is better to separate the common code first.
The common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-viai2c-wmt.c.

The MAINTAINERS file will be updated accordingly in upcoming commits.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                            |   2 +-
 drivers/i2c/busses/Makefile            |   1 +
 drivers/i2c/busses/i2c-viai2c-common.c | 221 +++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  71 +++++
 drivers/i2c/busses/i2c-viai2c-wmt.c    | 143 +++++++++
 drivers/i2c/busses/i2c-wmt.c           | 422 -------------------------
 6 files changed, 437 insertions(+), 423 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9104430e148e..a73ccc8e89d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2988,7 +2988,7 @@ S:	Orphan
 F:	Documentation/devicetree/bindings/i2c/i2c-wmt.txt
 F:	arch/arm/mach-vt8500/
 F:	drivers/clocksource/timer-vt8500.c
-F:	drivers/i2c/busses/i2c-wmt.c
+F:	drivers/i2c/busses/i2c-viai2c-wmt.c
 F:	drivers/mmc/host/wmt-sdmmc.c
 F:	drivers/pwm/pwm-vt8500.c
 F:	drivers/rtc/rtc-vt8500.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3757b9391e60..06ceb4775cbd 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 000000000000..fa47a4d9549c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+{
+	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+		ret = -EIO;
+
+	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	int xfer_len = 0;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, i2c_dev->base + REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(i2c_dev->base + REG_CR);
+		val &= ~CR_TX_END;
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CSR);
+		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
+			writew(val, i2c_dev->base + REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (last != 1)
+				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
+								REG_CDR);
+			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	u32 xfer_len = 0;
+
+	val = readw(i2c_dev->base + REG_CR);
+	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= CR_TX_NEXT_NO_ACK;
+
+	writew(val, i2c_dev->base + REG_CR);
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	return 0;
+}
+
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = wmt_i2c_read(i2c_dev, pmsg);
+		else
+			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+	struct wmt_i2c_dev *i2c_dev = data;
+
+	/* save the status and write-clear it */
+	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+
+	complete(&i2c_dev->complete);
+
+	return IRQ_HANDLED;
+}
+
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 000000000000..fcff8e4456eb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define REG_CR		0x00
+#define REG_TCR		0x02
+#define REG_CSR		0x04
+#define REG_ISR		0x06
+#define REG_IMR		0x08
+#define REG_CDR		0x0A
+#define REG_TR		0x0C
+#define REG_MCR		0x0E
+
+/* REG_CR Bit fields */
+#define CR_TX_NEXT_ACK		0x0000
+#define CR_ENABLE		0x0001
+#define CR_TX_NEXT_NO_ACK	0x0002
+#define CR_TX_END		0x0004
+#define CR_CPU_RDY		0x0008
+#define SLAV_MODE_SEL		0x8000
+
+/* REG_TCR Bit fields */
+#define TCR_STANDARD_MODE	0x0000
+#define TCR_MASTER_WRITE	0x0000
+#define TCR_HS_MODE		0x2000
+#define TCR_MASTER_READ		0x4000
+#define TCR_FAST_MODE		0x8000
+#define TCR_SLAVE_ADDR_MASK	0x007F
+
+/* REG_ISR Bit fields */
+#define ISR_NACK_ADDR		0x0001
+#define ISR_BYTE_END		0x0002
+#define ISR_SCL_TIMEOUT		0x0004
+#define ISR_WRITE_ALL		0x0007
+
+/* REG_IMR Bit fields */
+#define IMR_ENABLE_ALL		0x0007
+
+/* REG_CSR Bit fields */
+#define CSR_RCV_NOT_ACK		0x0001
+#define CSR_RCV_ACK_MASK	0x0001
+#define CSR_READY_MASK		0x0002
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+struct wmt_i2c_dev {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+};
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
new file mode 100644
index 000000000000..1a80f38d0b88
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+#define REG_SLAVE_CR	0x10
+#define REG_SLAVE_SR	0x12
+#define REG_SLAVE_ISR	0x14
+#define REG_SLAVE_IMR	0x16
+#define REG_SLAVE_DR	0x18
+#define REG_SLAVE_TR	0x1A
+
+/* REG_TR */
+#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define TR_STD			0x0064
+#define TR_HS			0x0019
+
+/* REG_MCR */
+#define MCR_APB_96M		7
+#define MCR_APB_166M		12
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= wmt_i2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+{
+	int err;
+
+	err = clk_prepare_enable(i2c_dev->clk);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c_dev->clk, 20000000);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c_dev->clk);
+		return err;
+	}
+
+	writew(0, i2c_dev->base + REG_CR);
+	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
+	writew(CR_ENABLE, i2c_dev->base + REG_CR);
+	readw(i2c_dev->base + REG_CSR);		/* read clear */
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+
+	if (i2c_dev->tcr == TCR_FAST_MODE)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	else
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c_dev *i2c_dev;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
+
+	i2c_dev->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c_dev->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c_dev->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+		i2c_dev->tcr = TCR_FAST_MODE;
+
+	adap = &i2c_dev->adapter;
+	i2c_set_adapdata(adap, i2c_dev);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c_dev);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	return i2c_add_adapter(adap);
+}
+
+static void wmt_i2c_remove(struct platform_device *pdev)
+{
+	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	/* Disable interrupts, clock and delete adapter */
+	writew(0, i2c_dev->base + REG_IMR);
+	clk_disable_unprepare(i2c_dev->clk);
+	i2c_del_adapter(&i2c_dev->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.remove_new	= wmt_i2c_remove,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index f1888f100d83..000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,422 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
-
-/* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c_dev {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
-{
-	unsigned long timeout;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	int xfer_len = 0;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	u32 xfer_len = 0;
-
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
-
-	writew(val, i2c_dev->base + REG_CR);
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
-		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c_dev *i2c_dev = data;
-
-	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
-
-	complete(&i2c_dev->complete);
-
-	return IRQ_HANDLED;
-}
-
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
-{
-	int err;
-	struct wmt_i2c_dev *i2c_dev;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
-		return -EINVAL;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
-
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
-
-	*pi2c_dev = i2c_dev;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
-{
-	int err;
-
-	err = clk_prepare_enable(i2c_dev->clk);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c_dev->clk, 20000000);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
-		return err;
-	}
-
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
-	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c_dev);
-	if (err)
-		return err;
-
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
-
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	return i2c_add_adapter(adap);
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.34.1


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

* [PATCH v7 3/6] i2c: wmt: rename something
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
  2024-01-05  7:51         ` [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
  2024-01-05  7:51         ` [PATCH v7 2/6] i2c: wmt: split out common files Hans Hu
@ 2024-01-05  7:51         ` Hans Hu
  2024-02-21 12:34           ` Wolfram Sang
  2024-01-05  7:51         ` [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
                           ` (3 subsequent siblings)
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-05  7:51 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen

v6->v7:
	Put those renaming related patches in 1 patch file.
	Link: https://lore.kernel.org/all/75978a2c47f17bf6871b92803e9c075e52aed1b6.1703830854.git.hanshu-oc@zhaoxin.com/
	Link: https://lore.kernel.org/all/c417d693bbdb3a4b804c1c3ba03e57bf4e8c33e1.1703830854.git.hanshu-oc@zhaoxin.com/
	Link: https://lore.kernel.org/all/65b930cefd380ce45e0e1b3967bc7f51737b0948.1703830854.git.hanshu-oc@zhaoxin.com/

1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename
   common registers, functions, and variable names to follow the
   VIAI2C_ and viai2c_ naming conventions for consistency and clarity.
2. rename i2c_dev to i2c, to shorten the length of a line.
3. rename wait_result to time_left, make it better to reflect the meaning
   of the value returned by wait_for_completion_timeout(). 
4. remove TCR_MASTER_WRITE, its value is 0.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 156 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |  70 ++++++-----
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  60 +++++-----
 3 files changed, 142 insertions(+), 144 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index fa47a4d9549c..3e565d5ee4c7 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,14 +2,14 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+int viai2c_wait_bus_not_busy(struct viai2c *i2c)
 {
 	unsigned long timeout;
 
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	timeout = jiffies + VIAI2C_TIMEOUT;
+	while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -18,28 +18,28 @@ int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+int viai2c_check_status(struct viai2c *i2c)
 {
 	int ret = 0;
-	unsigned long wait_result;
+	unsigned long time_left;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+	time_left = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
-	if (!wait_result)
+	if (!time_left)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
 
@@ -49,173 +49,173 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c->base + VIAI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK;
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(i2c->base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
+			writew(val, i2c->base + VIAI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
+					i2c->base + VIAI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c->base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= VIAI2C_CR_RX_END;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c->base + VIAI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= VIAI2C_CR_RX_END;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	return 0;
 }
 
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct viai2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = viai2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
 }
 
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
+static irqreturn_t viai2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct viai2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 {
 	int err;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
+					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index fcff8e4456eb..28799e7e97f0 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -11,48 +11,46 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_READ			BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+#define VIAI2C_TCR_ADDR_MASK		GENMASK(6, 0)
+
+/* REG_CSR Bit fields */
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
 
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
 
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -63,9 +61,9 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+int viai2c_wait_bus_not_busy(struct viai2c *i2c);
+int viai2c_check_status(struct viai2c *i2c);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 1a80f38d0b88..56602f248e1f 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -35,39 +35,39 @@ static u32 wmt_i2c_func(struct i2c_adapter *adap)
 }
 
 static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
+	.master_xfer	= viai2c_xfer,
 	.functionality	= wmt_i2c_func,
 };
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct viai2c *i2c)
 {
 	int err;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c->base + VIAI2C_REG_CR);
+	writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
+	readw(i2c->base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR);
 
 	return 0;
 }
@@ -75,34 +75,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = viai2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c->tcr = VIAI2C_TCR_FAST;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
@@ -113,12 +113,12 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 static void wmt_i2c_remove(struct platform_device *pdev)
 {
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct viai2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	writew(0, i2c->base + VIAI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.34.1


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

* [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
                           ` (2 preceding siblings ...)
  2024-01-05  7:51         ` [PATCH v7 3/6] i2c: wmt: rename something Hans Hu
@ 2024-01-05  7:51         ` Hans Hu
  2024-02-21 12:37           ` Wolfram Sang
  2024-01-05  7:51         ` [PATCH v7 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
                           ` (2 subsequent siblings)
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-05  7:51 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen

v6->v7:
	1. some dirty patches were removed
	2. rename structure member 'to/ti' to 't1/t2'
	   to make it easier to understand.
	3. add a comment about arbitration.
	Link: https://lore.kernel.org/all/b0f284621b6763c32133d39be83f05f1184b3635.1703830854.git.hanshu-oc@zhaoxin.com/

During each byte access, the host performs clock stretching.
In this case, the thread may be interrupted by preemption,
resulting in a long stretching time.

However, some touchpad can only tolerate host clock stretching
of no more than 200 ms. We reduce the impact of this through
a retransmission mechanism.

Since __i2c_lock_bus_helper() is used to ensure that the
current access will not be interrupted by the other access,
We don't need to worry about arbitration anymore.

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 26 ++++++++++++++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  3 +++
 2 files changed, 29 insertions(+)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 3e565d5ee4c7..0fd2554731ca 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -22,12 +22,37 @@ int viai2c_check_status(struct viai2c *i2c)
 {
 	int ret = 0;
 	unsigned long time_left;
+	unsigned long delta_ms;
 
 	time_left = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
 	if (!time_left)
 		return -ETIMEDOUT;
 
+	/*
+	 * During each byte access, the host performs clock stretching.
+	 * In this case, the thread may be interrupted by preemption,
+	 * resulting in a long stretching time.
+	 *
+	 * However, some touchpad can only tolerate host clock stretching
+	 * of no more than 200 ms. We reduce the impact of this through
+	 * a retransmission mechanism.
+	 *
+	 * Since __i2c_lock_bus_helper() is used to ensure that the
+	 * current access will not be interrupted by the other access,
+	 * We don't need to worry about arbitration anymore.
+	 */
+	local_irq_disable();
+	i2c->t2 = ktime_get();
+	delta_ms = ktime_to_ms(ktime_sub(i2c->t2, i2c->t1));
+	if (delta_ms > VIAI2C_STRETCHING_TIMEOUT) {
+		local_irq_enable();
+		dev_warn(i2c->dev, "thread blocked more than %ldms\n", delta_ms);
+		return -EAGAIN;
+	}
+	i2c->t1 = i2c->t2;
+	local_irq_enable();
+
 	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
@@ -158,6 +183,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	int ret = 0;
 	struct viai2c *i2c = i2c_get_adapdata(adap);
 
+	i2c->t2 = i2c->t1 = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 28799e7e97f0..d0ffba22104d 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -49,6 +49,7 @@
 #define VIAI2C_REG_MCR		0x0E
 
 #define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_STRETCHING_TIMEOUT	200
 
 struct viai2c {
 	struct i2c_adapter	adapter;
@@ -59,6 +60,8 @@ struct viai2c {
 	u16			tcr;
 	int			irq;
 	u16			cmd_status;
+	ktime_t			t1;
+	ktime_t			t2;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
-- 
2.34.1


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

* [PATCH v7 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
                           ` (3 preceding siblings ...)
  2024-01-05  7:51         ` [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2024-01-05  7:51         ` Hans Hu
  2024-02-21 12:39           ` Wolfram Sang
  2024-01-05  7:51         ` [PATCH v7 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-05  7:51 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen

Enumeration variables are added to differentiate
between different platforms.

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 31 +++++++++++++++++---------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 +++++-
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  2 +-
 3 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 0fd2554731ca..2bc34a574fab 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -79,7 +79,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -92,7 +92,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -118,7 +118,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		}
 
 		if (xfer_len == pmsg->len) {
-			if (last != 1)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
@@ -139,7 +139,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(i2c->base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -153,7 +153,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -186,7 +186,8 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	i2c->t2 = i2c->t1 = ktime_get();
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if ((i2c->platform == VIAI2C_PLAT_WMT)
+		   && !(pmsg->flags & I2C_M_NOSTART)) {
 			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
@@ -214,9 +215,10 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 {
 	int err;
+	int irq_flags;
 	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
@@ -228,12 +230,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 	if (IS_ERR(i2c->base))
 		return PTR_ERR(i2c->base);
 
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
+	if (plat == VIAI2C_PLAT_WMT) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else {
+		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
+	}
+
+	i2c->platform = plat;
 
 	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
-					0, pdev->name, i2c);
+					irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
 				"failed to request irq %i\n", i2c->irq);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index d0ffba22104d..4da330d8cfea 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -51,6 +51,10 @@
 #define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 #define VIAI2C_STRETCHING_TIMEOUT	200
 
+enum {
+	VIAI2C_PLAT_WMT = 1,
+};
+
 struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
@@ -62,11 +66,12 @@ struct viai2c {
 	u16			cmd_status;
 	ktime_t			t1;
 	ktime_t			t2;
+	int			platform;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
 int viai2c_check_status(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 56602f248e1f..ba22fdc0f27c 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -80,7 +80,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = viai2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
 	if (err)
 		return err;
 
-- 
2.34.1


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

* [PATCH v7 6/6] i2c: add zhaoxin i2c controller driver
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
                           ` (4 preceding siblings ...)
  2024-01-05  7:51         ` [PATCH v7 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2024-01-05  7:51         ` Hans Hu
  2024-02-21 12:44           ` Wolfram Sang
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-05  7:51 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen

v6->v7:
	1. rename 'i2c-zhaoxin-plt.c' to 'i2c-viai2c-zhaoxin.c'
	2. remove '#define zxi2c viai2c', use viai2c directly

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the "IIC1D17" HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                             |   8 +
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c  |  17 +-
 drivers/i2c/busses/i2c-viai2c-common.h  |   4 +
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 282 ++++++++++++++++++++++++
 6 files changed, 320 insertions(+), 3 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a73ccc8e89d0..afbd95a4f759 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10023,6 +10023,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-viai2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 28eb48dd5b32..6ccc9f858c90 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -336,6 +336,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 06ceb4775cbd..faeca9c41fc7 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 2bc34a574fab..06a35485b9d1 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -120,6 +120,8 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		if (xfer_len == pmsg->len) {
 			if (i2c->platform == VIAI2C_PLAT_WMT && !last)
 				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && last)
+				writeb(VIAI2C_CR_TX_END, i2c->base + VIAI2C_REG_CR);
 		} else {
 			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
@@ -130,7 +132,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 	return 0;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 	int ret;
@@ -153,7 +155,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART))
+	   || (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -194,7 +197,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
@@ -208,6 +211,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!i2c->cmd_status && i2c->platform == VIAI2C_PLAT_ZHAOXIN)
+		return IRQ_NONE;
+
 	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
 	complete(&i2c->complete);
@@ -235,6 +241,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 		i2c->irq = irq_of_parse_and_map(np, 0);
 		if (!i2c->irq)
 			return -EINVAL;
+	} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	} else {
 		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
 	}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 4da330d8cfea..a3dab19c3873 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -53,6 +53,7 @@
 
 enum {
 	VIAI2C_PLAT_WMT = 1,
+	VIAI2C_PLAT_ZHAOXIN
 };
 
 struct viai2c {
@@ -67,6 +68,9 @@ struct viai2c {
 	ktime_t			t1;
 	ktime_t			t2;
 	int			platform;
+	u8			hrv;
+	u16			tr;
+	u16			mcr;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
new file mode 100644
index 000000000000..f0e5bc632e5d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include "i2c-viai2c-common.h"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+
+#define ZXI2C_FIFO_SIZE		32
+
+static int zxi2c_fifo_xfer(struct viai2c *i2c, struct i2c_msg *msg)
+{
+	u16 xfered_len = 0;
+	u16 byte_left = msg->len;
+	u16 tcr_val = i2c->tcr;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+
+	i2c->t2 = i2c->t1 = ktime_get();
+	while (byte_left) {
+		u16 i;
+		u8 tmp;
+		int error;
+		u16 xfer_len = min_t(u16, byte_left, ZXI2C_FIFO_SIZE);
+
+		byte_left -= xfer_len;
+
+		/* reset fifo buffer */
+		tmp = ioread8(base + ZXI2C_REG_HCR);
+		iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+		/* set xfer len */
+		if (read) {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HRLR);
+		} else {
+			iowrite8(xfer_len - 1, base + ZXI2C_REG_HTLR);
+			/* set write data */
+			for (i = 0; i < xfer_len; i++)
+				iowrite8(msg->buf[xfered_len + i], base + ZXI2C_REG_HTDR);
+		}
+
+		/* prepare to stop transmission */
+		if (i2c->hrv && !byte_left) {
+			tmp = ioread8(base + VIAI2C_REG_CR);
+			tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+			iowrite8(tmp, base + VIAI2C_REG_CR);
+		}
+
+		reinit_completion(&i2c->complete);
+
+		if (xfered_len) {
+			/* continue transmission */
+			tmp = ioread8(base + VIAI2C_REG_CR);
+			iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
+		} else {
+			/* start transmission */
+			tcr_val |= read ? VIAI2C_TCR_READ : 0;
+			writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+		}
+
+		error = viai2c_check_status(i2c);
+		if (error)
+			return error;
+
+		/* get the received data */
+		if (read)
+			for (i = 0; i < xfer_len; i++)
+				msg->buf[xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR);
+
+		xfered_len += xfer_len;
+	}
+
+	return 1;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap);
+	void __iomem *base = i2c->base;
+
+	ret = viai2c_wait_bus_not_busy(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 && (i2c->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR);
+
+		ret = zxi2c_fifo_xfer(i2c, msgs);
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret < 0)
+			iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR);
+		/* make sure the state machine is stopped */
+		usleep_range(1, 2);
+	}
+	/* dis interrupt */
+	iowrite8(0, base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct viai2c *i2c)
+{
+	iowrite16(i2c->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(i2c->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct viai2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
+				params[0], fstp, params[2]);
+		i2c->tr = params[2] | 0xff00;
+	} else {
+		i2c->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	i2c->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0x80 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		i2c->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct viai2c *i2c;
+	struct i2c_adapter *adap;
+
+	error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
+	if (error)
+		return error;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	i2c->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->retries = 2;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
+			dev_name(pdev->dev.parent), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int __maybe_unused zxi2c_resume(struct device *dev)
+{
+	struct viai2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = "i2c_zhaoxin",
+		.acpi_match_table = zxi2c_acpi_match,
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* Re: [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-01-05  7:51         ` [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2024-01-15 15:17           ` Krzysztof Kozlowski
  2024-01-16  1:43             ` Hans Hu
  2024-02-21 12:10           ` Wolfram Sang
  1 sibling, 1 reply; 133+ messages in thread
From: Krzysztof Kozlowski @ 2024-01-15 15:17 UTC (permalink / raw)
  To: Hans Hu, andi.shyti, linux-i2c; +Cc: wsa, cobechen

On 05/01/2024 08:51, Hans Hu wrote:
> v5->v7:
> 	nothing changed.
> v4->v5:
> 	add previous prototype 'static' for wmt_i2c_init().
> 	Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt

Why there is only changelog and no commit msg? Changelog goes usually
under ---, especially if it is quite non-informative...

Best regards,
Krzysztof


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

* Re: [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-01-15 15:17           ` Krzysztof Kozlowski
@ 2024-01-16  1:43             ` Hans Hu
  2024-01-21 23:56               ` Andi Shyti
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-01-16  1:43 UTC (permalink / raw)
  To: Krzysztof Kozlowski, andi.shyti, linux-i2c; +Cc: wsa, cobechen

Hi Krzysztof,


On 2024/1/15 23:17, Krzysztof Kozlowski wrote:
>
> On 05/01/2024 08:51, Hans Hu wrote:
>> v5->v7:
>>        nothing changed.
>> v4->v5:
>>        add previous prototype 'static' for wmt_i2c_init().
>>        Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
> Why there is only changelog and no commit msg? Changelog goes usually
> under ---, especially if it is quite non-informative...


Commit msg comes after changelog. Yes, I should have put
commit msg at the beginning. Other patches also have this
problem. Adjustments will be made at the next submission.

Hans,
Thank you



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

* Re: [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-01-16  1:43             ` Hans Hu
@ 2024-01-21 23:56               ` Andi Shyti
  0 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-01-21 23:56 UTC (permalink / raw)
  To: Hans Hu; +Cc: Krzysztof Kozlowski, linux-i2c, wsa, cobechen

Hi Hans,

> > On 05/01/2024 08:51, Hans Hu wrote:
> > > v5->v7:
> > >        nothing changed.
> > > v4->v5:
> > >        add previous prototype 'static' for wmt_i2c_init().
> > >        Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
> > Why there is only changelog and no commit msg? Changelog goes usually
> > under ---, especially if it is quite non-informative...
> 
> Commit msg comes after changelog. Yes, I should have put
> commit msg at the beginning. Other patches also have this
> problem. Adjustments will be made at the next submission.

While it can be convenient to include the changelog in each
patch from the reviewers perspective, having it all in patch 0 is
sufficient.

Personally, I'm not in favour of adding the changelog to the
commit log, even though it's a practice common in many
communities. However, I'm open to whatever approach you select, 
provided there is consistency.

If you decide to keep the changelog, consider placing it at the
end of the commit message, right before the tag section.

Andi

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

* Re: [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-01-05  7:51         ` [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
  2024-01-15 15:17           ` Krzysztof Kozlowski
@ 2024-02-21 12:10           ` Wolfram Sang
  1 sibling, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2024-02-21 12:10 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Fri, Jan 05, 2024 at 03:51:44PM +0800, Hans Hu wrote:
> v5->v7:
> 	nothing changed.
> v4->v5:
> 	add previous prototype 'static' for wmt_i2c_init().
> 	Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
> 
> Some common initialization actions are put in the function
> wmt_i2c_init(), which is convenient to share with zhaoxin.
> 
> Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v7 2/6] i2c: wmt: split out common files
  2024-01-05  7:51         ` [PATCH v7 2/6] i2c: wmt: split out common files Hans Hu
@ 2024-02-21 12:19           ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2024-02-21 12:19 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Fri, Jan 05, 2024 at 03:51:45PM +0800, Hans Hu wrote:
> v6->v7:
> 	1. adjust the patch sequence: move the split file patch to the front
> 	2. rename i2c-wmt-plt.c to i2c-viai2c-wmt.c
> 	3. remove '#define wmt_i2c viai2c', use viai2c directly
> 	Link: https://lore.kernel.org/all/1871ceb5c3d6804c6a7f7a38327919861985c066.1703830854.git.hanshu-oc@zhaoxin.com/
> 
> Since the I2C IP of both wmt and zhaoxin originates from VIA,
> it is better to separate the common code first.
> The common driver is named as i2c-viai2c-common.c.
> Old i2c-wmt.c renamed to i2c-viai2c-wmt.c.
> 
> The MAINTAINERS file will be updated accordingly in upcoming commits.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Looks good from a high level point of view plus some detail checks:

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v7 3/6] i2c: wmt: rename something
  2024-01-05  7:51         ` [PATCH v7 3/6] i2c: wmt: rename something Hans Hu
@ 2024-02-21 12:34           ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2024-02-21 12:34 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Fri, Jan 05, 2024 at 03:51:46PM +0800, Hans Hu wrote:
> v6->v7:
> 	Put those renaming related patches in 1 patch file.
> 	Link: https://lore.kernel.org/all/75978a2c47f17bf6871b92803e9c075e52aed1b6.1703830854.git.hanshu-oc@zhaoxin.com/
> 	Link: https://lore.kernel.org/all/c417d693bbdb3a4b804c1c3ba03e57bf4e8c33e1.1703830854.git.hanshu-oc@zhaoxin.com/
> 	Link: https://lore.kernel.org/all/65b930cefd380ce45e0e1b3967bc7f51737b0948.1703830854.git.hanshu-oc@zhaoxin.com/
> 
> 1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename
>    common registers, functions, and variable names to follow the
>    VIAI2C_ and viai2c_ naming conventions for consistency and clarity.
> 2. rename i2c_dev to i2c, to shorten the length of a line.
> 3. rename wait_result to time_left, make it better to reflect the meaning
>    of the value returned by wait_for_completion_timeout(). 
> 4. remove TCR_MASTER_WRITE, its value is 0.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Maybe not super necessary, but OK:

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked
  2024-01-05  7:51         ` [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2024-02-21 12:37           ` Wolfram Sang
  2024-02-22  9:03             ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2024-02-21 12:37 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

Hi,

On Fri, Jan 05, 2024 at 03:51:47PM +0800, Hans Hu wrote:
> v6->v7:
> 	1. some dirty patches were removed
> 	2. rename structure member 'to/ti' to 't1/t2'
> 	   to make it easier to understand.
> 	3. add a comment about arbitration.
> 	Link: https://lore.kernel.org/all/b0f284621b6763c32133d39be83f05f1184b3635.1703830854.git.hanshu-oc@zhaoxin.com/
> 
> During each byte access, the host performs clock stretching.
> In this case, the thread may be interrupted by preemption,
> resulting in a long stretching time.
> 
> However, some touchpad can only tolerate host clock stretching
> of no more than 200 ms. We reduce the impact of this through
> a retransmission mechanism.
> 
> Since __i2c_lock_bus_helper() is used to ensure that the
> current access will not be interrupted by the other access,
> We don't need to worry about arbitration anymore.
> 
> Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Uh oh, NACK. We shouldn't limit clock stretching because some touchpad
controllers can't handle it.

The first thing I suggest is to move more handling to the interrupt
context, like filling the next byte after the previous has been
processed. Then, you are not interruptible anymore.

If this all fails, we need to determine a bus specific property, but I
am quite sure the above conversion will be enough.

Maybe it is an idea to first get the driver converted to support your
platform, and afterwards the conversion to more handling in interrupt.

Kind regards,

   Wolfram


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v7 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2024-01-05  7:51         ` [PATCH v7 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2024-02-21 12:39           ` Wolfram Sang
  2024-02-22  8:50             ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2024-02-21 12:39 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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


> +enum {
> +	VIAI2C_PLAT_WMT = 1,
> +};

Minor, but why not starting at 0?

>  struct viai2c {
>  	struct i2c_adapter	adapter;
>  	struct completion	complete;
> @@ -62,11 +66,12 @@ struct viai2c {
>  	u16			cmd_status;
>  	ktime_t			t1;
>  	ktime_t			t2;
> +	int			platform;

unsigned int?


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v7 6/6] i2c: add zhaoxin i2c controller driver
  2024-01-05  7:51         ` [PATCH v7 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2024-02-21 12:44           ` Wolfram Sang
  2024-02-22  8:49             ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2024-02-21 12:44 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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


> @@ -67,6 +68,9 @@ struct viai2c {
>  	ktime_t			t1;
>  	ktime_t			t2;
>  	int			platform;
> +	u8			hrv;
> +	u16			tr;
> +	u16			mcr;

Hmm, since this is zhaoxin specific, what about adding

	void			*pltfm_priv;

and put 'hrv', 'tr', and 'mcr' to a struct 'viai2c_zhaoxin' local to
i2c-viai2c-zhaoxin.c and populate pltfm_priv with it?

Rest looks good so far...


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v7 6/6] i2c: add zhaoxin i2c controller driver
  2024-02-21 12:44           ` Wolfram Sang
@ 2024-02-22  8:49             ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-02-22  8:49 UTC (permalink / raw)
  To: Wolfram Sang, andi.shyti, linux-i2c, cobechen

Hi Wolfram,


>> @@ -67,6 +68,9 @@ struct viai2c {
>>   	ktime_t			t1;
>>   	ktime_t			t2;
>>   	int			platform;
>> +	u8			hrv;
>> +	u16			tr;
>> +	u16			mcr;
> Hmm, since this is zhaoxin specific, what about adding
>
> 	void			*pltfm_priv;
>
> and put 'hrv', 'tr', and 'mcr' to a struct 'viai2c_zhaoxin' local to
> i2c-viai2c-zhaoxin.c and populate pltfm_priv with it?
>
> Rest looks good so far...
>

will add it.

Hans,
Thank you



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

* Re: [PATCH v7 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2024-02-21 12:39           ` Wolfram Sang
@ 2024-02-22  8:50             ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-02-22  8:50 UTC (permalink / raw)
  To: Wolfram Sang, andi.shyti, linux-i2c, cobechen

Hi Wolfram,

>> +enum {
>> +	VIAI2C_PLAT_WMT = 1,
>> +};
> Minor, but why not starting at 0?
>
>>   struct viai2c {
>>   	struct i2c_adapter	adapter;
>>   	struct completion	complete;
>> @@ -62,11 +66,12 @@ struct viai2c {
>>   	u16			cmd_status;
>>   	ktime_t			t1;
>>   	ktime_t			t2;
>> +	int			platform;
> unsigned int?
>

will change it.

Hans,
Thank you


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

* Re: [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked
  2024-02-21 12:37           ` Wolfram Sang
@ 2024-02-22  9:03             ` Hans Hu
  2024-02-22  9:37               ` Wolfram Sang
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-02-22  9:03 UTC (permalink / raw)
  To: Wolfram Sang, andi.shyti, linux-i2c, cobechen

Hi Wolfram,


On 2024/2/21 20:37, Wolfram Sang wrote:
> Hi,
>
> On Fri, Jan 05, 2024 at 03:51:47PM +0800, Hans Hu wrote:
>> v6->v7:
>> 	1. some dirty patches were removed
>> 	2. rename structure member 'to/ti' to 't1/t2'
>> 	   to make it easier to understand.
>> 	3. add a comment about arbitration.
>> 	Link: https://lore.kernel.org/all/b0f284621b6763c32133d39be83f05f1184b3635.1703830854.git.hanshu-oc@zhaoxin.com/
>>
>> During each byte access, the host performs clock stretching.
>> In this case, the thread may be interrupted by preemption,
>> resulting in a long stretching time.
>>
>> However, some touchpad can only tolerate host clock stretching
>> of no more than 200 ms. We reduce the impact of this through
>> a retransmission mechanism.
>>
>> Since __i2c_lock_bus_helper() is used to ensure that the
>> current access will not be interrupted by the other access,
>> We don't need to worry about arbitration anymore.
>>
>> Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
>> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> Uh oh, NACK. We shouldn't limit clock stretching because some touchpad
> controllers can't handle it.
>
> The first thing I suggest is to move more handling to the interrupt
> context, like filling the next byte after the previous has been
> processed. Then, you are not interruptible anymore.
>
> If this all fails, we need to determine a bus specific property, but I
> am quite sure the above conversion will be enough.
>
> Maybe it is an idea to first get the driver converted to support your
> platform, and afterwards the conversion to more handling in interrupt.
>
> Kind regards,
>
>     Wolfram
>

Thanks for your suggestion, the purpose of this approach is to
reduce the clock stretching caused by the system. Therefore,
I try to put almost all of the processing in the interrupt context.

Hans,
Thank you


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

* Re: [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked
  2024-02-22  9:03             ` Hans Hu
@ 2024-02-22  9:37               ` Wolfram Sang
  2024-02-22 10:42                 ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2024-02-22  9:37 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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


> Thanks for your suggestion, the purpose of this approach is to
> reduce the clock stretching caused by the system. Therefore,
> I try to put almost all of the processing in the interrupt context.

Well, I think per-msg handling in interrupt context is enough. The
transfer (consisting of multiple messages) handling is usually best left
in process context.


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked
  2024-02-22  9:37               ` Wolfram Sang
@ 2024-02-22 10:42                 ` Hans Hu
  2024-02-22 17:26                   ` Wolfram Sang
  0 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-02-22 10:42 UTC (permalink / raw)
  To: Wolfram Sang, andi.shyti, linux-i2c, cobechen


>> Thanks for your suggestion, the purpose of this approach is to
>> reduce the clock stretching caused by the system. Therefore,
>> I try to put almost all of the processing in the interrupt context.
> Well, I think per-msg handling in interrupt context is enough. The
> transfer (consisting of multiple messages) handling is usually best left
> in process context.
>

OK, I understand now.

Hans,
Thank you


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

* Re: [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked
  2024-02-22 10:42                 ` Hans Hu
@ 2024-02-22 17:26                   ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2024-02-22 17:26 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen

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

On Thu, Feb 22, 2024 at 06:42:20PM +0800, Hans Hu wrote:
> 
> > > Thanks for your suggestion, the purpose of this approach is to
> > > reduce the clock stretching caused by the system. Therefore,
> > > I try to put almost all of the processing in the interrupt context.
> > Well, I think per-msg handling in interrupt context is enough. The
> > transfer (consisting of multiple messages) handling is usually best left
> > in process context.
> > 
> 
> OK, I understand now.

If you need inspiration, check i2c-digicolor.c for a simple driver
implementing it.


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* [PATCH v8 0/6] i2c: add zhaoxin i2c controller driver
  2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
                           ` (5 preceding siblings ...)
  2024-01-05  7:51         ` [PATCH v7 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2024-02-27  6:36         ` Hans Hu
  2024-02-27  6:36           ` [PATCH v8 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
                             ` (6 more replies)
  6 siblings, 7 replies; 133+ messages in thread
From: Hans Hu @ 2024-02-27  6:36 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu

v7->v8:
	* move per-msg handling to interrupt context
	* add private struct viai2c_zhaoxin to handle zhaoxin specific things
	* fixed some other formatting issues
	Link: https://lore.kernel.org/all/cover.1704440251.git.hanshu-oc@zhaoxin.com/

v6->v7:
	* adjust the patch sequence
	* put those renaming related patches in 1 patch file
	* rename i2c-*-plt.c to i2c-viai2c-*.c
	* Some other adjustments suggested by Andi
	For more details, see the comment in each patch please.
	Link: https://lore.kernel.org/all/cover.1703830854.git.hanshu-oc@zhaoxin.com/

v5->v6:
	* fix build warnning reported by kernel test robot.
	  Link: https://lore.kernel.org/all/202312291225.cWVt6YF9-lkp@intel.com/
	Link: https://lore.kernel.org/all/cover.1703733126.git.hanshu-oc@zhaoxin.com/

v4->v5:
	* fix 1 build error.
	  Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
	Link: https://lore.kernel.org/all/cover.1703647471.git.hanshu-oc@zhaoxin.com/

v3->v4:
	* Some adjustments as suggested by Wolfram.
	* rebase patch on top of for-next branch.
	Link: https://lore.kernel.org/all/cover.1698889581.git.hanshu-oc@zhaoxin.com/

v2->v3:
	* Split the number of patches from 2 to 12. Make it easier to review.
	Link: https://lore.kernel.org/all/cover.1691999569.git.hanshu-oc@zhaoxin.com/

v1->v2:
	* Fixed some bugs I found myself.
	Link: https://lore.kernel.org/all/cover.1691030850.git.hanshu-oc@zhaoxin.com/

Old version:
	This patch has already gone through a round of reviews.
	Compared with the first round, the main difference of this
	round of patch is the use of i2c-wmt driver.
	Link: https://lore.kernel.org/all/20230614094858.317652-1-hanshu-oc@zhaoxin.com/

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Hans Hu (6):
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: split out common files
  i2c: wmt: rename something
  i2c: wmt: fix a bug when thread blocked
  i2c: wmt: add platform type VIAI2C_PLAT_WMT
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                             |  10 +-
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   3 +
 drivers/i2c/busses/i2c-viai2c-common.c  | 250 ++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h  |  85 +++++
 drivers/i2c/busses/i2c-viai2c-wmt.c     | 143 ++++++++
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 299 +++++++++++++++++
 drivers/i2c/busses/i2c-wmt.c            | 417 ------------------------
 8 files changed, 799 insertions(+), 418 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

-- 
2.34.1


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

* [PATCH v8 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
@ 2024-02-27  6:36           ` Hans Hu
  2024-02-27  6:36           ` [PATCH v8 2/6] i2c: wmt: split out common files Hans Hu
                             ` (5 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-02-27  6:36 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

---
 drivers/i2c/busses/i2c-wmt.c | 67 +++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 31 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index ec2a8da134e5..f1888f100d83 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -351,15 +373,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,21 +381,13 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
 	}
 
-	err = i2c_add_adapter(adap);
-	if (err)
-		return err;
-
-	platform_set_drvdata(pdev, i2c_dev);
-
-	return 0;
+	return i2c_add_adapter(adap);
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
-- 
2.34.1


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

* [PATCH v8 2/6] i2c: wmt: split out common files
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
  2024-02-27  6:36           ` [PATCH v8 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2024-02-27  6:36           ` Hans Hu
  2024-02-27  6:36           ` [PATCH v8 3/6] i2c: wmt: rename something Hans Hu
                             ` (4 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-02-27  6:36 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

Since the I2C IP of both wmt and zhaoxin originates from VIA,
it is better to separate the common code first.
The common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-viai2c-wmt.c.

The MAINTAINERS file will be updated accordingly in upcoming commits.

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

---
 MAINTAINERS                            |   2 +-
 drivers/i2c/busses/Makefile            |   1 +
 drivers/i2c/busses/i2c-viai2c-common.c | 221 +++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  71 +++++
 drivers/i2c/busses/i2c-viai2c-wmt.c    | 143 +++++++++
 drivers/i2c/busses/i2c-wmt.c           | 422 -------------------------
 6 files changed, 437 insertions(+), 423 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 9104430e148e..a73ccc8e89d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2988,7 +2988,7 @@ S:	Orphan
 F:	Documentation/devicetree/bindings/i2c/i2c-wmt.txt
 F:	arch/arm/mach-vt8500/
 F:	drivers/clocksource/timer-vt8500.c
-F:	drivers/i2c/busses/i2c-wmt.c
+F:	drivers/i2c/busses/i2c-viai2c-wmt.c
 F:	drivers/mmc/host/wmt-sdmmc.c
 F:	drivers/pwm/pwm-vt8500.c
 F:	drivers/rtc/rtc-vt8500.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3757b9391e60..06ceb4775cbd 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -120,6 +120,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 000000000000..fa47a4d9549c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+{
+	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+		ret = -EIO;
+
+	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	int xfer_len = 0;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, i2c_dev->base + REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(i2c_dev->base + REG_CR);
+		val &= ~CR_TX_END;
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CSR);
+		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
+			writew(val, i2c_dev->base + REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (last != 1)
+				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
+								REG_CDR);
+			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	u32 xfer_len = 0;
+
+	val = readw(i2c_dev->base + REG_CR);
+	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= CR_TX_NEXT_NO_ACK;
+
+	writew(val, i2c_dev->base + REG_CR);
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	return 0;
+}
+
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = wmt_i2c_read(i2c_dev, pmsg);
+		else
+			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+	struct wmt_i2c_dev *i2c_dev = data;
+
+	/* save the status and write-clear it */
+	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+
+	complete(&i2c_dev->complete);
+
+	return IRQ_HANDLED;
+}
+
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 000000000000..fcff8e4456eb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define REG_CR		0x00
+#define REG_TCR		0x02
+#define REG_CSR		0x04
+#define REG_ISR		0x06
+#define REG_IMR		0x08
+#define REG_CDR		0x0A
+#define REG_TR		0x0C
+#define REG_MCR		0x0E
+
+/* REG_CR Bit fields */
+#define CR_TX_NEXT_ACK		0x0000
+#define CR_ENABLE		0x0001
+#define CR_TX_NEXT_NO_ACK	0x0002
+#define CR_TX_END		0x0004
+#define CR_CPU_RDY		0x0008
+#define SLAV_MODE_SEL		0x8000
+
+/* REG_TCR Bit fields */
+#define TCR_STANDARD_MODE	0x0000
+#define TCR_MASTER_WRITE	0x0000
+#define TCR_HS_MODE		0x2000
+#define TCR_MASTER_READ		0x4000
+#define TCR_FAST_MODE		0x8000
+#define TCR_SLAVE_ADDR_MASK	0x007F
+
+/* REG_ISR Bit fields */
+#define ISR_NACK_ADDR		0x0001
+#define ISR_BYTE_END		0x0002
+#define ISR_SCL_TIMEOUT		0x0004
+#define ISR_WRITE_ALL		0x0007
+
+/* REG_IMR Bit fields */
+#define IMR_ENABLE_ALL		0x0007
+
+/* REG_CSR Bit fields */
+#define CSR_RCV_NOT_ACK		0x0001
+#define CSR_RCV_ACK_MASK	0x0001
+#define CSR_READY_MASK		0x0002
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+struct wmt_i2c_dev {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+};
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
new file mode 100644
index 000000000000..1a80f38d0b88
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+#define REG_SLAVE_CR	0x10
+#define REG_SLAVE_SR	0x12
+#define REG_SLAVE_ISR	0x14
+#define REG_SLAVE_IMR	0x16
+#define REG_SLAVE_DR	0x18
+#define REG_SLAVE_TR	0x1A
+
+/* REG_TR */
+#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define TR_STD			0x0064
+#define TR_HS			0x0019
+
+/* REG_MCR */
+#define MCR_APB_96M		7
+#define MCR_APB_166M		12
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= wmt_i2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+{
+	int err;
+
+	err = clk_prepare_enable(i2c_dev->clk);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c_dev->clk, 20000000);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c_dev->clk);
+		return err;
+	}
+
+	writew(0, i2c_dev->base + REG_CR);
+	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
+	writew(CR_ENABLE, i2c_dev->base + REG_CR);
+	readw(i2c_dev->base + REG_CSR);		/* read clear */
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+
+	if (i2c_dev->tcr == TCR_FAST_MODE)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	else
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c_dev *i2c_dev;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
+
+	i2c_dev->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c_dev->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c_dev->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+		i2c_dev->tcr = TCR_FAST_MODE;
+
+	adap = &i2c_dev->adapter;
+	i2c_set_adapdata(adap, i2c_dev);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c_dev);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	return i2c_add_adapter(adap);
+}
+
+static void wmt_i2c_remove(struct platform_device *pdev)
+{
+	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	/* Disable interrupts, clock and delete adapter */
+	writew(0, i2c_dev->base + REG_IMR);
+	clk_disable_unprepare(i2c_dev->clk);
+	i2c_del_adapter(&i2c_dev->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.remove_new	= wmt_i2c_remove,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index f1888f100d83..000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,422 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
-
-/* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c_dev {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
-{
-	unsigned long timeout;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	int xfer_len = 0;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	u32 xfer_len = 0;
-
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
-
-	writew(val, i2c_dev->base + REG_CR);
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
-		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c_dev *i2c_dev = data;
-
-	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
-
-	complete(&i2c_dev->complete);
-
-	return IRQ_HANDLED;
-}
-
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
-{
-	int err;
-	struct wmt_i2c_dev *i2c_dev;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
-		return -EINVAL;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
-
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
-
-	*pi2c_dev = i2c_dev;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
-{
-	int err;
-
-	err = clk_prepare_enable(i2c_dev->clk);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c_dev->clk, 20000000);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
-		return err;
-	}
-
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
-	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c_dev);
-	if (err)
-		return err;
-
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
-
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	return i2c_add_adapter(adap);
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.34.1


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

* [PATCH v8 3/6] i2c: wmt: rename something
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
  2024-02-27  6:36           ` [PATCH v8 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
  2024-02-27  6:36           ` [PATCH v8 2/6] i2c: wmt: split out common files Hans Hu
@ 2024-02-27  6:36           ` Hans Hu
  2024-02-27  6:36           ` [PATCH v8 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
                             ` (3 subsequent siblings)
  6 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-02-27  6:36 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename
   common registers, functions, and variable names to follow the
   VIAI2C_ and viai2c_ naming conventions for consistency and clarity.
2. rename i2c_dev to i2c, to shorten the length of a line.
3. rename wait_result to time_left, make it better to reflect the meaning
   of the value returned by wait_for_completion_timeout(). 
4. remove TCR_MASTER_WRITE, its value is 0.

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

---
 drivers/i2c/busses/i2c-viai2c-common.c | 156 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |  70 ++++++-----
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  60 +++++-----
 3 files changed, 142 insertions(+), 144 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index fa47a4d9549c..3e565d5ee4c7 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,14 +2,14 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+int viai2c_wait_bus_not_busy(struct viai2c *i2c)
 {
 	unsigned long timeout;
 
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	timeout = jiffies + VIAI2C_TIMEOUT;
+	while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -18,28 +18,28 @@ int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+int viai2c_check_status(struct viai2c *i2c)
 {
 	int ret = 0;
-	unsigned long wait_result;
+	unsigned long time_left;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+	time_left = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
-	if (!wait_result)
+	if (!time_left)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
 
@@ -49,173 +49,173 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c->base + VIAI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK;
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(i2c->base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
+			writew(val, i2c->base + VIAI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
+					i2c->base + VIAI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c->base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= VIAI2C_CR_RX_END;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c->base + VIAI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= VIAI2C_CR_RX_END;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	return 0;
 }
 
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct viai2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = viai2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
 }
 
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
+static irqreturn_t viai2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct viai2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 {
 	int err;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
+					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index fcff8e4456eb..28799e7e97f0 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -11,48 +11,46 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_READ			BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+#define VIAI2C_TCR_ADDR_MASK		GENMASK(6, 0)
+
+/* REG_CSR Bit fields */
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
 
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
 
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -63,9 +61,9 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+int viai2c_wait_bus_not_busy(struct viai2c *i2c);
+int viai2c_check_status(struct viai2c *i2c);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 1a80f38d0b88..56602f248e1f 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -35,39 +35,39 @@ static u32 wmt_i2c_func(struct i2c_adapter *adap)
 }
 
 static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
+	.master_xfer	= viai2c_xfer,
 	.functionality	= wmt_i2c_func,
 };
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct viai2c *i2c)
 {
 	int err;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c->base + VIAI2C_REG_CR);
+	writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
+	readw(i2c->base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR);
 
 	return 0;
 }
@@ -75,34 +75,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = viai2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c->tcr = VIAI2C_TCR_FAST;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
@@ -113,12 +113,12 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 
 static void wmt_i2c_remove(struct platform_device *pdev)
 {
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct viai2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	writew(0, i2c->base + VIAI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.34.1


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

* [PATCH v8 4/6] i2c: wmt: fix a bug when thread blocked
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
                             ` (2 preceding siblings ...)
  2024-02-27  6:36           ` [PATCH v8 3/6] i2c: wmt: rename something Hans Hu
@ 2024-02-27  6:36           ` Hans Hu
  2024-03-04  9:41             ` Wolfram Sang
  2024-02-27  6:36           ` [PATCH v8 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
                             ` (2 subsequent siblings)
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-02-27  6:36 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu

During each byte access, the host performs clock stretching.

To reduce the host performs clock stretching, move most of
the per-msg processing to the interrupt context.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

---
 drivers/i2c/busses/i2c-viai2c-common.c | 139 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |   6 +-
 2 files changed, 73 insertions(+), 72 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 3e565d5ee4c7..30405205ba3a 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -18,37 +18,18 @@ int viai2c_wait_bus_not_busy(struct viai2c *i2c)
 	return 0;
 }
 
-int viai2c_check_status(struct viai2c *i2c)
-{
-	int ret = 0;
-	unsigned long time_left;
-
-	time_left = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!time_left)
-		return -ETIMEDOUT;
-
-	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
 static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 {
 	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	int xfer_len = 0;
+
+	i2c->last = last;
 
 	if (pmsg->len == 0) {
 		/*
 		 * We still need to run through the while (..) once, so
 		 * start at -1 and break out early from the loop
 		 */
-		xfer_len = -1;
+		i2c->xfered_len = -1;
 		writew(0, i2c->base + VIAI2C_REG_CDR);
 	} else {
 		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
@@ -73,43 +54,15 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	while (xfer_len < pmsg->len) {
-		ret = viai2c_check_status(i2c);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(i2c->base + VIAI2C_REG_CSR);
-		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
-			writew(val, i2c->base + VIAI2C_REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
-			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
-					i2c->base + VIAI2C_REG_CR);
-		}
-	}
+	if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+		return -ETIMEDOUT;
 
-	return 0;
+	return i2c->ret;
 }
 
 static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
 	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	u32 xfer_len = 0;
 
 	val = readw(i2c->base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
@@ -134,21 +87,10 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	while (xfer_len < pmsg->len) {
-		ret = viai2c_check_status(i2c);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= VIAI2C_CR_RX_END;
-		writew(val, i2c->base + VIAI2C_REG_CR);
-	}
+	if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+		return -ETIMEDOUT;
 
-	return 0;
+	return i2c->ret;
 }
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -166,6 +108,9 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 				return ret;
 		}
 
+		i2c->msg = pmsg;
+		i2c->xfered_len = 0;
+
 		if (pmsg->flags & I2C_M_RD)
 			ret = viai2c_read(i2c, pmsg);
 		else
@@ -175,15 +120,69 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	return (ret < 0) ? ret : i;
 }
 
+static int viai2c_irq_xfer(struct viai2c *i2c)
+{
+	u16 val;
+	struct i2c_msg *msg = i2c->msg;
+	u8 read = msg->flags & I2C_M_RD;
+	void __iomem *base = i2c->base;
+
+	if (read) {
+		msg->buf[i2c->xfered_len] = readw(base + VIAI2C_REG_CDR) >> 8;
+
+		val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
+		if (i2c->xfered_len == msg->len - 2)
+			val |= VIAI2C_CR_RX_END;
+		writew(val, base + VIAI2C_REG_CR);
+	} else {
+
+		val = readw(base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg_ratelimited(i2c->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (msg->len == 0) {
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
+			writew(val, base + VIAI2C_REG_CR);
+			return 0;
+		}
+
+		if ((i2c->xfered_len + 1) == msg->len) {
+			if (!i2c->last)
+				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+		} else {
+			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+		}
+	}
+
+	i2c->xfered_len++;
+
+	return i2c->xfered_len == msg->len;
+}
+
 static irqreturn_t viai2c_isr(int irq, void *data)
 {
 	struct viai2c *i2c = data;
+	u8 status;
 
 	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
+	status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(status, i2c->base + VIAI2C_REG_ISR);
+
+	i2c->ret = 0;
+	if (status & VIAI2C_ISR_NACK_ADDR)
+		i2c->ret = -EIO;
+
+	if (status & VIAI2C_ISR_SCL_TIMEOUT)
+		i2c->ret = -ETIMEDOUT;
+
+	if (!i2c->ret)
+		i2c->ret = viai2c_irq_xfer(i2c);
 
-	complete(&i2c->complete);
+	if (i2c->ret)
+		complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 28799e7e97f0..c92e054ac7e7 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -58,11 +58,13 @@ struct viai2c {
 	struct clk		*clk;
 	u16			tcr;
 	int			irq;
-	u16			cmd_status;
+	u16			xfered_len;
+	struct i2c_msg		*msg;
+	int			ret;
+	bool			last;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
-int viai2c_check_status(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
-- 
2.34.1


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

* [PATCH v8 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
                             ` (3 preceding siblings ...)
  2024-02-27  6:36           ` [PATCH v8 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2024-02-27  6:36           ` Hans Hu
  2024-03-04  9:46             ` Wolfram Sang
  2024-02-27  6:36           ` [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-02-27  6:36 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu

Enumeration variables are added to differentiate
between different platforms.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

---
 drivers/i2c/busses/i2c-viai2c-common.c | 33 ++++++++++++++++----------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 +++++-
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  2 +-
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 30405205ba3a..75663a3e3fe5 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -35,7 +35,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -48,7 +48,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -67,7 +67,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(i2c->base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -81,7 +81,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -102,7 +102,8 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if ((i2c->platform == VIAI2C_PLAT_WMT)
+		   && !(pmsg->flags & I2C_M_NOSTART)) {
 			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
@@ -149,7 +150,7 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 		}
 
 		if ((i2c->xfered_len + 1) == msg->len) {
-			if (!i2c->last)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
@@ -175,7 +176,7 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	if (status & VIAI2C_ISR_NACK_ADDR)
 		i2c->ret = -EIO;
 
-	if (status & VIAI2C_ISR_SCL_TIMEOUT)
+	if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
 		i2c->ret = -ETIMEDOUT;
 
 	if (!i2c->ret)
@@ -187,9 +188,10 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 {
 	int err;
+	int irq_flags;
 	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
@@ -201,12 +203,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 	if (IS_ERR(i2c->base))
 		return PTR_ERR(i2c->base);
 
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
+	if (plat == VIAI2C_PLAT_WMT) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else {
+		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
+	}
+
+	i2c->platform = plat;
 
 	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
-					0, pdev->name, i2c);
+					irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
 				"failed to request irq %i\n", i2c->irq);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index c92e054ac7e7..cfe5ab2bd779 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -50,6 +50,10 @@
 
 #define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
+enum {
+	VIAI2C_PLAT_WMT,
+};
+
 struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
@@ -62,10 +66,11 @@ struct viai2c {
 	struct i2c_msg		*msg;
 	int			ret;
 	bool			last;
+	unsigned int		platform;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 56602f248e1f..ba22fdc0f27c 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -80,7 +80,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = viai2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
 	if (err)
 		return err;
 
-- 
2.34.1


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

* [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
                             ` (4 preceding siblings ...)
  2024-02-27  6:36           ` [PATCH v8 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2024-02-27  6:36           ` Hans Hu
  2024-03-04  9:49             ` Wolfram Sang
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
  6 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-02-27  6:36 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the "IIC1D17" HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

---
 MAINTAINERS                             |   8 +
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c  |  31 ++-
 drivers/i2c/busses/i2c-viai2c-common.h  |   9 +
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 299 ++++++++++++++++++++++++
 6 files changed, 354 insertions(+), 5 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c

diff --git a/MAINTAINERS b/MAINTAINERS
index a73ccc8e89d0..afbd95a4f759 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10023,6 +10023,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-viai2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 28eb48dd5b32..6ccc9f858c90 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -336,6 +336,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 06ceb4775cbd..faeca9c41fc7 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 75663a3e3fe5..05b615144442 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -60,7 +60,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 	return i2c->ret;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 
@@ -81,7 +81,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART))
+	   || (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -100,6 +101,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	int ret = 0;
 	struct viai2c *i2c = i2c_get_adapdata(adap);
 
+	i2c->mode = VIAI2C_BYTE_MODE;
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if ((i2c->platform == VIAI2C_PLAT_WMT)
@@ -113,7 +115,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 		i2c->xfered_len = 0;
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
@@ -152,6 +154,8 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 		if ((i2c->xfered_len + 1) == msg->len) {
 			if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last)
+				writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
 		} else {
 			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
 			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
@@ -163,6 +167,11 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 	return i2c->xfered_len == msg->len;
 }
 
+int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
+{
+	return 0;
+}
+
 static irqreturn_t viai2c_isr(int irq, void *data)
 {
 	struct viai2c *i2c = data;
@@ -170,6 +179,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN)
+		return IRQ_NONE;
+
 	writew(status, i2c->base + VIAI2C_REG_ISR);
 
 	i2c->ret = 0;
@@ -179,8 +191,12 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
 		i2c->ret = -ETIMEDOUT;
 
-	if (!i2c->ret)
-		i2c->ret = viai2c_irq_xfer(i2c);
+	if (!i2c->ret) {
+		if (i2c->mode == VIAI2C_BYTE_MODE)
+			i2c->ret = viai2c_irq_xfer(i2c);
+		else
+			i2c->ret = viai2c_fifo_irq_xfer(i2c, true);
+	}
 
 	if (i2c->ret)
 		complete(&i2c->complete);
@@ -208,6 +224,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 		i2c->irq = irq_of_parse_and_map(np, 0);
 		if (!i2c->irq)
 			return -EINVAL;
+	} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	} else {
 		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
 	}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index cfe5ab2bd779..81e827c54434 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -52,6 +52,12 @@
 
 enum {
 	VIAI2C_PLAT_WMT,
+	VIAI2C_PLAT_ZHAOXIN
+};
+
+enum {
+	VIAI2C_BYTE_MODE,
+	VIAI2C_FIFO_MODE
 };
 
 struct viai2c {
@@ -66,11 +72,14 @@ struct viai2c {
 	struct i2c_msg		*msg;
 	int			ret;
 	bool			last;
+	unsigned int		mode;
 	unsigned int		platform;
+	void			*pltfm_priv;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
+int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
new file mode 100644
index 000000000000..99db93caa4cb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include "i2c-viai2c-common.h"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+
+#define ZXI2C_FIFO_SIZE		32
+
+struct viai2c_zhaoxin {
+	u8			hrv;
+	u16			tr;
+	u16			mcr;
+	u16			xfer_len;
+};
+
+/* 'irq == true' means in interrupt context */
+int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
+{
+	u16 i;
+	u8 tmp;
+	struct i2c_msg *msg = i2c->msg;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	if (irq) {
+		/* get the received data */
+		if (read)
+			for (i = 0; i < priv->xfer_len; i++)
+				msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR);
+
+		i2c->xfered_len += priv->xfer_len;
+		if (i2c->xfered_len == msg->len)
+			return 1;
+	}
+
+	/* reset fifo buffer */
+	tmp = ioread8(base + ZXI2C_REG_HCR);
+	iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+	/* set xfer len */
+	priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE);
+	if (read) {
+		iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR);
+	} else {
+		iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR);
+		/* set write data */
+		for (i = 0; i < priv->xfer_len; i++)
+			iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR);
+	}
+
+	/* prepare to stop transmission */
+	if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) {
+		tmp = ioread8(base + VIAI2C_REG_CR);
+		tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+		iowrite8(tmp, base + VIAI2C_REG_CR);
+	}
+
+	if (irq) {
+		/* continue transmission */
+		tmp = ioread8(base + VIAI2C_REG_CR);
+		iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
+	} else {
+		u16 tcr_val = i2c->tcr;
+
+		/* start transmission */
+		tcr_val |= read ? VIAI2C_TCR_READ : 0;
+		writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+	}
+
+	return 0;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap);
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+	void __iomem *base = i2c->base;
+
+	ret = viai2c_wait_bus_not_busy(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 && (priv->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR);
+
+		i2c->msg = msgs;
+		i2c->mode = VIAI2C_FIFO_MODE;
+		priv->xfer_len = i2c->xfered_len = 0;
+
+		viai2c_fifo_irq_xfer(i2c, 0);
+
+		if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+			return -ETIMEDOUT;
+
+		ret = i2c->ret;
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret == -ETIMEDOUT)
+			iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR);
+	}
+	/* dis interrupt */
+	iowrite8(0, base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct viai2c *i2c)
+{
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	iowrite16(priv->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(priv->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct viai2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
+				params[0], fstp, params[2]);
+		priv->tr = params[2] | 0xff00;
+	} else {
+		priv->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	priv->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0x80 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		priv->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct viai2c *i2c;
+	struct i2c_adapter *adap;
+	struct viai2c_zhaoxin *priv;
+
+	error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
+	if (error)
+		return error;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	i2c->pltfm_priv = priv;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	priv->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
+			dev_name(pdev->dev.parent), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int __maybe_unused zxi2c_resume(struct device *dev)
+{
+	struct viai2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = "i2c_zhaoxin",
+		.acpi_match_table = zxi2c_acpi_match,
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* Re: [PATCH v8 4/6] i2c: wmt: fix a bug when thread blocked
  2024-02-27  6:36           ` [PATCH v8 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2024-03-04  9:41             ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2024-03-04  9:41 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen, hanshu

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

On Tue, Feb 27, 2024 at 02:36:31PM +0800, Hans Hu wrote:
> During each byte access, the host performs clock stretching.
> 
> To reduce the host performs clock stretching, move most of
> the per-msg processing to the interrupt context.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

I don't have the HW, so I can't review on register level. From a high
level point of view, it matches my suggestion and looks good (one nit):

Suggested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>

> +		val = readw(base + VIAI2C_REG_CSR);
> +		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
> +			dev_dbg_ratelimited(i2c->dev, "write RCV NACK error\n");

Even as a debug message, I think this should go. If NACK really is a
problem depends on the client, so the error and messaging should not be
handled at bus level.


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v8 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2024-02-27  6:36           ` [PATCH v8 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2024-03-04  9:46             ` Wolfram Sang
  0 siblings, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2024-03-04  9:46 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen, hanshu

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

On Tue, Feb 27, 2024 at 02:36:32PM +0800, Hans Hu wrote:
> Enumeration variables are added to differentiate
> between different platforms.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Just glimpsed it, looks OK:

Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver
  2024-02-27  6:36           ` [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2024-03-04  9:49             ` Wolfram Sang
  2024-03-04 23:01               ` [SPAM] " Andi Shyti
  0 siblings, 1 reply; 133+ messages in thread
From: Wolfram Sang @ 2024-03-04  9:49 UTC (permalink / raw)
  To: Hans Hu; +Cc: andi.shyti, linux-i2c, cobechen, hanshu

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

On Tue, Feb 27, 2024 at 02:36:33PM +0800, Hans Hu wrote:
> Add Zhaoxin I2C controller driver. It provides the access to the i2c
> busses, which connects to the touchpad, eeprom, I2S, etc.
> 
> Zhaoxin I2C controller has two separate busses, so may accommodate up
> to two I2C adapters. Those adapters are listed in the ACPI namespace
> with the "IIC1D17" HID, and probed by a platform driver.
> 
> The driver works with IRQ mode, and supports basic I2C features. Flags
> I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
> the unsupported access.
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Can't really say anything about the ACPI handling. Looks mostly good
for my eyes.

> +		/*
> +		 * if BIOS setting value far from golden value,
> +		 * use golden value and warn user
> +		 */
> +		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
> +				params[0], fstp, params[2]);

Well, if you want to warn the user, the string should be more
descriptive. Maybe "FW settings might cause wrong timings" or whatever
these values mean. I don't know.

The issues I mentioned could be resolved incrementally from my point of
view. Or with a new series. I don't mind. So, in general:

Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [SPAM] Re: [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver
  2024-03-04  9:49             ` Wolfram Sang
@ 2024-03-04 23:01               ` Andi Shyti
  2024-03-05  2:45                 ` Hans Hu
  0 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-03-04 23:01 UTC (permalink / raw)
  To: Wolfram Sang, Hans Hu, linux-i2c, cobechen, hanshu

Hi Hans,

...

> > +		/*
> > +		 * if BIOS setting value far from golden value,
> > +		 * use golden value and warn user
> > +		 */
> > +		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
> > +				params[0], fstp, params[2]);
> 
> Well, if you want to warn the user, the string should be more
> descriptive. Maybe "FW settings might cause wrong timings" or whatever
> these values mean. I don't know.
> 
> The issues I mentioned could be resolved incrementally from my point of
> view. Or with a new series. I don't mind. So, in general:

Same goes for few minor checkpatch warnings.

I will accept incremental patches to fix them... they are mainly
allignment issues.

Thanks,
Andi

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

* Re: [SPAM] Re: [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver
  2024-03-04 23:01               ` [SPAM] " Andi Shyti
@ 2024-03-05  2:45                 ` Hans Hu
  2024-03-06 11:50                   ` Andi Shyti
  2024-03-06 16:54                   ` Wolfram Sang
  0 siblings, 2 replies; 133+ messages in thread
From: Hans Hu @ 2024-03-05  2:45 UTC (permalink / raw)
  To: Andi Shyti, Wolfram Sang, linux-i2c, cobechen, hanshu

Hi Wolfram and Andi,


>>> +           /*
>>> +            * if BIOS setting value far from golden value,
>>> +            * use golden value and warn user
>>> +            */
>>> +           dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
>>> +                           params[0], fstp, params[2]);
>> Well, if you want to warn the user, the string should be more
>> descriptive. Maybe "FW settings might cause wrong timings" or whatever
>> these values mean. I don't know.
>>
>> The issues I mentioned could be resolved incrementally from my point of
>> view. Or with a new series. I don't mind. So, in general:
> Same goes for few minor checkpatch warnings.
>
> I will accept incremental patches to fix them... they are mainly
> allignment issues.
>

OK, the issues you mentioned will be fixed with a new series.
For the current series patch, do I need to push it to the latest
for-next branch? Or will you push it?

Thanks,
Hans


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

* Re: [SPAM] Re: [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver
  2024-03-05  2:45                 ` Hans Hu
@ 2024-03-06 11:50                   ` Andi Shyti
  2024-03-06 16:54                   ` Wolfram Sang
  1 sibling, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 11:50 UTC (permalink / raw)
  To: Hans Hu; +Cc: Wolfram Sang, linux-i2c, cobechen, hanshu

Hi Hans,

> > > > +           /*
> > > > +            * if BIOS setting value far from golden value,
> > > > +            * use golden value and warn user
> > > > +            */
> > > > +           dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
> > > > +                           params[0], fstp, params[2]);
> > > Well, if you want to warn the user, the string should be more
> > > descriptive. Maybe "FW settings might cause wrong timings" or whatever
> > > these values mean. I don't know.
> > > 
> > > The issues I mentioned could be resolved incrementally from my point of
> > > view. Or with a new series. I don't mind. So, in general:
> > Same goes for few minor checkpatch warnings.
> > 
> > I will accept incremental patches to fix them... they are mainly
> > allignment issues.
> > 
> 
> OK, the issues you mentioned will be fixed with a new series.

Thanks! Looking forward to receiving your new patches.

> For the current series patch, do I need to push it to the latest
> for-next branch? Or will you push it?

I believe you can't push it :-)

I am taking care of it!

Andi

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

* Re: [SPAM] Re: [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver
  2024-03-05  2:45                 ` Hans Hu
  2024-03-06 11:50                   ` Andi Shyti
@ 2024-03-06 16:54                   ` Wolfram Sang
  1 sibling, 0 replies; 133+ messages in thread
From: Wolfram Sang @ 2024-03-06 16:54 UTC (permalink / raw)
  To: Hans Hu; +Cc: Andi Shyti, linux-i2c, cobechen, hanshu

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

Hi,

> OK, the issues you mentioned will be fixed with a new series.

If you do this new series, please make sure you rebase it on top of
Andi's for-next tree. He just applied a fix for wmt, namely:

"[PATCH] i2c: wmt: Fix an error handling path in wmt_i2c_probe()"

Your new series should be on top of this patch to avoid merge conflicts.

Happy hacking,

   Wolfram


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* [PATCH v9 0/6] i2c: add zhaoxin i2c controller driver
  2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
                             ` (5 preceding siblings ...)
  2024-02-27  6:36           ` [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2024-03-06 21:24           ` Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 1/6] i2c: wmt: create wmt_i2c_init for general init Andi Shyti
                               ` (7 more replies)
  6 siblings, 8 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 21:24 UTC (permalink / raw)
  To: Hans Hu, linux-i2c; +Cc: wsa, cobechen, hanshu, Andi Shyti

Hi Hans,

no functional change here, just fixed a rebase conflict. Patch
78c1dbed3652 ("i2c: wmt: Fix an error handling path in
wmt_i2c_probe()") from Christophe Jaillet is a fix that has
created some conflict with your series.

My work here is just to adapt your series to this change.

Check the changelog for more details. The little adaptation are
limited to patch 1, 2 and 3. The other patches don't have any
change.

The series has been applied in i2c/i2c-host-next[*].

Thanks,
Andi

PS I was almost tempted to fix the checkpatch notes, but we have
a deal on that ;-)

PPS I'm keeping your e-mail structure and sending the series as
reply to your PATCH 0 of v8.

[*] git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git

v8->v9:
	* In Patch 1 in probe() do not return at the
	  i2c_add_adapter(), but call clk_disable_unprepare()
	  in case of failure.
	* In Patch 2 fix the conflict when i2c-wmt.c is removed.
	* In Patch 2 in wmt_i2c_probe() function, call
	  clk_disable_unprepare() in case of failure. While at
	  it, add a comment to explain the reason.
	* When renaming i2c_dev to i2c, change also the reference
	  in clk_disable_unprepare().
v7->v8:
        * move per-msg handling to interrupt context
        * add private struct viai2c_zhaoxin to handle zhaoxin specific things
        * fixed some other formatting issues
        Link: https://lore.kernel.org/all/cover.1704440251.git.hanshu-oc@zhaoxin.com/

v6->v7:
        * adjust the patch sequence
        * put those renaming related patches in 1 patch file
        * rename i2c-*-plt.c to i2c-viai2c-*.c
        * Some other adjustments suggested by Andi
        For more details, see the comment in each patch please.
        Link: https://lore.kernel.org/all/cover.1703830854.git.hanshu-oc@zhaoxin.com/

v5->v6:
        * fix build warnning reported by kernel test robot.
          Link: https://lore.kernel.org/all/202312291225.cWVt6YF9-lkp@intel.com/
        Link: https://lore.kernel.org/all/cover.1703733126.git.hanshu-oc@zhaoxin.com/

v4->v5:
        * fix 1 build error.
          Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
        Link: https://lore.kernel.org/all/cover.1703647471.git.hanshu-oc@zhaoxin.com/

v3->v4:
        * Some adjustments as suggested by Wolfram.
        * rebase patch on top of for-next branch.
        Link: https://lore.kernel.org/all/cover.1698889581.git.hanshu-oc@zhaoxin.com/

v2->v3:
        * Split the number of patches from 2 to 12. Make it easier to review.
        Link: https://lore.kernel.org/all/cover.1691999569.git.hanshu-oc@zhaoxin.com/

v1->v2:
        * Fixed some bugs I found myself.
        Link: https://lore.kernel.org/all/cover.1691030850.git.hanshu-oc@zhaoxin.com/

Old version:
        This patch has already gone through a round of reviews.
        Compared with the first round, the main difference of this
        round of patch is the use of i2c-wmt driver.
        Link: https://lore.kernel.org/all/20230614094858.317652-1-hanshu-oc@zhaoxin.com/

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Hans Hu (6):
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: split out common files
  i2c: wmt: rename something
  i2c: wmt: fix a bug when thread blocked
  i2c: wmt: add platform type VIAI2C_PLAT_WMT
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                             |  10 +-
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   3 +
 drivers/i2c/busses/i2c-viai2c-common.c  | 250 ++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h  |  85 +++++
 drivers/i2c/busses/i2c-viai2c-wmt.c     | 148 +++++++++
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 299 +++++++++++++++++
 drivers/i2c/busses/i2c-wmt.c            | 421 ------------------------
 8 files changed, 804 insertions(+), 422 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

-- 
2.43.0


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

* [PATCH v9 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
@ 2024-03-06 21:24             ` Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 2/6] i2c: wmt: split out common files Andi Shyti
                               ` (6 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 21:24 UTC (permalink / raw)
  To: Hans Hu, linux-i2c; +Cc: wsa, cobechen, hanshu, Andi Shyti

From: Hans Hu <hanshu-oc@zhaoxin.com>

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
---
 drivers/i2c/busses/i2c-wmt.c | 61 +++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 26 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 198afee5233c3..ec9d9eb888e0c 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -351,15 +373,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,8 +381,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
@@ -380,8 +391,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (err)
 		goto err_disable_clk;
 
-	platform_set_drvdata(pdev, i2c_dev);
-
 	return 0;
 
 err_disable_clk:
-- 
2.43.0


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

* [PATCH v9 2/6] i2c: wmt: split out common files
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 1/6] i2c: wmt: create wmt_i2c_init for general init Andi Shyti
@ 2024-03-06 21:24             ` Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 3/6] i2c: wmt: rename something Andi Shyti
                               ` (5 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 21:24 UTC (permalink / raw)
  To: Hans Hu, linux-i2c; +Cc: wsa, cobechen, hanshu, Andi Shyti

From: Hans Hu <hanshu-oc@zhaoxin.com>

Since the I2C IP of both wmt and zhaoxin originates from VIA,
it is better to separate the common code first.
The common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-viai2c-wmt.c.

The MAINTAINERS file will be updated accordingly in upcoming commits.

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
---
 MAINTAINERS                            |   2 +-
 drivers/i2c/busses/Makefile            |   1 +
 drivers/i2c/busses/i2c-viai2c-common.c | 221 +++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  71 ++++
 drivers/i2c/busses/i2c-viai2c-wmt.c    | 148 +++++++++
 drivers/i2c/busses/i2c-wmt.c           | 430 -------------------------
 6 files changed, 442 insertions(+), 431 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 960512bec4288..b1bb0feb0d33e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2993,7 +2993,7 @@ S:	Orphan
 F:	Documentation/devicetree/bindings/i2c/i2c-wmt.txt
 F:	arch/arm/mach-vt8500/
 F:	drivers/clocksource/timer-vt8500.c
-F:	drivers/i2c/busses/i2c-wmt.c
+F:	drivers/i2c/busses/i2c-viai2c-wmt.c
 F:	drivers/mmc/host/wmt-sdmmc.c
 F:	drivers/pwm/pwm-vt8500.c
 F:	drivers/rtc/rtc-vt8500.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index aa0ee8ecd6f2f..63c7bbad8134f 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 0000000000000..fa47a4d9549c0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+{
+	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+						msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+		ret = -EIO;
+
+	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	int xfer_len = 0;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, i2c_dev->base + REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(i2c_dev->base + REG_CR);
+		val &= ~CR_TX_END;
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CSR);
+		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
+			writew(val, i2c_dev->base + REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (last != 1)
+				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
+								REG_CDR);
+			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	u32 xfer_len = 0;
+
+	val = readw(i2c_dev->base + REG_CR);
+	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= CR_TX_NEXT_NO_ACK;
+
+	writew(val, i2c_dev->base + REG_CR);
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	return 0;
+}
+
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = wmt_i2c_read(i2c_dev, pmsg);
+		else
+			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+	struct wmt_i2c_dev *i2c_dev = data;
+
+	/* save the status and write-clear it */
+	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+
+	complete(&i2c_dev->complete);
+
+	return IRQ_HANDLED;
+}
+
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+					0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 0000000000000..fcff8e4456eb8
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define REG_CR		0x00
+#define REG_TCR		0x02
+#define REG_CSR		0x04
+#define REG_ISR		0x06
+#define REG_IMR		0x08
+#define REG_CDR		0x0A
+#define REG_TR		0x0C
+#define REG_MCR		0x0E
+
+/* REG_CR Bit fields */
+#define CR_TX_NEXT_ACK		0x0000
+#define CR_ENABLE		0x0001
+#define CR_TX_NEXT_NO_ACK	0x0002
+#define CR_TX_END		0x0004
+#define CR_CPU_RDY		0x0008
+#define SLAV_MODE_SEL		0x8000
+
+/* REG_TCR Bit fields */
+#define TCR_STANDARD_MODE	0x0000
+#define TCR_MASTER_WRITE	0x0000
+#define TCR_HS_MODE		0x2000
+#define TCR_MASTER_READ		0x4000
+#define TCR_FAST_MODE		0x8000
+#define TCR_SLAVE_ADDR_MASK	0x007F
+
+/* REG_ISR Bit fields */
+#define ISR_NACK_ADDR		0x0001
+#define ISR_BYTE_END		0x0002
+#define ISR_SCL_TIMEOUT		0x0004
+#define ISR_WRITE_ALL		0x0007
+
+/* REG_IMR Bit fields */
+#define IMR_ENABLE_ALL		0x0007
+
+/* REG_CSR Bit fields */
+#define CSR_RCV_NOT_ACK		0x0001
+#define CSR_RCV_ACK_MASK	0x0001
+#define CSR_READY_MASK		0x0002
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+struct wmt_i2c_dev {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+};
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
new file mode 100644
index 0000000000000..0af0009eab8fe
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+#define REG_SLAVE_CR	0x10
+#define REG_SLAVE_SR	0x12
+#define REG_SLAVE_ISR	0x14
+#define REG_SLAVE_IMR	0x16
+#define REG_SLAVE_DR	0x18
+#define REG_SLAVE_TR	0x1A
+
+/* REG_TR */
+#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define TR_STD			0x0064
+#define TR_HS			0x0019
+
+/* REG_MCR */
+#define MCR_APB_96M		7
+#define MCR_APB_166M		12
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= wmt_i2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+{
+	int err;
+
+	err = clk_prepare_enable(i2c_dev->clk);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c_dev->clk, 20000000);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c_dev->clk);
+		return err;
+	}
+
+	writew(0, i2c_dev->base + REG_CR);
+	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
+	writew(CR_ENABLE, i2c_dev->base + REG_CR);
+	readw(i2c_dev->base + REG_CSR);		/* read clear */
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+
+	if (i2c_dev->tcr == TCR_FAST_MODE)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	else
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c_dev *i2c_dev;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
+
+	i2c_dev->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c_dev->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c_dev->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+		i2c_dev->tcr = TCR_FAST_MODE;
+
+	adap = &i2c_dev->adapter;
+	i2c_set_adapdata(adap, i2c_dev);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c_dev);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	err = i2c_add_adapter(adap);
+	if (err)
+		/* wmt_i2c_reset_hardware() enables i2c_dev->clk */
+		clk_disable_unprepare(i2c_dev->clk);
+
+	return err;
+}
+
+static void wmt_i2c_remove(struct platform_device *pdev)
+{
+	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	/* Disable interrupts, clock and delete adapter */
+	writew(0, i2c_dev->base + REG_IMR);
+	clk_disable_unprepare(i2c_dev->clk);
+	i2c_del_adapter(&i2c_dev->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.remove_new	= wmt_i2c_remove,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index ec9d9eb888e0c..0000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,430 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
-
-/* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c_dev {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
-{
-	unsigned long timeout;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-						msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	int xfer_len = 0;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	u32 xfer_len = 0;
-
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
-
-	writew(val, i2c_dev->base + REG_CR);
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
-		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c_dev *i2c_dev = data;
-
-	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
-
-	complete(&i2c_dev->complete);
-
-	return IRQ_HANDLED;
-}
-
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
-{
-	int err;
-	struct wmt_i2c_dev *i2c_dev;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
-		return -EINVAL;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
-
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
-
-	*pi2c_dev = i2c_dev;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
-{
-	int err;
-
-	err = clk_prepare_enable(i2c_dev->clk);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c_dev->clk, 20000000);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
-		return err;
-	}
-
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
-	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c_dev);
-	if (err)
-		return err;
-
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
-
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	err = i2c_add_adapter(adap);
-	if (err)
-		goto err_disable_clk;
-
-	return 0;
-
-err_disable_clk:
-	clk_disable_unprepare(i2c_dev->clk);
-	return err;
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.43.0


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

* [PATCH v9 3/6] i2c: wmt: rename something
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 1/6] i2c: wmt: create wmt_i2c_init for general init Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 2/6] i2c: wmt: split out common files Andi Shyti
@ 2024-03-06 21:24             ` Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 4/6] i2c: wmt: fix a bug when thread blocked Andi Shyti
                               ` (4 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 21:24 UTC (permalink / raw)
  To: Hans Hu, linux-i2c; +Cc: wsa, cobechen, hanshu, Andi Shyti

From: Hans Hu <hanshu-oc@zhaoxin.com>

1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename
   common registers, functions, and variable names to follow the
   VIAI2C_ and viai2c_ naming conventions for consistency and clarity.
2. rename i2c_dev to i2c, to shorten the length of a line.
3. rename wait_result to time_left, make it better to reflect the meaning
   of the value returned by wait_for_completion_timeout().
4. remove TCR_MASTER_WRITE, its value is 0.

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 156 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |  70 ++++++-----
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  62 +++++-----
 3 files changed, 143 insertions(+), 145 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index fa47a4d9549c0..3e565d5ee4c7c 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,14 +2,14 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+int viai2c_wait_bus_not_busy(struct viai2c *i2c)
 {
 	unsigned long timeout;
 
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	timeout = jiffies + VIAI2C_TIMEOUT;
+	while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -18,28 +18,28 @@ int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+int viai2c_check_status(struct viai2c *i2c)
 {
 	int ret = 0;
-	unsigned long wait_result;
+	unsigned long time_left;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+	time_left = wait_for_completion_timeout(&i2c->complete,
 						msecs_to_jiffies(500));
-	if (!wait_result)
+	if (!time_left)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
 
@@ -49,173 +49,173 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c->base + VIAI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK;
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(i2c->base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
+			writew(val, i2c->base + VIAI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
+					i2c->base + VIAI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c->base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= VIAI2C_CR_RX_END;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c->base + VIAI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= VIAI2C_CR_RX_END;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	return 0;
 }
 
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct viai2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = viai2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
 }
 
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
+static irqreturn_t viai2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct viai2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 {
 	int err;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-					0, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
+					0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index fcff8e4456eb8..28799e7e97f0b 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -11,48 +11,46 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_READ			BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+#define VIAI2C_TCR_ADDR_MASK		GENMASK(6, 0)
+
+/* REG_CSR Bit fields */
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
 
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
 
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -63,9 +61,9 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+int viai2c_wait_bus_not_busy(struct viai2c *i2c);
+int viai2c_check_status(struct viai2c *i2c);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 0af0009eab8fe..07fd954f1d008 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -35,39 +35,39 @@ static u32 wmt_i2c_func(struct i2c_adapter *adap)
 }
 
 static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
+	.master_xfer	= viai2c_xfer,
 	.functionality	= wmt_i2c_func,
 };
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct viai2c *i2c)
 {
 	int err;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c->base + VIAI2C_REG_CR);
+	writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
+	readw(i2c->base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR);
 
 	return 0;
 }
@@ -75,34 +75,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = viai2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c->tcr = VIAI2C_TCR_FAST;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
@@ -111,19 +111,19 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	err = i2c_add_adapter(adap);
 	if (err)
 		/* wmt_i2c_reset_hardware() enables i2c_dev->clk */
-		clk_disable_unprepare(i2c_dev->clk);
+		clk_disable_unprepare(i2c->clk);
 
 	return err;
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
 {
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct viai2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	writew(0, i2c->base + VIAI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.43.0


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

* [PATCH v9 4/6] i2c: wmt: fix a bug when thread blocked
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
                               ` (2 preceding siblings ...)
  2024-03-06 21:24             ` [PATCH v9 3/6] i2c: wmt: rename something Andi Shyti
@ 2024-03-06 21:24             ` Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Andi Shyti
                               ` (3 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 21:24 UTC (permalink / raw)
  To: Hans Hu, linux-i2c; +Cc: wsa, cobechen, hanshu, Andi Shyti

From: Hans Hu <hanshu-oc@zhaoxin.com>

During each byte access, the host performs clock stretching.

To reduce the host performs clock stretching, move most of
the per-msg processing to the interrupt context.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
Suggested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 139 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |   6 +-
 2 files changed, 73 insertions(+), 72 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 3e565d5ee4c7c..30405205ba3a0 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -18,37 +18,18 @@ int viai2c_wait_bus_not_busy(struct viai2c *i2c)
 	return 0;
 }
 
-int viai2c_check_status(struct viai2c *i2c)
-{
-	int ret = 0;
-	unsigned long time_left;
-
-	time_left = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!time_left)
-		return -ETIMEDOUT;
-
-	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
 static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 {
 	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	int xfer_len = 0;
+
+	i2c->last = last;
 
 	if (pmsg->len == 0) {
 		/*
 		 * We still need to run through the while (..) once, so
 		 * start at -1 and break out early from the loop
 		 */
-		xfer_len = -1;
+		i2c->xfered_len = -1;
 		writew(0, i2c->base + VIAI2C_REG_CDR);
 	} else {
 		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
@@ -73,43 +54,15 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	while (xfer_len < pmsg->len) {
-		ret = viai2c_check_status(i2c);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(i2c->base + VIAI2C_REG_CSR);
-		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
-			writew(val, i2c->base + VIAI2C_REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
-			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE,
-					i2c->base + VIAI2C_REG_CR);
-		}
-	}
+	if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+		return -ETIMEDOUT;
 
-	return 0;
+	return i2c->ret;
 }
 
 static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
 	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	u32 xfer_len = 0;
 
 	val = readw(i2c->base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
@@ -134,21 +87,10 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	while (xfer_len < pmsg->len) {
-		ret = viai2c_check_status(i2c);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= VIAI2C_CR_RX_END;
-		writew(val, i2c->base + VIAI2C_REG_CR);
-	}
+	if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+		return -ETIMEDOUT;
 
-	return 0;
+	return i2c->ret;
 }
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -166,6 +108,9 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 				return ret;
 		}
 
+		i2c->msg = pmsg;
+		i2c->xfered_len = 0;
+
 		if (pmsg->flags & I2C_M_RD)
 			ret = viai2c_read(i2c, pmsg);
 		else
@@ -175,15 +120,69 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	return (ret < 0) ? ret : i;
 }
 
+static int viai2c_irq_xfer(struct viai2c *i2c)
+{
+	u16 val;
+	struct i2c_msg *msg = i2c->msg;
+	u8 read = msg->flags & I2C_M_RD;
+	void __iomem *base = i2c->base;
+
+	if (read) {
+		msg->buf[i2c->xfered_len] = readw(base + VIAI2C_REG_CDR) >> 8;
+
+		val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
+		if (i2c->xfered_len == msg->len - 2)
+			val |= VIAI2C_CR_RX_END;
+		writew(val, base + VIAI2C_REG_CR);
+	} else {
+
+		val = readw(base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg_ratelimited(i2c->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (msg->len == 0) {
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
+			writew(val, base + VIAI2C_REG_CR);
+			return 0;
+		}
+
+		if ((i2c->xfered_len + 1) == msg->len) {
+			if (!i2c->last)
+				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+		} else {
+			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+		}
+	}
+
+	i2c->xfered_len++;
+
+	return i2c->xfered_len == msg->len;
+}
+
 static irqreturn_t viai2c_isr(int irq, void *data)
 {
 	struct viai2c *i2c = data;
+	u8 status;
 
 	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
+	status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(status, i2c->base + VIAI2C_REG_ISR);
+
+	i2c->ret = 0;
+	if (status & VIAI2C_ISR_NACK_ADDR)
+		i2c->ret = -EIO;
+
+	if (status & VIAI2C_ISR_SCL_TIMEOUT)
+		i2c->ret = -ETIMEDOUT;
+
+	if (!i2c->ret)
+		i2c->ret = viai2c_irq_xfer(i2c);
 
-	complete(&i2c->complete);
+	if (i2c->ret)
+		complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 28799e7e97f0b..c92e054ac7e73 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -58,11 +58,13 @@ struct viai2c {
 	struct clk		*clk;
 	u16			tcr;
 	int			irq;
-	u16			cmd_status;
+	u16			xfered_len;
+	struct i2c_msg		*msg;
+	int			ret;
+	bool			last;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
-int viai2c_check_status(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
-- 
2.43.0


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

* [PATCH v9 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
                               ` (3 preceding siblings ...)
  2024-03-06 21:24             ` [PATCH v9 4/6] i2c: wmt: fix a bug when thread blocked Andi Shyti
@ 2024-03-06 21:24             ` Andi Shyti
  2024-03-06 21:24             ` [PATCH v9 6/6] i2c: add zhaoxin i2c controller driver Andi Shyti
                               ` (2 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 21:24 UTC (permalink / raw)
  To: Hans Hu, linux-i2c; +Cc: wsa, cobechen, hanshu, Andi Shyti

From: Hans Hu <hanshu-oc@zhaoxin.com>

Enumeration variables are added to differentiate
between different platforms.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 33 ++++++++++++++++----------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 +++++-
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  2 +-
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 30405205ba3a0..75663a3e3fe57 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -35,7 +35,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -48,7 +48,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -67,7 +67,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(i2c->base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -81,7 +81,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -102,7 +102,8 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if ((i2c->platform == VIAI2C_PLAT_WMT)
+		   && !(pmsg->flags & I2C_M_NOSTART)) {
 			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
@@ -149,7 +150,7 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 		}
 
 		if ((i2c->xfered_len + 1) == msg->len) {
-			if (!i2c->last)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
@@ -175,7 +176,7 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	if (status & VIAI2C_ISR_NACK_ADDR)
 		i2c->ret = -EIO;
 
-	if (status & VIAI2C_ISR_SCL_TIMEOUT)
+	if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
 		i2c->ret = -ETIMEDOUT;
 
 	if (!i2c->ret)
@@ -187,9 +188,10 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 {
 	int err;
+	int irq_flags;
 	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
@@ -201,12 +203,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 	if (IS_ERR(i2c->base))
 		return PTR_ERR(i2c->base);
 
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
+	if (plat == VIAI2C_PLAT_WMT) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else {
+		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
+	}
+
+	i2c->platform = plat;
 
 	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
-					0, pdev->name, i2c);
+					irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
 				"failed to request irq %i\n", i2c->irq);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index c92e054ac7e73..cfe5ab2bd7792 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -50,6 +50,10 @@
 
 #define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
+enum {
+	VIAI2C_PLAT_WMT,
+};
+
 struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
@@ -62,10 +66,11 @@ struct viai2c {
 	struct i2c_msg		*msg;
 	int			ret;
 	bool			last;
+	unsigned int		platform;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 07fd954f1d008..aa6c34a78b1e4 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -80,7 +80,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = viai2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
 	if (err)
 		return err;
 
-- 
2.43.0


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

* [PATCH v9 6/6] i2c: add zhaoxin i2c controller driver
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
                               ` (4 preceding siblings ...)
  2024-03-06 21:24             ` [PATCH v9 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Andi Shyti
@ 2024-03-06 21:24             ` Andi Shyti
  2024-03-08  1:22             ` [PATCH v9 0/6] " Hans Hu
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
  7 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-06 21:24 UTC (permalink / raw)
  To: Hans Hu, linux-i2c; +Cc: wsa, cobechen, hanshu, Andi Shyti

From: Hans Hu <hanshu-oc@zhaoxin.com>

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the "IIC1D17" HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
---
 MAINTAINERS                             |   8 +
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c  |  31 ++-
 drivers/i2c/busses/i2c-viai2c-common.h  |   9 +
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 299 ++++++++++++++++++++++++
 6 files changed, 354 insertions(+), 5 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c

diff --git a/MAINTAINERS b/MAINTAINERS
index b1bb0feb0d33e..00c003c86e991 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10158,6 +10158,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-viai2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 97989c914260f..cc781f8ec7141 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -336,6 +336,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 63c7bbad8134f..3d65934f5eb48 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 75663a3e3fe57..05b6151444420 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -60,7 +60,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 	return i2c->ret;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 
@@ -81,7 +81,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART))
+	   || (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -100,6 +101,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	int ret = 0;
 	struct viai2c *i2c = i2c_get_adapdata(adap);
 
+	i2c->mode = VIAI2C_BYTE_MODE;
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if ((i2c->platform == VIAI2C_PLAT_WMT)
@@ -113,7 +115,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 		i2c->xfered_len = 0;
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
@@ -152,6 +154,8 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 		if ((i2c->xfered_len + 1) == msg->len) {
 			if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last)
+				writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
 		} else {
 			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
 			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
@@ -163,6 +167,11 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 	return i2c->xfered_len == msg->len;
 }
 
+int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
+{
+	return 0;
+}
+
 static irqreturn_t viai2c_isr(int irq, void *data)
 {
 	struct viai2c *i2c = data;
@@ -170,6 +179,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN)
+		return IRQ_NONE;
+
 	writew(status, i2c->base + VIAI2C_REG_ISR);
 
 	i2c->ret = 0;
@@ -179,8 +191,12 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
 		i2c->ret = -ETIMEDOUT;
 
-	if (!i2c->ret)
-		i2c->ret = viai2c_irq_xfer(i2c);
+	if (!i2c->ret) {
+		if (i2c->mode == VIAI2C_BYTE_MODE)
+			i2c->ret = viai2c_irq_xfer(i2c);
+		else
+			i2c->ret = viai2c_fifo_irq_xfer(i2c, true);
+	}
 
 	if (i2c->ret)
 		complete(&i2c->complete);
@@ -208,6 +224,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 		i2c->irq = irq_of_parse_and_map(np, 0);
 		if (!i2c->irq)
 			return -EINVAL;
+	} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	} else {
 		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
 	}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index cfe5ab2bd7792..81e827c544347 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -52,6 +52,12 @@
 
 enum {
 	VIAI2C_PLAT_WMT,
+	VIAI2C_PLAT_ZHAOXIN
+};
+
+enum {
+	VIAI2C_BYTE_MODE,
+	VIAI2C_FIFO_MODE
 };
 
 struct viai2c {
@@ -66,11 +72,14 @@ struct viai2c {
 	struct i2c_msg		*msg;
 	int			ret;
 	bool			last;
+	unsigned int		mode;
 	unsigned int		platform;
+	void			*pltfm_priv;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
+int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
new file mode 100644
index 0000000000000..99db93caa4cb9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include "i2c-viai2c-common.h"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+
+#define ZXI2C_FIFO_SIZE		32
+
+struct viai2c_zhaoxin {
+	u8			hrv;
+	u16			tr;
+	u16			mcr;
+	u16			xfer_len;
+};
+
+/* 'irq == true' means in interrupt context */
+int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
+{
+	u16 i;
+	u8 tmp;
+	struct i2c_msg *msg = i2c->msg;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	if (irq) {
+		/* get the received data */
+		if (read)
+			for (i = 0; i < priv->xfer_len; i++)
+				msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR);
+
+		i2c->xfered_len += priv->xfer_len;
+		if (i2c->xfered_len == msg->len)
+			return 1;
+	}
+
+	/* reset fifo buffer */
+	tmp = ioread8(base + ZXI2C_REG_HCR);
+	iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+	/* set xfer len */
+	priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE);
+	if (read) {
+		iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR);
+	} else {
+		iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR);
+		/* set write data */
+		for (i = 0; i < priv->xfer_len; i++)
+			iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR);
+	}
+
+	/* prepare to stop transmission */
+	if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) {
+		tmp = ioread8(base + VIAI2C_REG_CR);
+		tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+		iowrite8(tmp, base + VIAI2C_REG_CR);
+	}
+
+	if (irq) {
+		/* continue transmission */
+		tmp = ioread8(base + VIAI2C_REG_CR);
+		iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
+	} else {
+		u16 tcr_val = i2c->tcr;
+
+		/* start transmission */
+		tcr_val |= read ? VIAI2C_TCR_READ : 0;
+		writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+	}
+
+	return 0;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap);
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+	void __iomem *base = i2c->base;
+
+	ret = viai2c_wait_bus_not_busy(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 && (priv->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR);
+
+		i2c->msg = msgs;
+		i2c->mode = VIAI2C_FIFO_MODE;
+		priv->xfer_len = i2c->xfered_len = 0;
+
+		viai2c_fifo_irq_xfer(i2c, 0);
+
+		if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+			return -ETIMEDOUT;
+
+		ret = i2c->ret;
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret == -ETIMEDOUT)
+			iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR);
+	}
+	/* dis interrupt */
+	iowrite8(0, base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct viai2c *i2c)
+{
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	iowrite16(priv->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(priv->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct viai2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "speed:%d, fstp:0x%x, golden:0x%x\n",
+				params[0], fstp, params[2]);
+		priv->tr = params[2] | 0xff00;
+	} else {
+		priv->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	priv->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0x80 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		priv->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct viai2c *i2c;
+	struct i2c_adapter *adap;
+	struct viai2c_zhaoxin *priv;
+
+	error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
+	if (error)
+		return error;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	i2c->pltfm_priv = priv;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	priv->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
+			dev_name(pdev->dev.parent), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int __maybe_unused zxi2c_resume(struct device *dev)
+{
+	struct viai2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = "i2c_zhaoxin",
+		.acpi_match_table = zxi2c_acpi_match,
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.43.0


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

* Re: [PATCH v9 0/6] i2c: add zhaoxin i2c controller driver
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
                               ` (5 preceding siblings ...)
  2024-03-06 21:24             ` [PATCH v9 6/6] i2c: add zhaoxin i2c controller driver Andi Shyti
@ 2024-03-08  1:22             ` Hans Hu
  2024-03-08 12:30               ` Andi Shyti
  2024-04-03 23:29               ` Andi Shyti
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
  7 siblings, 2 replies; 133+ messages in thread
From: Hans Hu @ 2024-03-08  1:22 UTC (permalink / raw)
  To: Andi Shyti, linux-i2c; +Cc: wsa, cobechen, hanshu

Hi Andi,


> Check the changelog for more details. The little adaptation are
> limited to patch 1, 2 and 3. The other patches don't have any
> change.
>
> The series has been applied in i2c/i2c-host-next[*].

V9 does not appear to have been applied in i2c/i2c-host-next[*]. So, 
should I submit a v10 version? which its structure is: * patch 0-6 is 
consistent with v9. * patch 7 is new to fix issues as you mentioned 
before Thanks, Hans

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

* Re: [PATCH v9 0/6] i2c: add zhaoxin i2c controller driver
  2024-03-08  1:22             ` [PATCH v9 0/6] " Hans Hu
@ 2024-03-08 12:30               ` Andi Shyti
  2024-04-03 23:29               ` Andi Shyti
  1 sibling, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-03-08 12:30 UTC (permalink / raw)
  To: Hans Hu; +Cc: linux-i2c, wsa, cobechen, hanshu

Hi Hans,

> > Check the changelog for more details. The little adaptation are
> > limited to patch 1, 2 and 3. The other patches don't have any
> > change.
> > 
> > The series has been applied in i2c/i2c-host-next[*].
> 
> V9 does not appear to have been applied in i2c/i2c-host-next[*]. So, should
> I submit a v10 version? which its structure is: * patch 0-6 is consistent
> with v9. * patch 7 is new to fix issues as you mentioned before Thanks, Hans

I'm sorry, I forgot to push :-(

Please, check now.

Andi

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

* Re: [PATCH v9 0/6] i2c: add zhaoxin i2c controller driver
  2024-03-08  1:22             ` [PATCH v9 0/6] " Hans Hu
  2024-03-08 12:30               ` Andi Shyti
@ 2024-04-03 23:29               ` Andi Shyti
  2024-04-07  1:36                 ` Hans Hu
  1 sibling, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-04-03 23:29 UTC (permalink / raw)
  To: Hans Hu; +Cc: linux-i2c, wsa, cobechen, hanshu

Hi Hans,

On Fri, Mar 08, 2024 at 09:22:16AM +0800, Hans Hu wrote:
> > Check the changelog for more details. The little adaptation are
> > limited to patch 1, 2 and 3. The other patches don't have any
> > change.
> > 
> > The series has been applied in i2c/i2c-host-next[*].
> 
> V9 does not appear to have been applied in i2c/i2c-host-next[*]. So, should
> I submit a v10 version? which its structure is: * patch 0-6 is consistent
> with v9. * patch 7 is new to fix issues as you mentioned before Thanks, Hans

I just want to make sure that we have an understanding on this
series.

Now that the 6.9 merge window is well over, are you planning to
resend this series?

Thanks,
Andi

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

* Re: [PATCH v9 0/6] i2c: add zhaoxin i2c controller driver
  2024-04-03 23:29               ` Andi Shyti
@ 2024-04-07  1:36                 ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-04-07  1:36 UTC (permalink / raw)
  To: Andi Shyti; +Cc: linux-i2c, wsa, cobechen, hanshu

Hi Andi,


> Hi Hans,
>
> On Fri, Mar 08, 2024 at 09:22:16AM +0800, Hans Hu wrote:
>>> Check the changelog for more details. The little adaptation are
>>> limited to patch 1, 2 and 3. The other patches don't have any
>>> change.
>>>
>>> The series has been applied in i2c/i2c-host-next[*].
>> V9 does not appear to have been applied in i2c/i2c-host-next[*]. So, should
>> I submit a v10 version? which its structure is: * patch 0-6 is consistent
>> with v9. * patch 7 is new to fix issues as you mentioned before Thanks, Hans
> I just want to make sure that we have an understanding on this
> series.
>
> Now that the 6.9 merge window is well over, are you planning to
> resend this series?


Yes, I will submit the v10 patch based on the latest i2c/i2c-host-next[*].


Thanks,

Hans


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

* [PATCH v10 0/6] i2c: add zhaoxin i2c controller driver
  2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
                               ` (6 preceding siblings ...)
  2024-03-08  1:22             ` [PATCH v9 0/6] " Hans Hu
@ 2024-04-08  2:54             ` Hans Hu
  2024-04-08  2:54               ` [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
                                 ` (7 more replies)
  7 siblings, 8 replies; 133+ messages in thread
From: Hans Hu @ 2024-04-08  2:54 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu

v9->v10:
	* fixed style issues that were checked out by checkpatch.pl.
	* In Patch 3 in wmt_i2c_write() function, deleted the log
	  when received nack.
	* In Patch 4 in viai2c_irq_xfer() function, return 1 for
	  I2C_SMBUS_QUICK access.
	* In Patch 6 in zxi2c_get_bus_speed() function, adjusted
	  the log when firmware gives inappropriate parameters.
	Link: https://lore.kernel.org/all/20240306212413.1850236-1-andi.shyti@kernel.org/

v8->v9:
	* In Patch 1 in probe() do not return at the
	  i2c_add_adapter(), but call clk_disable_unprepare()
	  in case of failure.
	* In Patch 2 fix the conflict when i2c-wmt.c is removed.
	* In Patch 2 in wmt_i2c_probe() function, call
	  clk_disable_unprepare() in case of failure. While at
	  it, add a comment to explain the reason.
	* When renaming i2c_dev to i2c, change also the reference
	  in clk_disable_unprepare().
	Link: https://lore.kernel.org/all/20240306212413.1850236-1-andi.shyti@kernel.org/

v7->v8:
	* move per-msg handling to interrupt context
	* add private struct viai2c_zhaoxin to handle zhaoxin specific things
	* fixed some other formatting issues
	Link: https://lore.kernel.org/all/cover.1704440251.git.hanshu-oc@zhaoxin.com/

v6->v7:
	* adjust the patch sequence
	* put those renaming related patches in 1 patch file
	* rename i2c-*-plt.c to i2c-viai2c-*.c
	* Some other adjustments suggested by Andi
	For more details, see the comment in each patch please.
	Link: https://lore.kernel.org/all/cover.1703830854.git.hanshu-oc@zhaoxin.com/

v5->v6:
	* fix build warnning reported by kernel test robot.
	  Link: https://lore.kernel.org/all/202312291225.cWVt6YF9-lkp@intel.com/
	Link: https://lore.kernel.org/all/cover.1703733126.git.hanshu-oc@zhaoxin.com/

v4->v5:
	* fix 1 build error.
	  Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
	Link: https://lore.kernel.org/all/cover.1703647471.git.hanshu-oc@zhaoxin.com/

v3->v4:
	* Some adjustments as suggested by Wolfram.
	* rebase patch on top of for-next branch.
	Link: https://lore.kernel.org/all/cover.1698889581.git.hanshu-oc@zhaoxin.com/

v2->v3:
	* Split the number of patches from 2 to 12. Make it easier to review.
	Link: https://lore.kernel.org/all/cover.1691999569.git.hanshu-oc@zhaoxin.com/

v1->v2:
	* Fixed some bugs I found myself.
	Link: https://lore.kernel.org/all/cover.1691030850.git.hanshu-oc@zhaoxin.com/

Old version:
	This patch has already gone through a round of reviews.
	The difference from the first round is that it reuses
	the i2c-wmt driver.
	Link: https://lore.kernel.org/all/20230614094858.317652-1-hanshu-oc@zhaoxin.com/

Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>

Hans Hu (6):
  i2c: wmt: create wmt_i2c_init for general init
  i2c: wmt: split out common files
  i2c: wmt: rename something
  i2c: wmt: fix a bug when thread blocked
  i2c: wmt: add platform type VIAI2C_PLAT_WMT
  i2c: add zhaoxin i2c controller driver

 MAINTAINERS                             |  10 +-
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   3 +
 drivers/i2c/busses/i2c-viai2c-common.c  | 256 ++++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h  |  85 +++++
 drivers/i2c/busses/i2c-viai2c-wmt.c     | 148 +++++++++
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 298 +++++++++++++++++
 drivers/i2c/busses/i2c-wmt.c            | 421 ------------------------
 8 files changed, 809 insertions(+), 422 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

-- 
2.34.1


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

* [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
@ 2024-04-08  2:54               ` Hans Hu
  2024-04-23 11:23                 ` Andi Shyti
  2024-04-08  2:54               ` [PATCH v10 2/6] i2c: wmt: split out common files Hans Hu
                                 ` (6 subsequent siblings)
  7 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-04-08  2:54 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

Some common initialization actions are put in the function
wmt_i2c_init(), which is convenient to share with zhaoxin.

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-wmt.c | 65 ++++++++++++++++++++----------------
 1 file changed, 37 insertions(+), 28 deletions(-)

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 198afee5233c..76ede433f65c 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -109,7 +109,7 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
 	unsigned long wait_result;
 
 	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-						msecs_to_jiffies(500));
+						  msecs_to_jiffies(500));
 	if (!wait_result)
 		return -ETIMEDOUT;
 
@@ -286,6 +286,38 @@ static irqreturn_t wmt_i2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+			       0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
+
 static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 {
 	int err;
@@ -327,19 +359,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq) {
-		dev_err(&pdev->dev, "irq missing or invalid\n");
-		return -EINVAL;
-	}
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
 
 	i2c_dev->clk = of_clk_get(np, 0);
 	if (IS_ERR(i2c_dev->clk)) {
@@ -348,18 +370,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
+	if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ)
 		i2c_dev->tcr = TCR_FAST_MODE;
 
-	i2c_dev->dev = &pdev->dev;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
-							"i2c", i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
-		return err;
-	}
-
 	adap = &i2c_dev->adapter;
 	i2c_set_adapdata(adap, i2c_dev);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
@@ -368,8 +381,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	init_completion(&i2c_dev->complete);
-
 	err = wmt_i2c_reset_hardware(i2c_dev);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
@@ -380,8 +391,6 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	if (err)
 		goto err_disable_clk;
 
-	platform_set_drvdata(pdev, i2c_dev);
-
 	return 0;
 
 err_disable_clk:
-- 
2.34.1


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

* [PATCH v10 2/6] i2c: wmt: split out common files
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
  2024-04-08  2:54               ` [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2024-04-08  2:54               ` Hans Hu
  2024-04-08  2:54               ` [PATCH v10 3/6] i2c: wmt: rename something Hans Hu
                                 ` (5 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-04-08  2:54 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

Since the I2C IP of both wmt and zhaoxin originates from VIA,
it is better to separate the common code first.
The common driver is named as i2c-viai2c-common.c.
Old i2c-wmt.c renamed to i2c-viai2c-wmt.c.

The MAINTAINERS file will be updated accordingly in upcoming commits.

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                            |   2 +-
 drivers/i2c/busses/Makefile            |   1 +
 drivers/i2c/busses/i2c-viai2c-common.c | 221 +++++++++++++
 drivers/i2c/busses/i2c-viai2c-common.h |  71 ++++
 drivers/i2c/busses/i2c-viai2c-wmt.c    | 148 +++++++++
 drivers/i2c/busses/i2c-wmt.c           | 430 -------------------------
 6 files changed, 442 insertions(+), 431 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
 create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
 create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
 delete mode 100644 drivers/i2c/busses/i2c-wmt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7c121493f43d..97fcb8d38210 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3018,7 +3018,7 @@ S:	Orphan
 F:	Documentation/devicetree/bindings/i2c/i2c-wmt.txt
 F:	arch/arm/mach-vt8500/
 F:	drivers/clocksource/timer-vt8500.c
-F:	drivers/i2c/busses/i2c-wmt.c
+F:	drivers/i2c/busses/i2c-viai2c-wmt.c
 F:	drivers/mmc/host/wmt-sdmmc.c
 F:	drivers/pwm/pwm-vt8500.c
 F:	drivers/rtc/rtc-vt8500.c
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index aa0ee8ecd6f2..63c7bbad8134 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_I2C_TEGRA_BPMP)	+= i2c-tegra-bpmp.o
 obj-$(CONFIG_I2C_UNIPHIER)	+= i2c-uniphier.o
 obj-$(CONFIG_I2C_UNIPHIER_F)	+= i2c-uniphier-f.o
 obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
+i2c-wmt-objs := i2c-viai2c-wmt.o i2c-viai2c-common.o
 obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
 i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
new file mode 100644
index 000000000000..b36a5d902990
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/of_irq.h>
+#include "i2c-viai2c-common.h"
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+{
+	unsigned long timeout;
+
+	timeout = jiffies + WMT_I2C_TIMEOUT;
+	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+		if (time_after(jiffies, timeout)) {
+			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			return -EBUSY;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+{
+	int ret = 0;
+	unsigned long wait_result;
+
+	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+						  msecs_to_jiffies(500));
+	if (!wait_result)
+		return -ETIMEDOUT;
+
+	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+		ret = -EIO;
+
+	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+
+static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	int xfer_len = 0;
+
+	if (pmsg->len == 0) {
+		/*
+		 * We still need to run through the while (..) once, so
+		 * start at -1 and break out early from the loop
+		 */
+		xfer_len = -1;
+		writew(0, i2c_dev->base + REG_CDR);
+	} else {
+		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+	}
+
+	if (!(pmsg->flags & I2C_M_NOSTART)) {
+		val = readw(i2c_dev->base + REG_CR);
+		val &= ~CR_TX_END;
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CSR);
+		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+			return -EIO;
+		}
+
+		if (pmsg->len == 0) {
+			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
+			writew(val, i2c_dev->base + REG_CR);
+			break;
+		}
+
+		if (xfer_len == pmsg->len) {
+			if (last != 1)
+				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+		} else {
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
+								REG_CDR);
+			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+		}
+	}
+
+	return 0;
+}
+
+static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+{
+	u16 val, tcr_val = i2c_dev->tcr;
+	int ret;
+	u32 xfer_len = 0;
+
+	val = readw(i2c_dev->base + REG_CR);
+	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+
+	if (!(pmsg->flags & I2C_M_NOSTART))
+		val |= CR_CPU_RDY;
+
+	if (pmsg->len == 1)
+		val |= CR_TX_NEXT_NO_ACK;
+
+	writew(val, i2c_dev->base + REG_CR);
+
+	reinit_completion(&i2c_dev->complete);
+
+	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+
+	writew(tcr_val, i2c_dev->base + REG_TCR);
+
+	if (pmsg->flags & I2C_M_NOSTART) {
+		val = readw(i2c_dev->base + REG_CR);
+		val |= CR_CPU_RDY;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	while (xfer_len < pmsg->len) {
+		ret = wmt_check_status(i2c_dev);
+		if (ret)
+			return ret;
+
+		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		xfer_len++;
+
+		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		if (xfer_len == pmsg->len - 1)
+			val |= CR_TX_NEXT_NO_ACK;
+		writew(val, i2c_dev->base + REG_CR);
+	}
+
+	return 0;
+}
+
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+
+	for (i = 0; ret >= 0 && i < num; i++) {
+		pmsg = &msgs[i];
+		if (!(pmsg->flags & I2C_M_NOSTART)) {
+			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			if (ret < 0)
+				return ret;
+		}
+
+		if (pmsg->flags & I2C_M_RD)
+			ret = wmt_i2c_read(i2c_dev, pmsg);
+		else
+			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+	}
+
+	return (ret < 0) ? ret : i;
+}
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+	struct wmt_i2c_dev *i2c_dev = data;
+
+	/* save the status and write-clear it */
+	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
+	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+
+	complete(&i2c_dev->complete);
+
+	return IRQ_HANDLED;
+}
+
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+{
+	int err;
+	struct wmt_i2c_dev *i2c_dev;
+	struct device_node *np = pdev->dev.of_node;
+
+	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return -ENOMEM;
+
+	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c_dev->base))
+		return PTR_ERR(i2c_dev->base);
+
+	i2c_dev->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c_dev->irq)
+		return -EINVAL;
+
+	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
+			       0, pdev->name, i2c_dev);
+	if (err)
+		return dev_err_probe(&pdev->dev, err,
+				"failed to request irq %i\n", i2c_dev->irq);
+
+	i2c_dev->dev = &pdev->dev;
+	init_completion(&i2c_dev->complete);
+	platform_set_drvdata(pdev, i2c_dev);
+
+	*pi2c_dev = i2c_dev;
+	return 0;
+}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
new file mode 100644
index 000000000000..fcff8e4456eb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __I2C_VIAI2C_COMMON_H_
+#define __I2C_VIAI2C_COMMON_H_
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define REG_CR		0x00
+#define REG_TCR		0x02
+#define REG_CSR		0x04
+#define REG_ISR		0x06
+#define REG_IMR		0x08
+#define REG_CDR		0x0A
+#define REG_TR		0x0C
+#define REG_MCR		0x0E
+
+/* REG_CR Bit fields */
+#define CR_TX_NEXT_ACK		0x0000
+#define CR_ENABLE		0x0001
+#define CR_TX_NEXT_NO_ACK	0x0002
+#define CR_TX_END		0x0004
+#define CR_CPU_RDY		0x0008
+#define SLAV_MODE_SEL		0x8000
+
+/* REG_TCR Bit fields */
+#define TCR_STANDARD_MODE	0x0000
+#define TCR_MASTER_WRITE	0x0000
+#define TCR_HS_MODE		0x2000
+#define TCR_MASTER_READ		0x4000
+#define TCR_FAST_MODE		0x8000
+#define TCR_SLAVE_ADDR_MASK	0x007F
+
+/* REG_ISR Bit fields */
+#define ISR_NACK_ADDR		0x0001
+#define ISR_BYTE_END		0x0002
+#define ISR_SCL_TIMEOUT		0x0004
+#define ISR_WRITE_ALL		0x0007
+
+/* REG_IMR Bit fields */
+#define IMR_ENABLE_ALL		0x0007
+
+/* REG_CSR Bit fields */
+#define CSR_RCV_NOT_ACK		0x0001
+#define CSR_RCV_ACK_MASK	0x0001
+#define CSR_READY_MASK		0x0002
+
+#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+
+struct wmt_i2c_dev {
+	struct i2c_adapter	adapter;
+	struct completion	complete;
+	struct device		*dev;
+	void __iomem		*base;
+	struct clk		*clk;
+	u16			tcr;
+	int			irq;
+	u16			cmd_status;
+};
+
+int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
+int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
+int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+
+#endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
new file mode 100644
index 000000000000..3125374cc2c0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Wondermedia I2C Master Mode Driver
+ *
+ *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ *  Derived from GPLv2+ licensed source:
+ *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include "i2c-viai2c-common.h"
+
+#define REG_SLAVE_CR	0x10
+#define REG_SLAVE_SR	0x12
+#define REG_SLAVE_ISR	0x14
+#define REG_SLAVE_IMR	0x16
+#define REG_SLAVE_DR	0x18
+#define REG_SLAVE_TR	0x1A
+
+/* REG_TR */
+#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
+#define TR_STD			0x0064
+#define TR_HS			0x0019
+
+/* REG_MCR */
+#define MCR_APB_96M		7
+#define MCR_APB_166M		12
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+	.master_xfer	= wmt_i2c_xfer,
+	.functionality	= wmt_i2c_func,
+};
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+{
+	int err;
+
+	err = clk_prepare_enable(i2c_dev->clk);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		return err;
+	}
+
+	err = clk_set_rate(i2c_dev->clk, 20000000);
+	if (err) {
+		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c_dev->clk);
+		return err;
+	}
+
+	writew(0, i2c_dev->base + REG_CR);
+	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
+	writew(CR_ENABLE, i2c_dev->base + REG_CR);
+	readw(i2c_dev->base + REG_CSR);		/* read clear */
+	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+
+	if (i2c_dev->tcr == TCR_FAST_MODE)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	else
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+
+	return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct wmt_i2c_dev *i2c_dev;
+	struct i2c_adapter *adap;
+	int err;
+	u32 clk_rate;
+
+	err = wmt_i2c_init(pdev, &i2c_dev);
+	if (err)
+		return err;
+
+	i2c_dev->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c_dev->clk)) {
+		dev_err(&pdev->dev, "unable to request clock\n");
+		return PTR_ERR(i2c_dev->clk);
+	}
+
+	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+	if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ)
+		i2c_dev->tcr = TCR_FAST_MODE;
+
+	adap = &i2c_dev->adapter;
+	i2c_set_adapdata(adap, i2c_dev);
+	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+	adap->owner = THIS_MODULE;
+	adap->algo = &wmt_i2c_algo;
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+
+	err = wmt_i2c_reset_hardware(i2c_dev);
+	if (err) {
+		dev_err(&pdev->dev, "error initializing hardware\n");
+		return err;
+	}
+
+	err = i2c_add_adapter(adap);
+	if (err)
+		/* wmt_i2c_reset_hardware() enables i2c_dev->clk */
+		clk_disable_unprepare(i2c_dev->clk);
+
+	return err;
+}
+
+static void wmt_i2c_remove(struct platform_device *pdev)
+{
+	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+	/* Disable interrupts, clock and delete adapter */
+	writew(0, i2c_dev->base + REG_IMR);
+	clk_disable_unprepare(i2c_dev->clk);
+	i2c_del_adapter(&i2c_dev->adapter);
+}
+
+static const struct of_device_id wmt_i2c_dt_ids[] = {
+	{ .compatible = "wm,wm8505-i2c" },
+	{ /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+	.probe		= wmt_i2c_probe,
+	.remove_new	= wmt_i2c_remove,
+	.driver		= {
+		.name	= "wmt-i2c",
+		.of_match_table = wmt_i2c_dt_ids,
+	},
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
deleted file mode 100644
index 76ede433f65c..000000000000
--- a/drivers/i2c/busses/i2c-wmt.c
+++ /dev/null
@@ -1,430 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *  Wondermedia I2C Master Mode Driver
- *
- *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
- *
- *  Derived from GPLv2+ licensed source:
- *  - Copyright (C) 2008 WonderMedia Technologies, Inc.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/platform_device.h>
-
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-#define REG_SLAVE_CR	0x10
-#define REG_SLAVE_SR	0x12
-#define REG_SLAVE_ISR	0x14
-#define REG_SLAVE_IMR	0x16
-#define REG_SLAVE_DR	0x18
-#define REG_SLAVE_TR	0x1A
-
-/* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
-
-/* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
-
-/* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
-
-/* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
-
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
-
-/* REG_TR */
-#define SCL_TIMEOUT(x)		(((x) & 0xFF) << 8)
-#define TR_STD			0x0064
-#define TR_HS			0x0019
-
-/* REG_MCR */
-#define MCR_APB_96M		7
-#define MCR_APB_166M		12
-
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
-
-struct wmt_i2c_dev {
-	struct i2c_adapter	adapter;
-	struct completion	complete;
-	struct device		*dev;
-	void __iomem		*base;
-	struct clk		*clk;
-	u16			tcr;
-	int			irq;
-	u16			cmd_status;
-};
-
-static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
-{
-	unsigned long timeout;
-
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
-		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
-			return -EBUSY;
-		}
-		msleep(20);
-	}
-
-	return 0;
-}
-
-static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
-{
-	int ret = 0;
-	unsigned long wait_result;
-
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-						  msecs_to_jiffies(500));
-	if (!wait_result)
-		return -ETIMEDOUT;
-
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg,
-			 int last)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	int xfer_len = 0;
-
-	if (pmsg->len == 0) {
-		/*
-		 * We still need to run through the while (..) once, so
-		 * start at -1 and break out early from the loop
-		 */
-		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
-	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
-	}
-
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
-		}
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
-{
-	u16 val, tcr_val = i2c_dev->tcr;
-	int ret;
-	u32 xfer_len = 0;
-
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
-
-	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
-
-	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
-
-	writew(val, i2c_dev->base + REG_CR);
-
-	reinit_completion(&i2c_dev->complete);
-
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
-
-	writew(tcr_val, i2c_dev->base + REG_TCR);
-
-	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
-	}
-
-	return 0;
-}
-
-static int wmt_i2c_xfer(struct i2c_adapter *adap,
-			struct i2c_msg msgs[],
-			int num)
-{
-	struct i2c_msg *pmsg;
-	int i;
-	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
-
-	for (i = 0; ret >= 0 && i < num; i++) {
-		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
-			if (ret < 0)
-				return ret;
-		}
-
-		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
-		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
-	}
-
-	return (ret < 0) ? ret : i;
-}
-
-static u32 wmt_i2c_func(struct i2c_adapter *adap)
-{
-	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
-}
-
-static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
-	.functionality	= wmt_i2c_func,
-};
-
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
-{
-	struct wmt_i2c_dev *i2c_dev = data;
-
-	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
-
-	complete(&i2c_dev->complete);
-
-	return IRQ_HANDLED;
-}
-
-static int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
-{
-	int err;
-	struct wmt_i2c_dev *i2c_dev;
-	struct device_node *np = pdev->dev.of_node;
-
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
-		return -ENOMEM;
-
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
-
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
-		return -EINVAL;
-
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-			       0, pdev->name, i2c_dev);
-	if (err)
-		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
-
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
-
-	*pi2c_dev = i2c_dev;
-	return 0;
-}
-
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
-{
-	int err;
-
-	err = clk_prepare_enable(i2c_dev->clk);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
-		return err;
-	}
-
-	err = clk_set_rate(i2c_dev->clk, 20000000);
-	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
-		return err;
-	}
-
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
-	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
-
-	return 0;
-}
-
-static int wmt_i2c_probe(struct platform_device *pdev)
-{
-	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
-	struct i2c_adapter *adap;
-	int err;
-	u32 clk_rate;
-
-	err = wmt_i2c_init(pdev, &i2c_dev);
-	if (err)
-		return err;
-
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
-		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
-	}
-
-	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
-	if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ)
-		i2c_dev->tcr = TCR_FAST_MODE;
-
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
-	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
-	adap->owner = THIS_MODULE;
-	adap->algo = &wmt_i2c_algo;
-	adap->dev.parent = &pdev->dev;
-	adap->dev.of_node = pdev->dev.of_node;
-
-	err = wmt_i2c_reset_hardware(i2c_dev);
-	if (err) {
-		dev_err(&pdev->dev, "error initializing hardware\n");
-		return err;
-	}
-
-	err = i2c_add_adapter(adap);
-	if (err)
-		goto err_disable_clk;
-
-	return 0;
-
-err_disable_clk:
-	clk_disable_unprepare(i2c_dev->clk);
-	return err;
-}
-
-static void wmt_i2c_remove(struct platform_device *pdev)
-{
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
-
-	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
-}
-
-static const struct of_device_id wmt_i2c_dt_ids[] = {
-	{ .compatible = "wm,wm8505-i2c" },
-	{ /* Sentinel */ },
-};
-
-static struct platform_driver wmt_i2c_driver = {
-	.probe		= wmt_i2c_probe,
-	.remove_new	= wmt_i2c_remove,
-	.driver		= {
-		.name	= "wmt-i2c",
-		.of_match_table = wmt_i2c_dt_ids,
-	},
-};
-
-module_platform_driver(wmt_i2c_driver);
-
-MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
-- 
2.34.1


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

* [PATCH v10 3/6] i2c: wmt: rename something
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
  2024-04-08  2:54               ` [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
  2024-04-08  2:54               ` [PATCH v10 2/6] i2c: wmt: split out common files Hans Hu
@ 2024-04-08  2:54               ` Hans Hu
  2024-04-23 11:54                 ` Andi Shyti
  2024-04-08  2:54               ` [PATCH v10 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
                                 ` (4 subsequent siblings)
  7 siblings, 1 reply; 133+ messages in thread
From: Hans Hu @ 2024-04-08  2:54 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename
   common registers, functions, and variable names to follow the
   VIAI2C_ and viai2c_ naming conventions for consistency and clarity.
2. rename i2c_dev to i2c, to shorten the length of a line.
3. rename wait_result to time_left, make it better to reflect the meaning
   of the value returned by wait_for_completion_timeout().
4. remove TCR_MASTER_WRITE, its value is 0.

Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 157 ++++++++++++-------------
 drivers/i2c/busses/i2c-viai2c-common.h |  70 ++++++-----
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  62 +++++-----
 3 files changed, 143 insertions(+), 146 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index b36a5d902990..59901c53ad48 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -2,14 +2,14 @@
 #include <linux/of_irq.h>
 #include "i2c-viai2c-common.h"
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+int viai2c_wait_bus_not_busy(struct viai2c *i2c)
 {
 	unsigned long timeout;
 
-	timeout = jiffies + WMT_I2C_TIMEOUT;
-	while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+	timeout = jiffies + VIAI2C_TIMEOUT;
+	while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) {
 		if (time_after(jiffies, timeout)) {
-			dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+			dev_warn(i2c->dev, "timeout waiting for bus ready\n");
 			return -EBUSY;
 		}
 		msleep(20);
@@ -18,28 +18,28 @@ int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
 	return 0;
 }
 
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+int viai2c_check_status(struct viai2c *i2c)
 {
 	int ret = 0;
-	unsigned long wait_result;
+	unsigned long time_left;
 
-	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-						  msecs_to_jiffies(500));
-	if (!wait_result)
+	time_left = wait_for_completion_timeout(&i2c->complete,
+						msecs_to_jiffies(500));
+	if (!time_left)
 		return -ETIMEDOUT;
 
-	if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
 		ret = -EIO;
 
-	if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
 		ret = -ETIMEDOUT;
 
 	return ret;
 }
 
-static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int last)
+static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	int xfer_len = 0;
 
@@ -49,173 +49,172 @@ static int wmt_i2c_write(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg, int
 		 * start at -1 and break out early from the loop
 		 */
 		xfer_len = -1;
-		writew(0, i2c_dev->base + REG_CDR);
+		writew(0, i2c->base + VIAI2C_REG_CDR);
 	} else {
-		writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-		val = readw(i2c_dev->base + REG_CR);
-		val &= ~CR_TX_END;
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val &= ~VIAI2C_CR_TX_END;
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+	tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK;
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CSR);
-		if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+		val = readw(i2c->base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
+			dev_dbg(i2c->dev, "write RCV NACK error\n");
 			return -EIO;
 		}
 
 		if (pmsg->len == 0) {
-			val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
-			writew(val, i2c_dev->base + REG_CR);
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
+			writew(val, i2c->base + VIAI2C_REG_CR);
 			break;
 		}
 
 		if (xfer_len == pmsg->len) {
 			if (last != 1)
-				writew(CR_ENABLE, i2c_dev->base + REG_CR);
+				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
 		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
-								REG_CDR);
-			writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
 		}
 	}
 
 	return 0;
 }
 
-static int wmt_i2c_read(struct wmt_i2c_dev *i2c_dev, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
-	u16 val, tcr_val = i2c_dev->tcr;
+	u16 val, tcr_val = i2c->tcr;
 	int ret;
 	u32 xfer_len = 0;
 
-	val = readw(i2c_dev->base + REG_CR);
-	val &= ~(CR_TX_END | CR_TX_NEXT_NO_ACK);
+	val = readw(i2c->base + VIAI2C_REG_CR);
+	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
 	if (!(pmsg->flags & I2C_M_NOSTART))
-		val |= CR_CPU_RDY;
+		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
-		val |= CR_TX_NEXT_NO_ACK;
+		val |= VIAI2C_CR_RX_END;
 
-	writew(val, i2c_dev->base + REG_CR);
+	writew(val, i2c->base + VIAI2C_REG_CR);
 
-	reinit_completion(&i2c_dev->complete);
+	reinit_completion(&i2c->complete);
 
-	tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+	tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK);
 
-	writew(tcr_val, i2c_dev->base + REG_TCR);
+	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
 	if (pmsg->flags & I2C_M_NOSTART) {
-		val = readw(i2c_dev->base + REG_CR);
-		val |= CR_CPU_RDY;
-		writew(val, i2c_dev->base + REG_CR);
+		val = readw(i2c->base + VIAI2C_REG_CR);
+		val |= VIAI2C_CR_CPU_RDY;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	while (xfer_len < pmsg->len) {
-		ret = wmt_check_status(i2c_dev);
+		ret = viai2c_check_status(i2c);
 		if (ret)
 			return ret;
 
-		pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+		pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8;
 		xfer_len++;
 
-		val = readw(i2c_dev->base + REG_CR) | CR_CPU_RDY;
+		val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
 		if (xfer_len == pmsg->len - 1)
-			val |= CR_TX_NEXT_NO_ACK;
-		writew(val, i2c_dev->base + REG_CR);
+			val |= VIAI2C_CR_RX_END;
+		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
 	return 0;
 }
 
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 {
 	struct i2c_msg *pmsg;
 	int i;
 	int ret = 0;
-	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+	struct viai2c *i2c = i2c_get_adapdata(adap);
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (!(pmsg->flags & I2C_M_NOSTART)) {
-			ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
 		}
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = wmt_i2c_read(i2c_dev, pmsg);
+			ret = viai2c_read(i2c, pmsg);
 		else
-			ret = wmt_i2c_write(i2c_dev, pmsg, (i + 1) == num);
+			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
 
 	return (ret < 0) ? ret : i;
 }
 
-static irqreturn_t wmt_i2c_isr(int irq, void *data)
+static irqreturn_t viai2c_isr(int irq, void *data)
 {
-	struct wmt_i2c_dev *i2c_dev = data;
+	struct viai2c *i2c = data;
 
 	/* save the status and write-clear it */
-	i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
-	writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
 
-	complete(&i2c_dev->complete);
+	complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
 
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 {
 	int err;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
-	i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
-	if (!i2c_dev)
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
 		return -ENOMEM;
 
-	i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
-	if (IS_ERR(i2c_dev->base))
-		return PTR_ERR(i2c_dev->base);
+	i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
+	if (IS_ERR(i2c->base))
+		return PTR_ERR(i2c->base);
 
-	i2c_dev->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c_dev->irq)
+	i2c->irq = irq_of_parse_and_map(np, 0);
+	if (!i2c->irq)
 		return -EINVAL;
 
-	err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr,
-			       0, pdev->name, i2c_dev);
+	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
+			       0, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
-				"failed to request irq %i\n", i2c_dev->irq);
+				"failed to request irq %i\n", i2c->irq);
 
-	i2c_dev->dev = &pdev->dev;
-	init_completion(&i2c_dev->complete);
-	platform_set_drvdata(pdev, i2c_dev);
+	i2c->dev = &pdev->dev;
+	init_completion(&i2c->complete);
+	platform_set_drvdata(pdev, i2c);
 
-	*pi2c_dev = i2c_dev;
+	*pi2c = i2c;
 	return 0;
 }
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index fcff8e4456eb..28799e7e97f0 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -11,48 +11,46 @@
 #include <linux/of_irq.h>
 #include <linux/platform_device.h>
 
-#define REG_CR		0x00
-#define REG_TCR		0x02
-#define REG_CSR		0x04
-#define REG_ISR		0x06
-#define REG_IMR		0x08
-#define REG_CDR		0x0A
-#define REG_TR		0x0C
-#define REG_MCR		0x0E
-
 /* REG_CR Bit fields */
-#define CR_TX_NEXT_ACK		0x0000
-#define CR_ENABLE		0x0001
-#define CR_TX_NEXT_NO_ACK	0x0002
-#define CR_TX_END		0x0004
-#define CR_CPU_RDY		0x0008
-#define SLAV_MODE_SEL		0x8000
+#define VIAI2C_REG_CR		0x00
+#define VIAI2C_CR_ENABLE		BIT(0)
+#define VIAI2C_CR_RX_END		BIT(1)
+#define VIAI2C_CR_TX_END		BIT(2)
+#define VIAI2C_CR_CPU_RDY		BIT(3)
+#define VIAI2C_CR_END_MASK		GENMASK(2, 1)
 
 /* REG_TCR Bit fields */
-#define TCR_STANDARD_MODE	0x0000
-#define TCR_MASTER_WRITE	0x0000
-#define TCR_HS_MODE		0x2000
-#define TCR_MASTER_READ		0x4000
-#define TCR_FAST_MODE		0x8000
-#define TCR_SLAVE_ADDR_MASK	0x007F
+#define VIAI2C_REG_TCR		0x02
+#define VIAI2C_TCR_HS_MODE		BIT(13)
+#define VIAI2C_TCR_READ			BIT(14)
+#define VIAI2C_TCR_FAST			BIT(15)
+#define VIAI2C_TCR_ADDR_MASK		GENMASK(6, 0)
+
+/* REG_CSR Bit fields */
+#define VIAI2C_REG_CSR		0x04
+#define VIAI2C_CSR_RCV_NOT_ACK		BIT(0)
+#define VIAI2C_CSR_RCV_ACK_MASK		BIT(0)
+#define VIAI2C_CSR_READY_MASK		BIT(1)
 
 /* REG_ISR Bit fields */
-#define ISR_NACK_ADDR		0x0001
-#define ISR_BYTE_END		0x0002
-#define ISR_SCL_TIMEOUT		0x0004
-#define ISR_WRITE_ALL		0x0007
+#define VIAI2C_REG_ISR		0x06
+#define VIAI2C_ISR_NACK_ADDR		BIT(0)
+#define VIAI2C_ISR_BYTE_END		BIT(1)
+#define VIAI2C_ISR_SCL_TIMEOUT		BIT(2)
+#define VIAI2C_ISR_MASK_ALL		GENMASK(2, 0)
 
 /* REG_IMR Bit fields */
-#define IMR_ENABLE_ALL		0x0007
+#define VIAI2C_REG_IMR		0x08
+#define VIAI2C_IMR_BYTE			BIT(1)
+#define VIAI2C_IMR_ENABLE_ALL		GENMASK(2, 0)
 
-/* REG_CSR Bit fields */
-#define CSR_RCV_NOT_ACK		0x0001
-#define CSR_RCV_ACK_MASK	0x0001
-#define CSR_READY_MASK		0x0002
+#define VIAI2C_REG_CDR		0x0A
+#define VIAI2C_REG_TR		0x0C
+#define VIAI2C_REG_MCR		0x0E
 
-#define WMT_I2C_TIMEOUT		(msecs_to_jiffies(1000))
+#define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
-struct wmt_i2c_dev {
+struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
 	struct device		*dev;
@@ -63,9 +61,9 @@ struct wmt_i2c_dev {
 	u16			cmd_status;
 };
 
-int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev);
-int wmt_check_status(struct wmt_i2c_dev *i2c_dev);
-int wmt_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int wmt_i2c_init(struct platform_device *pdev, struct wmt_i2c_dev **pi2c_dev);
+int viai2c_wait_bus_not_busy(struct viai2c *i2c);
+int viai2c_check_status(struct viai2c *i2c);
+int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 3125374cc2c0..1e9db735e1fa 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -35,39 +35,39 @@ static u32 wmt_i2c_func(struct i2c_adapter *adap)
 }
 
 static const struct i2c_algorithm wmt_i2c_algo = {
-	.master_xfer	= wmt_i2c_xfer,
+	.master_xfer	= viai2c_xfer,
 	.functionality	= wmt_i2c_func,
 };
 
-static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+static int wmt_i2c_reset_hardware(struct viai2c *i2c)
 {
 	int err;
 
-	err = clk_prepare_enable(i2c_dev->clk);
+	err = clk_prepare_enable(i2c->clk);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to enable clock\n");
+		dev_err(i2c->dev, "failed to enable clock\n");
 		return err;
 	}
 
-	err = clk_set_rate(i2c_dev->clk, 20000000);
+	err = clk_set_rate(i2c->clk, 20000000);
 	if (err) {
-		dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
-		clk_disable_unprepare(i2c_dev->clk);
+		dev_err(i2c->dev, "failed to set clock = 20Mhz\n");
+		clk_disable_unprepare(i2c->clk);
 		return err;
 	}
 
-	writew(0, i2c_dev->base + REG_CR);
-	writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
-	writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
-	writew(CR_ENABLE, i2c_dev->base + REG_CR);
-	readw(i2c_dev->base + REG_CSR);		/* read clear */
-	writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+	writew(0, i2c->base + VIAI2C_REG_CR);
+	writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR);
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
+	writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR);
+	writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
+	readw(i2c->base + VIAI2C_REG_CSR);		/* read clear */
+	writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR);
 
-	if (i2c_dev->tcr == TCR_FAST_MODE)
-		writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+	if (i2c->tcr == VIAI2C_TCR_FAST)
+		writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR);
 	else
-		writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+		writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR);
 
 	return 0;
 }
@@ -75,34 +75,34 @@ static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
 static int wmt_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
-	struct wmt_i2c_dev *i2c_dev;
+	struct viai2c *i2c;
 	struct i2c_adapter *adap;
 	int err;
 	u32 clk_rate;
 
-	err = wmt_i2c_init(pdev, &i2c_dev);
+	err = viai2c_init(pdev, &i2c);
 	if (err)
 		return err;
 
-	i2c_dev->clk = of_clk_get(np, 0);
-	if (IS_ERR(i2c_dev->clk)) {
+	i2c->clk = of_clk_get(np, 0);
+	if (IS_ERR(i2c->clk)) {
 		dev_err(&pdev->dev, "unable to request clock\n");
-		return PTR_ERR(i2c_dev->clk);
+		return PTR_ERR(i2c->clk);
 	}
 
 	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
 	if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ)
-		i2c_dev->tcr = TCR_FAST_MODE;
+		i2c->tcr = VIAI2C_TCR_FAST;
 
-	adap = &i2c_dev->adapter;
-	i2c_set_adapdata(adap, i2c_dev);
+	adap = &i2c->adapter;
+	i2c_set_adapdata(adap, i2c);
 	strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
 	adap->owner = THIS_MODULE;
 	adap->algo = &wmt_i2c_algo;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	err = wmt_i2c_reset_hardware(i2c_dev);
+	err = wmt_i2c_reset_hardware(i2c);
 	if (err) {
 		dev_err(&pdev->dev, "error initializing hardware\n");
 		return err;
@@ -111,19 +111,19 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	err = i2c_add_adapter(adap);
 	if (err)
 		/* wmt_i2c_reset_hardware() enables i2c_dev->clk */
-		clk_disable_unprepare(i2c_dev->clk);
+		clk_disable_unprepare(i2c->clk);
 
 	return err;
 }
 
 static void wmt_i2c_remove(struct platform_device *pdev)
 {
-	struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+	struct viai2c *i2c = platform_get_drvdata(pdev);
 
 	/* Disable interrupts, clock and delete adapter */
-	writew(0, i2c_dev->base + REG_IMR);
-	clk_disable_unprepare(i2c_dev->clk);
-	i2c_del_adapter(&i2c_dev->adapter);
+	writew(0, i2c->base + VIAI2C_REG_IMR);
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adapter);
 }
 
 static const struct of_device_id wmt_i2c_dt_ids[] = {
-- 
2.34.1


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

* [PATCH v10 4/6] i2c: wmt: fix a bug when thread blocked
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
                                 ` (2 preceding siblings ...)
  2024-04-08  2:54               ` [PATCH v10 3/6] i2c: wmt: rename something Hans Hu
@ 2024-04-08  2:54               ` Hans Hu
  2024-04-08  2:54               ` [PATCH v10 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
                                 ` (3 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-04-08  2:54 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

During each byte access, the host performs clock stretching.

To reduce the host performs clock stretching, move most of
the per-msg processing to the interrupt context.

Suggested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 145 +++++++++++++------------
 drivers/i2c/busses/i2c-viai2c-common.h |   6 +-
 2 files changed, 80 insertions(+), 71 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 59901c53ad48..1b39cf4f0d6c 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -18,37 +18,18 @@ int viai2c_wait_bus_not_busy(struct viai2c *i2c)
 	return 0;
 }
 
-int viai2c_check_status(struct viai2c *i2c)
-{
-	int ret = 0;
-	unsigned long time_left;
-
-	time_left = wait_for_completion_timeout(&i2c->complete,
-						msecs_to_jiffies(500));
-	if (!time_left)
-		return -ETIMEDOUT;
-
-	if (i2c->cmd_status & VIAI2C_ISR_NACK_ADDR)
-		ret = -EIO;
-
-	if (i2c->cmd_status & VIAI2C_ISR_SCL_TIMEOUT)
-		ret = -ETIMEDOUT;
-
-	return ret;
-}
-
 static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 {
 	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	int xfer_len = 0;
+
+	i2c->last = last;
 
 	if (pmsg->len == 0) {
 		/*
 		 * We still need to run through the while (..) once, so
 		 * start at -1 and break out early from the loop
 		 */
-		xfer_len = -1;
+		i2c->xfered_len = -1;
 		writew(0, i2c->base + VIAI2C_REG_CDR);
 	} else {
 		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
@@ -73,42 +54,15 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	while (xfer_len < pmsg->len) {
-		ret = viai2c_check_status(i2c);
-		if (ret)
-			return ret;
-
-		xfer_len++;
-
-		val = readw(i2c->base + VIAI2C_REG_CSR);
-		if (val & VIAI2C_CSR_RCV_NOT_ACK) {
-			dev_dbg(i2c->dev, "write RCV NACK error\n");
-			return -EIO;
-		}
-
-		if (pmsg->len == 0) {
-			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
-			writew(val, i2c->base + VIAI2C_REG_CR);
-			break;
-		}
-
-		if (xfer_len == pmsg->len) {
-			if (last != 1)
-				writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
-		} else {
-			writew(pmsg->buf[xfer_len] & 0xFF, i2c->base + VIAI2C_REG_CDR);
-			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR);
-		}
-	}
+	if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+		return -ETIMEDOUT;
 
-	return 0;
+	return i2c->ret;
 }
 
 static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 {
 	u16 val, tcr_val = i2c->tcr;
-	int ret;
-	u32 xfer_len = 0;
 
 	val = readw(i2c->base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
@@ -133,21 +87,10 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 		writew(val, i2c->base + VIAI2C_REG_CR);
 	}
 
-	while (xfer_len < pmsg->len) {
-		ret = viai2c_check_status(i2c);
-		if (ret)
-			return ret;
-
-		pmsg->buf[xfer_len] = readw(i2c->base + VIAI2C_REG_CDR) >> 8;
-		xfer_len++;
-
-		val = readw(i2c->base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
-		if (xfer_len == pmsg->len - 1)
-			val |= VIAI2C_CR_RX_END;
-		writew(val, i2c->base + VIAI2C_REG_CR);
-	}
+	if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+		return -ETIMEDOUT;
 
-	return 0;
+	return i2c->ret;
 }
 
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
@@ -165,6 +108,9 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 				return ret;
 		}
 
+		i2c->msg = pmsg;
+		i2c->xfered_len = 0;
+
 		if (pmsg->flags & I2C_M_RD)
 			ret = viai2c_read(i2c, pmsg);
 		else
@@ -174,15 +120,76 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	return (ret < 0) ? ret : i;
 }
 
+/*
+ * Main process of the byte mode xfer
+ *
+ * Return value indicates whether the transfer is complete
+ *  1: all the data has been successfully transferred
+ *  0: there is still data that needs to be transferred
+ *  -EIO: error occurred
+ */
+static int viai2c_irq_xfer(struct viai2c *i2c)
+{
+	u16 val;
+	struct i2c_msg *msg = i2c->msg;
+	u8 read = msg->flags & I2C_M_RD;
+	void __iomem *base = i2c->base;
+
+	if (read) {
+		msg->buf[i2c->xfered_len] = readw(base + VIAI2C_REG_CDR) >> 8;
+
+		val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY;
+		if (i2c->xfered_len == msg->len - 2)
+			val |= VIAI2C_CR_RX_END;
+		writew(val, base + VIAI2C_REG_CR);
+	} else {
+		val = readw(base + VIAI2C_REG_CSR);
+		if (val & VIAI2C_CSR_RCV_NOT_ACK)
+			return -EIO;
+
+		/* I2C_SMBUS_QUICK */
+		if (msg->len == 0) {
+			val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE;
+			writew(val, base + VIAI2C_REG_CR);
+			return 1;
+		}
+
+		if ((i2c->xfered_len + 1) == msg->len) {
+			if (!i2c->last)
+				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+		} else {
+			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
+			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+		}
+	}
+
+	i2c->xfered_len++;
+
+	return i2c->xfered_len == msg->len;
+}
+
 static irqreturn_t viai2c_isr(int irq, void *data)
 {
 	struct viai2c *i2c = data;
+	u8 status;
 
 	/* save the status and write-clear it */
-	i2c->cmd_status = readw(i2c->base + VIAI2C_REG_ISR);
-	writew(i2c->cmd_status, i2c->base + VIAI2C_REG_ISR);
+	status = readw(i2c->base + VIAI2C_REG_ISR);
+	writew(status, i2c->base + VIAI2C_REG_ISR);
+
+	i2c->ret = 0;
+	if (status & VIAI2C_ISR_NACK_ADDR)
+		i2c->ret = -EIO;
+
+	if (status & VIAI2C_ISR_SCL_TIMEOUT)
+		i2c->ret = -ETIMEDOUT;
+
+	if (!i2c->ret)
+		i2c->ret = viai2c_irq_xfer(i2c);
 
-	complete(&i2c->complete);
+	/* All the data has been successfully transferred or error occurred */
+	if (i2c->ret)
+		complete(&i2c->complete);
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index 28799e7e97f0..c92e054ac7e7 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -58,11 +58,13 @@ struct viai2c {
 	struct clk		*clk;
 	u16			tcr;
 	int			irq;
-	u16			cmd_status;
+	u16			xfered_len;
+	struct i2c_msg		*msg;
+	int			ret;
+	bool			last;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
-int viai2c_check_status(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
 
-- 
2.34.1


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

* [PATCH v10 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
                                 ` (3 preceding siblings ...)
  2024-04-08  2:54               ` [PATCH v10 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
@ 2024-04-08  2:54               ` Hans Hu
  2024-04-08  2:54               ` [PATCH v10 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
                                 ` (2 subsequent siblings)
  7 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-04-08  2:54 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

Enumeration variables are added to differentiate
between different platforms.

Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 drivers/i2c/busses/i2c-viai2c-common.c | 32 ++++++++++++++++----------
 drivers/i2c/busses/i2c-viai2c-common.h |  7 +++++-
 drivers/i2c/busses/i2c-viai2c-wmt.c    |  2 +-
 3 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 1b39cf4f0d6c..22a2e31e9c14 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -35,7 +35,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 		writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR);
 	}
 
-	if (!(pmsg->flags & I2C_M_NOSTART)) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val &= ~VIAI2C_CR_TX_END;
 		val |= VIAI2C_CR_CPU_RDY;
@@ -48,7 +48,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -67,7 +67,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 	val = readw(i2c->base + VIAI2C_REG_CR);
 	val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END);
 
-	if (!(pmsg->flags & I2C_M_NOSTART))
+	if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART))
 		val |= VIAI2C_CR_CPU_RDY;
 
 	if (pmsg->len == 1)
@@ -81,7 +81,7 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (pmsg->flags & I2C_M_NOSTART) {
+	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -102,7 +102,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
-		if (!(pmsg->flags & I2C_M_NOSTART)) {
+		if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
 			ret = viai2c_wait_bus_not_busy(i2c);
 			if (ret < 0)
 				return ret;
@@ -155,7 +155,7 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 		}
 
 		if ((i2c->xfered_len + 1) == msg->len) {
-			if (!i2c->last)
+			if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
 		} else {
 			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
@@ -181,7 +181,7 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	if (status & VIAI2C_ISR_NACK_ADDR)
 		i2c->ret = -EIO;
 
-	if (status & VIAI2C_ISR_SCL_TIMEOUT)
+	if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
 		i2c->ret = -ETIMEDOUT;
 
 	if (!i2c->ret)
@@ -194,9 +194,10 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 {
 	int err;
+	int irq_flags;
 	struct viai2c *i2c;
 	struct device_node *np = pdev->dev.of_node;
 
@@ -208,12 +209,19 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c)
 	if (IS_ERR(i2c->base))
 		return PTR_ERR(i2c->base);
 
-	i2c->irq = irq_of_parse_and_map(np, 0);
-	if (!i2c->irq)
-		return -EINVAL;
+	if (plat == VIAI2C_PLAT_WMT) {
+		irq_flags = 0;
+		i2c->irq = irq_of_parse_and_map(np, 0);
+		if (!i2c->irq)
+			return -EINVAL;
+	} else {
+		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
+	}
+
+	i2c->platform = plat;
 
 	err = devm_request_irq(&pdev->dev, i2c->irq, viai2c_isr,
-			       0, pdev->name, i2c);
+			       irq_flags, pdev->name, i2c);
 	if (err)
 		return dev_err_probe(&pdev->dev, err,
 				"failed to request irq %i\n", i2c->irq);
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index c92e054ac7e7..cfe5ab2bd779 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -50,6 +50,10 @@
 
 #define VIAI2C_TIMEOUT		(msecs_to_jiffies(1000))
 
+enum {
+	VIAI2C_PLAT_WMT,
+};
+
 struct viai2c {
 	struct i2c_adapter	adapter;
 	struct completion	complete;
@@ -62,10 +66,11 @@ struct viai2c {
 	struct i2c_msg		*msg;
 	int			ret;
 	bool			last;
+	unsigned int		platform;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
-int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c);
+int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c
index 1e9db735e1fa..e1988f946026 100644
--- a/drivers/i2c/busses/i2c-viai2c-wmt.c
+++ b/drivers/i2c/busses/i2c-viai2c-wmt.c
@@ -80,7 +80,7 @@ static int wmt_i2c_probe(struct platform_device *pdev)
 	int err;
 	u32 clk_rate;
 
-	err = viai2c_init(pdev, &i2c);
+	err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT);
 	if (err)
 		return err;
 
-- 
2.34.1


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

* [PATCH v10 6/6] i2c: add zhaoxin i2c controller driver
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
                                 ` (4 preceding siblings ...)
  2024-04-08  2:54               ` [PATCH v10 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
@ 2024-04-08  2:54               ` Hans Hu
  2024-04-23 12:02               ` [PATCH v10 0/6] " Andi Shyti
  2024-04-29  0:20               ` Andi Shyti
  7 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-04-08  2:54 UTC (permalink / raw)
  To: andi.shyti, linux-i2c; +Cc: wsa, cobechen, hanshu, Wolfram Sang

Add Zhaoxin I2C controller driver. It provides the access to the i2c
busses, which connects to the touchpad, eeprom, I2S, etc.

Zhaoxin I2C controller has two separate busses, so may accommodate up
to two I2C adapters. Those adapters are listed in the ACPI namespace
with the IIC1D17 HID, and probed by a platform driver.

The driver works with IRQ mode, and supports basic I2C features. Flags
I2C_AQ_NO_ZERO_LEN and I2C_AQ_COMB_WRITE_THEN_READ are used to limit
the unsupported access.

Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
---
 MAINTAINERS                             |   8 +
 drivers/i2c/busses/Kconfig              |  10 +
 drivers/i2c/busses/Makefile             |   2 +
 drivers/i2c/busses/i2c-viai2c-common.c  |  31 ++-
 drivers/i2c/busses/i2c-viai2c-common.h  |   9 +
 drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 298 ++++++++++++++++++++++++
 6 files changed, 353 insertions(+), 5 deletions(-)
 create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 97fcb8d38210..134c83409a3b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10265,6 +10265,14 @@ L:	linux-i2c@vger.kernel.org
 F:	Documentation/i2c/busses/i2c-ismt.rst
 F:	drivers/i2c/busses/i2c-ismt.c
 
+I2C/SMBUS ZHAOXIN DRIVER
+M:	Hans Hu <hanshu@zhaoxin.com>
+L:	linux-i2c@vger.kernel.org
+S:	Maintained
+W:	https://www.zhaoxin.com
+F:	drivers/i2c/busses/i2c-viai2c-common.c
+F:	drivers/i2c/busses/i2c-viai2c-zhaoxin.c
+
 I2C/SMBUS STUB DRIVER
 M:	Jean Delvare <jdelvare@suse.com>
 L:	linux-i2c@vger.kernel.org
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 97989c914260..cc781f8ec714 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -336,6 +336,16 @@ config I2C_VIAPRO
 
 if ACPI
 
+config I2C_ZHAOXIN
+	tristate "Zhaoxin I2C Interface"
+	depends on PCI || COMPILE_TEST
+	help
+	  If you say yes to this option, support will be included for the
+	  ZHAOXIN I2C interface
+
+	  This driver can also be built as a module. If so, the module
+	  will be called i2c-zhaoxin.
+
 comment "ACPI drivers"
 
 config I2C_SCMI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 63c7bbad8134..3d65934f5eb4 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
+i2c-zhaoxin-objs := i2c-viai2c-zhaoxin.o i2c-viai2c-common.o
+obj-$(CONFIG_I2C_ZHAOXIN)	+= i2c-zhaoxin.o
 
 # Mac SMBus host controller drivers
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c
index 22a2e31e9c14..1844d13f1f79 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.c
+++ b/drivers/i2c/busses/i2c-viai2c-common.c
@@ -60,7 +60,7 @@ static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last)
 	return i2c->ret;
 }
 
-static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
+static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first)
 {
 	u16 val, tcr_val = i2c->tcr;
 
@@ -81,7 +81,8 @@ static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg)
 
 	writew(tcr_val, i2c->base + VIAI2C_REG_TCR);
 
-	if (i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) {
+	if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) ||
+	    (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) {
 		val = readw(i2c->base + VIAI2C_REG_CR);
 		val |= VIAI2C_CR_CPU_RDY;
 		writew(val, i2c->base + VIAI2C_REG_CR);
@@ -100,6 +101,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	int ret = 0;
 	struct viai2c *i2c = i2c_get_adapdata(adap);
 
+	i2c->mode = VIAI2C_BYTE_MODE;
 	for (i = 0; ret >= 0 && i < num; i++) {
 		pmsg = &msgs[i];
 		if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) {
@@ -112,7 +114,7 @@ int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 		i2c->xfered_len = 0;
 
 		if (pmsg->flags & I2C_M_RD)
-			ret = viai2c_read(i2c, pmsg);
+			ret = viai2c_read(i2c, pmsg, i == 0);
 		else
 			ret = viai2c_write(i2c, pmsg, (i + 1) == num);
 	}
@@ -157,6 +159,8 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 		if ((i2c->xfered_len + 1) == msg->len) {
 			if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last)
 				writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
+			else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last)
+				writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR);
 		} else {
 			writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR);
 			writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR);
@@ -168,6 +172,11 @@ static int viai2c_irq_xfer(struct viai2c *i2c)
 	return i2c->xfered_len == msg->len;
 }
 
+int __weak viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
+{
+	return 0;
+}
+
 static irqreturn_t viai2c_isr(int irq, void *data)
 {
 	struct viai2c *i2c = data;
@@ -175,6 +184,9 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 
 	/* save the status and write-clear it */
 	status = readw(i2c->base + VIAI2C_REG_ISR);
+	if (!status && i2c->platform == VIAI2C_PLAT_ZHAOXIN)
+		return IRQ_NONE;
+
 	writew(status, i2c->base + VIAI2C_REG_ISR);
 
 	i2c->ret = 0;
@@ -184,8 +196,12 @@ static irqreturn_t viai2c_isr(int irq, void *data)
 	if (i2c->platform == VIAI2C_PLAT_WMT && (status & VIAI2C_ISR_SCL_TIMEOUT))
 		i2c->ret = -ETIMEDOUT;
 
-	if (!i2c->ret)
-		i2c->ret = viai2c_irq_xfer(i2c);
+	if (!i2c->ret) {
+		if (i2c->mode == VIAI2C_BYTE_MODE)
+			i2c->ret = viai2c_irq_xfer(i2c);
+		else
+			i2c->ret = viai2c_fifo_irq_xfer(i2c, true);
+	}
 
 	/* All the data has been successfully transferred or error occurred */
 	if (i2c->ret)
@@ -214,6 +230,11 @@ int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat)
 		i2c->irq = irq_of_parse_and_map(np, 0);
 		if (!i2c->irq)
 			return -EINVAL;
+	} else if (plat == VIAI2C_PLAT_ZHAOXIN) {
+		irq_flags = IRQF_SHARED;
+		i2c->irq = platform_get_irq(pdev, 0);
+		if (i2c->irq < 0)
+			return i2c->irq;
 	} else {
 		return dev_err_probe(&pdev->dev, -EINVAL, "wrong platform type\n");
 	}
diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h
index cfe5ab2bd779..81e827c54434 100644
--- a/drivers/i2c/busses/i2c-viai2c-common.h
+++ b/drivers/i2c/busses/i2c-viai2c-common.h
@@ -52,6 +52,12 @@
 
 enum {
 	VIAI2C_PLAT_WMT,
+	VIAI2C_PLAT_ZHAOXIN
+};
+
+enum {
+	VIAI2C_BYTE_MODE,
+	VIAI2C_FIFO_MODE
 };
 
 struct viai2c {
@@ -66,11 +72,14 @@ struct viai2c {
 	struct i2c_msg		*msg;
 	int			ret;
 	bool			last;
+	unsigned int		mode;
 	unsigned int		platform;
+	void			*pltfm_priv;
 };
 
 int viai2c_wait_bus_not_busy(struct viai2c *i2c);
 int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
 int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat);
+int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq);
 
 #endif
diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
new file mode 100644
index 000000000000..7e3ac2a3e1fd
--- /dev/null
+++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *  Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation.
+ *                    All rights reserved.
+ */
+
+#include <linux/acpi.h>
+#include "i2c-viai2c-common.h"
+
+/*
+ * registers
+ */
+/* Zhaoxin specific register bit fields */
+/* REG_CR Bit fields */
+#define   ZXI2C_CR_MST_RST		BIT(7)
+#define   ZXI2C_CR_FIFO_MODE		BIT(14)
+/* REG_ISR/IMR Bit fields */
+#define   ZXI2C_IRQ_FIFONACK		BIT(4)
+#define   ZXI2C_IRQ_FIFOEND		BIT(3)
+#define   ZXI2C_IRQ_MASK		(VIAI2C_ISR_MASK_ALL \
+					| ZXI2C_IRQ_FIFOEND \
+					| ZXI2C_IRQ_FIFONACK)
+/* Zhaoxin specific registers */
+#define ZXI2C_REG_CLK		0x10
+#define   ZXI2C_CLK_50M			BIT(0)
+#define ZXI2C_REG_REV		0x11
+#define ZXI2C_REG_HCR		0x12
+#define   ZXI2C_HCR_RST_FIFO		GENMASK(1, 0)
+#define ZXI2C_REG_HTDR		0x13
+#define ZXI2C_REG_HRDR		0x14
+#define ZXI2C_REG_HTLR		0x15
+#define ZXI2C_REG_HRLR		0x16
+#define ZXI2C_REG_HWCNTR	0x18
+#define ZXI2C_REG_HRCNTR	0x19
+
+/* parameters Constants */
+#define ZXI2C_GOLD_FSTP_100K	0xF3
+#define ZXI2C_GOLD_FSTP_400K	0x38
+#define ZXI2C_GOLD_FSTP_1M	0x13
+#define ZXI2C_GOLD_FSTP_3400K	0x37
+#define ZXI2C_HS_MASTER_CODE	(0x08 << 8)
+
+#define ZXI2C_FIFO_SIZE		32
+
+struct viai2c_zhaoxin {
+	u8			hrv;
+	u16			tr;
+	u16			mcr;
+	u16			xfer_len;
+};
+
+/* 'irq == true' means in interrupt context */
+int viai2c_fifo_irq_xfer(struct viai2c *i2c, bool irq)
+{
+	u16 i;
+	u8 tmp;
+	struct i2c_msg *msg = i2c->msg;
+	void __iomem *base = i2c->base;
+	bool read = !!(msg->flags & I2C_M_RD);
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	if (irq) {
+		/* get the received data */
+		if (read)
+			for (i = 0; i < priv->xfer_len; i++)
+				msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR);
+
+		i2c->xfered_len += priv->xfer_len;
+		if (i2c->xfered_len == msg->len)
+			return 1;
+	}
+
+	/* reset fifo buffer */
+	tmp = ioread8(base + ZXI2C_REG_HCR);
+	iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR);
+
+	/* set xfer len */
+	priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE);
+	if (read) {
+		iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR);
+	} else {
+		iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR);
+		/* set write data */
+		for (i = 0; i < priv->xfer_len; i++)
+			iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR);
+	}
+
+	/* prepare to stop transmission */
+	if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) {
+		tmp = ioread8(base + VIAI2C_REG_CR);
+		tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END;
+		iowrite8(tmp, base + VIAI2C_REG_CR);
+	}
+
+	if (irq) {
+		/* continue transmission */
+		tmp = ioread8(base + VIAI2C_REG_CR);
+		iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR);
+	} else {
+		u16 tcr_val = i2c->tcr;
+
+		/* start transmission */
+		tcr_val |= read ? VIAI2C_TCR_READ : 0;
+		writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR);
+	}
+
+	return 0;
+}
+
+static int zxi2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	u8 tmp;
+	int ret;
+	struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap);
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+	void __iomem *base = i2c->base;
+
+	ret = viai2c_wait_bus_not_busy(i2c);
+	if (ret)
+		return ret;
+
+	tmp = ioread8(base + VIAI2C_REG_CR);
+	tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END);
+
+	if (num == 1 && msgs->len >= 2 && (priv->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) {
+		/* enable fifo mode */
+		iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable fifo irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR);
+
+		i2c->msg = msgs;
+		i2c->mode = VIAI2C_FIFO_MODE;
+		priv->xfer_len = 0;
+		i2c->xfered_len = 0;
+
+		viai2c_fifo_irq_xfer(i2c, 0);
+
+		if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT))
+			return -ETIMEDOUT;
+
+		ret = i2c->ret;
+	} else {
+		/* enable byte mode */
+		iowrite16(tmp, base + VIAI2C_REG_CR);
+		/* clear irq status */
+		iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR);
+		/* enable byte irq */
+		iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR);
+
+		ret = viai2c_xfer(adap, msgs, num);
+		if (ret == -ETIMEDOUT)
+			iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR);
+	}
+	/* dis interrupt */
+	iowrite8(0, base + VIAI2C_REG_IMR);
+
+	return ret;
+}
+
+static u32 zxi2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm zxi2c_algorithm = {
+	.master_xfer	= zxi2c_master_xfer,
+	.functionality	= zxi2c_func,
+};
+
+static const struct i2c_adapter_quirks zxi2c_quirks = {
+	.flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ,
+};
+
+static const u32 zxi2c_speed_params_table[][3] = {
+	/* speed, ZXI2C_TCR, ZXI2C_FSTP */
+	{ I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K },
+	{ I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K },
+	{ I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M },
+	{ I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST,
+	  ZXI2C_GOLD_FSTP_3400K },
+};
+
+static void zxi2c_set_bus_speed(struct viai2c *i2c)
+{
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+
+	iowrite16(priv->tr, i2c->base + VIAI2C_REG_TR);
+	iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK);
+	iowrite16(priv->mcr, i2c->base + VIAI2C_REG_MCR);
+}
+
+static void zxi2c_get_bus_speed(struct viai2c *i2c)
+{
+	u8 i, count;
+	u8 fstp;
+	const u32 *params;
+	struct viai2c_zhaoxin *priv = i2c->pltfm_priv;
+	u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev);
+
+	count = ARRAY_SIZE(zxi2c_speed_params_table);
+	for (i = 0; i < count; i++)
+		if (acpi_speed == zxi2c_speed_params_table[i][0])
+			break;
+	/* if not found, use 400k as default */
+	i = i < count ? i : 1;
+
+	params = zxi2c_speed_params_table[i];
+	fstp = ioread8(i2c->base + VIAI2C_REG_TR);
+	if (abs(fstp - params[2]) > 0x10) {
+		/*
+		 * if BIOS setting value far from golden value,
+		 * use golden value and warn user
+		 */
+		dev_warn(i2c->dev, "FW FSTP[%x] might cause wrong timings, dropped\n", fstp);
+		priv->tr = params[2] | 0xff00;
+	} else {
+		priv->tr = fstp | 0xff00;
+	}
+
+	i2c->tcr = params[1];
+	priv->mcr = ioread16(i2c->base + VIAI2C_REG_MCR);
+	/* for Hs-mode, use 0x80 as master code */
+	if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ)
+		priv->mcr |= ZXI2C_HS_MASTER_CODE;
+
+	dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0]));
+}
+
+static int zxi2c_probe(struct platform_device *pdev)
+{
+	int error;
+	struct viai2c *i2c;
+	struct i2c_adapter *adap;
+	struct viai2c_zhaoxin *priv;
+
+	error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN);
+	if (error)
+		return error;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+	i2c->pltfm_priv = priv;
+
+	zxi2c_get_bus_speed(i2c);
+	zxi2c_set_bus_speed(i2c);
+
+	priv->hrv = ioread8(i2c->base + ZXI2C_REG_REV);
+
+	adap = &i2c->adapter;
+	adap->owner = THIS_MODULE;
+	adap->algo = &zxi2c_algorithm;
+	adap->quirks = &zxi2c_quirks;
+	adap->dev.parent = &pdev->dev;
+	ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
+	snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s",
+		 dev_name(pdev->dev.parent), dev_name(i2c->dev));
+	i2c_set_adapdata(adap, i2c);
+
+	return devm_i2c_add_adapter(&pdev->dev, adap);
+}
+
+static int __maybe_unused zxi2c_resume(struct device *dev)
+{
+	struct viai2c *i2c = dev_get_drvdata(dev);
+
+	iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR);
+	zxi2c_set_bus_speed(i2c);
+
+	return 0;
+}
+
+static const struct dev_pm_ops zxi2c_pm = {
+	SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume)
+};
+
+static const struct acpi_device_id zxi2c_acpi_match[] = {
+	{"IIC1D17", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match);
+
+static struct platform_driver zxi2c_driver = {
+	.probe = zxi2c_probe,
+	.driver = {
+		.name = "i2c_zhaoxin",
+		.acpi_match_table = zxi2c_acpi_match,
+		.pm = &zxi2c_pm,
+	},
+};
+
+module_platform_driver(zxi2c_driver);
+
+MODULE_AUTHOR("HansHu@zhaoxin.com");
+MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver");
+MODULE_LICENSE("GPL");
-- 
2.34.1


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

* Re: [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init
  2024-04-08  2:54               ` [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
@ 2024-04-23 11:23                 ` Andi Shyti
  0 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-04-23 11:23 UTC (permalink / raw)
  To: Hans Hu; +Cc: linux-i2c, wsa, cobechen, hanshu, Wolfram Sang

Hi Hnas,

...

> @@ -109,7 +109,7 @@ static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
>  	unsigned long wait_result;
>  
>  	wait_result = wait_for_completion_timeout(&i2c_dev->complete,
> -						msecs_to_jiffies(500));
> +						  msecs_to_jiffies(500));

argh!!! This change is not related to this patch.

>  	if (!wait_result)
>  		return -ETIMEDOUT;
>  

...

> @@ -348,18 +370,9 @@ static int wmt_i2c_probe(struct platform_device *pdev)
>  	}
>  
>  	err = of_property_read_u32(np, "clock-frequency", &clk_rate);
> -	if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ))
> +	if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ)

This is not related either.

Andi

>  		i2c_dev->tcr = TCR_FAST_MODE;

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

* Re: [PATCH v10 3/6] i2c: wmt: rename something
  2024-04-08  2:54               ` [PATCH v10 3/6] i2c: wmt: rename something Hans Hu
@ 2024-04-23 11:54                 ` Andi Shyti
  0 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-04-23 11:54 UTC (permalink / raw)
  To: Hans Hu; +Cc: linux-i2c, wsa, cobechen, hanshu, Wolfram Sang

Hi Hans,

On Mon, Apr 08, 2024 at 10:54:45AM +0800, Hans Hu wrote:
> 1. The I2C IP for both wmt and zhaoxin originates from VIA. Rename
>    common registers, functions, and variable names to follow the
>    VIAI2C_ and viai2c_ naming conventions for consistency and clarity.
> 2. rename i2c_dev to i2c, to shorten the length of a line.
> 3. rename wait_result to time_left, make it better to reflect the meaning
>    of the value returned by wait_for_completion_timeout().
> 4. remove TCR_MASTER_WRITE, its value is 0.

next time all the above changes should be on separate patches.

Andi

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

* Re: [PATCH v10 0/6] i2c: add zhaoxin i2c controller driver
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
                                 ` (5 preceding siblings ...)
  2024-04-08  2:54               ` [PATCH v10 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
@ 2024-04-23 12:02               ` Andi Shyti
  2024-04-23 12:16                 ` Hans Hu
  2024-04-29  0:20               ` Andi Shyti
  7 siblings, 1 reply; 133+ messages in thread
From: Andi Shyti @ 2024-04-23 12:02 UTC (permalink / raw)
  To: Hans Hu; +Cc: linux-i2c, wsa, cobechen, hanshu

Hi Hans,

it all looks good, except for that unrelated cleanup you added in
patch '1'.

If you are OK with it, I can take the series and remove the
cleanup.

Please keep in mind that splitting patches in smaller chunks
helps reviews and future bisects, even if the change is a trivial
cosmetic improvement.

Thanks,
Andi

On Mon, Apr 08, 2024 at 10:54:42AM +0800, Hans Hu wrote:
> v9->v10:
> 	* fixed style issues that were checked out by checkpatch.pl.
> 	* In Patch 3 in wmt_i2c_write() function, deleted the log
> 	  when received nack.
> 	* In Patch 4 in viai2c_irq_xfer() function, return 1 for
> 	  I2C_SMBUS_QUICK access.
> 	* In Patch 6 in zxi2c_get_bus_speed() function, adjusted
> 	  the log when firmware gives inappropriate parameters.
> 	Link: https://lore.kernel.org/all/20240306212413.1850236-1-andi.shyti@kernel.org/
> 
> v8->v9:
> 	* In Patch 1 in probe() do not return at the
> 	  i2c_add_adapter(), but call clk_disable_unprepare()
> 	  in case of failure.
> 	* In Patch 2 fix the conflict when i2c-wmt.c is removed.
> 	* In Patch 2 in wmt_i2c_probe() function, call
> 	  clk_disable_unprepare() in case of failure. While at
> 	  it, add a comment to explain the reason.
> 	* When renaming i2c_dev to i2c, change also the reference
> 	  in clk_disable_unprepare().
> 	Link: https://lore.kernel.org/all/20240306212413.1850236-1-andi.shyti@kernel.org/
> 
> v7->v8:
> 	* move per-msg handling to interrupt context
> 	* add private struct viai2c_zhaoxin to handle zhaoxin specific things
> 	* fixed some other formatting issues
> 	Link: https://lore.kernel.org/all/cover.1704440251.git.hanshu-oc@zhaoxin.com/
> 
> v6->v7:
> 	* adjust the patch sequence
> 	* put those renaming related patches in 1 patch file
> 	* rename i2c-*-plt.c to i2c-viai2c-*.c
> 	* Some other adjustments suggested by Andi
> 	For more details, see the comment in each patch please.
> 	Link: https://lore.kernel.org/all/cover.1703830854.git.hanshu-oc@zhaoxin.com/
> 
> v5->v6:
> 	* fix build warnning reported by kernel test robot.
> 	  Link: https://lore.kernel.org/all/202312291225.cWVt6YF9-lkp@intel.com/
> 	Link: https://lore.kernel.org/all/cover.1703733126.git.hanshu-oc@zhaoxin.com/
> 
> v4->v5:
> 	* fix 1 build error.
> 	  Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
> 	Link: https://lore.kernel.org/all/cover.1703647471.git.hanshu-oc@zhaoxin.com/
> 
> v3->v4:
> 	* Some adjustments as suggested by Wolfram.
> 	* rebase patch on top of for-next branch.
> 	Link: https://lore.kernel.org/all/cover.1698889581.git.hanshu-oc@zhaoxin.com/
> 
> v2->v3:
> 	* Split the number of patches from 2 to 12. Make it easier to review.
> 	Link: https://lore.kernel.org/all/cover.1691999569.git.hanshu-oc@zhaoxin.com/
> 
> v1->v2:
> 	* Fixed some bugs I found myself.
> 	Link: https://lore.kernel.org/all/cover.1691030850.git.hanshu-oc@zhaoxin.com/
> 
> Old version:
> 	This patch has already gone through a round of reviews.
> 	The difference from the first round is that it reuses
> 	the i2c-wmt driver.
> 	Link: https://lore.kernel.org/all/20230614094858.317652-1-hanshu-oc@zhaoxin.com/
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> 
> Hans Hu (6):
>   i2c: wmt: create wmt_i2c_init for general init
>   i2c: wmt: split out common files
>   i2c: wmt: rename something
>   i2c: wmt: fix a bug when thread blocked
>   i2c: wmt: add platform type VIAI2C_PLAT_WMT
>   i2c: add zhaoxin i2c controller driver
> 
>  MAINTAINERS                             |  10 +-
>  drivers/i2c/busses/Kconfig              |  10 +
>  drivers/i2c/busses/Makefile             |   3 +
>  drivers/i2c/busses/i2c-viai2c-common.c  | 256 ++++++++++++++
>  drivers/i2c/busses/i2c-viai2c-common.h  |  85 +++++
>  drivers/i2c/busses/i2c-viai2c-wmt.c     | 148 +++++++++
>  drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 298 +++++++++++++++++
>  drivers/i2c/busses/i2c-wmt.c            | 421 ------------------------
>  8 files changed, 809 insertions(+), 422 deletions(-)
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c
>  delete mode 100644 drivers/i2c/busses/i2c-wmt.c
> 
> -- 
> 2.34.1
> 

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

* Re: [PATCH v10 0/6] i2c: add zhaoxin i2c controller driver
  2024-04-23 12:02               ` [PATCH v10 0/6] " Andi Shyti
@ 2024-04-23 12:16                 ` Hans Hu
  0 siblings, 0 replies; 133+ messages in thread
From: Hans Hu @ 2024-04-23 12:16 UTC (permalink / raw)
  To: Andi Shyti; +Cc: linux-i2c, wsa, cobechen, hanshu

Hi Andi,


> Hi Hans,
>
> it all looks good, except for that unrelated cleanup you added in
> patch '1'.
>
> If you are OK with it, I can take the series and remove the
> cleanup.
>
> Please keep in mind that splitting patches in smaller chunks
> helps reviews and future bisects, even if the change is a trivial
> cosmetic improvement.


I'm OK with it.

I have learned a lot from submitting the i2c patch this time,
and I will keep in mind all the suggestions you and others have.

Hans,
Thank you very much!


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

* Re: [PATCH v10 0/6] i2c: add zhaoxin i2c controller driver
  2024-04-08  2:54             ` [PATCH v10 " Hans Hu
                                 ` (6 preceding siblings ...)
  2024-04-23 12:02               ` [PATCH v10 0/6] " Andi Shyti
@ 2024-04-29  0:20               ` Andi Shyti
  7 siblings, 0 replies; 133+ messages in thread
From: Andi Shyti @ 2024-04-29  0:20 UTC (permalink / raw)
  To: Hans Hu; +Cc: linux-i2c, wsa, cobechen, hanshu

Hi Hans,

With the small change I announced in patch 1, I have applied the
patches to i2c/i2c-host on:

git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git

Thank you,
Andi

Patches applied
===============
[1/6] i2c: wmt: create wmt_i2c_init for general init
      commit: 526a34e7cf93806305b9fd91a5ff7a7d17901b9b
[2/6] i2c: wmt: split out common files
      commit: 9743b438b7177178c7783877c5416e845b23c06d
[3/6] i2c: wmt: rename something
      commit: 185df2a0f3c45b477d6833fbc3ac57b8ef336352
[4/6] i2c: wmt: fix a bug when thread blocked
      commit: b538a9ab48414ddae46aec07939c575f8c5b43c2
[5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT
      commit: b28d202ef30163a32e61af4cdbf19dbeded05698
[6/6] i2c: add zhaoxin i2c controller driver
      commit: d103b529c3b75168e79eae8134ade797126a6a98

On Mon, Apr 08, 2024 at 10:54:42AM +0800, Hans Hu wrote:
> v9->v10:
> 	* fixed style issues that were checked out by checkpatch.pl.
> 	* In Patch 3 in wmt_i2c_write() function, deleted the log
> 	  when received nack.
> 	* In Patch 4 in viai2c_irq_xfer() function, return 1 for
> 	  I2C_SMBUS_QUICK access.
> 	* In Patch 6 in zxi2c_get_bus_speed() function, adjusted
> 	  the log when firmware gives inappropriate parameters.
> 	Link: https://lore.kernel.org/all/20240306212413.1850236-1-andi.shyti@kernel.org/
> 
> v8->v9:
> 	* In Patch 1 in probe() do not return at the
> 	  i2c_add_adapter(), but call clk_disable_unprepare()
> 	  in case of failure.
> 	* In Patch 2 fix the conflict when i2c-wmt.c is removed.
> 	* In Patch 2 in wmt_i2c_probe() function, call
> 	  clk_disable_unprepare() in case of failure. While at
> 	  it, add a comment to explain the reason.
> 	* When renaming i2c_dev to i2c, change also the reference
> 	  in clk_disable_unprepare().
> 	Link: https://lore.kernel.org/all/20240306212413.1850236-1-andi.shyti@kernel.org/
> 
> v7->v8:
> 	* move per-msg handling to interrupt context
> 	* add private struct viai2c_zhaoxin to handle zhaoxin specific things
> 	* fixed some other formatting issues
> 	Link: https://lore.kernel.org/all/cover.1704440251.git.hanshu-oc@zhaoxin.com/
> 
> v6->v7:
> 	* adjust the patch sequence
> 	* put those renaming related patches in 1 patch file
> 	* rename i2c-*-plt.c to i2c-viai2c-*.c
> 	* Some other adjustments suggested by Andi
> 	For more details, see the comment in each patch please.
> 	Link: https://lore.kernel.org/all/cover.1703830854.git.hanshu-oc@zhaoxin.com/
> 
> v5->v6:
> 	* fix build warnning reported by kernel test robot.
> 	  Link: https://lore.kernel.org/all/202312291225.cWVt6YF9-lkp@intel.com/
> 	Link: https://lore.kernel.org/all/cover.1703733126.git.hanshu-oc@zhaoxin.com/
> 
> v4->v5:
> 	* fix 1 build error.
> 	  Link: https://lore.kernel.org/all/ZYx0VPVmyQhtG+B9@shikoro/1-a.txt
> 	Link: https://lore.kernel.org/all/cover.1703647471.git.hanshu-oc@zhaoxin.com/
> 
> v3->v4:
> 	* Some adjustments as suggested by Wolfram.
> 	* rebase patch on top of for-next branch.
> 	Link: https://lore.kernel.org/all/cover.1698889581.git.hanshu-oc@zhaoxin.com/
> 
> v2->v3:
> 	* Split the number of patches from 2 to 12. Make it easier to review.
> 	Link: https://lore.kernel.org/all/cover.1691999569.git.hanshu-oc@zhaoxin.com/
> 
> v1->v2:
> 	* Fixed some bugs I found myself.
> 	Link: https://lore.kernel.org/all/cover.1691030850.git.hanshu-oc@zhaoxin.com/
> 
> Old version:
> 	This patch has already gone through a round of reviews.
> 	The difference from the first round is that it reuses
> 	the i2c-wmt driver.
> 	Link: https://lore.kernel.org/all/20230614094858.317652-1-hanshu-oc@zhaoxin.com/
> 
> Signed-off-by: Hans Hu <hanshu-oc@zhaoxin.com>
> 
> Hans Hu (6):
>   i2c: wmt: create wmt_i2c_init for general init
>   i2c: wmt: split out common files
>   i2c: wmt: rename something
>   i2c: wmt: fix a bug when thread blocked
>   i2c: wmt: add platform type VIAI2C_PLAT_WMT
>   i2c: add zhaoxin i2c controller driver
> 
>  MAINTAINERS                             |  10 +-
>  drivers/i2c/busses/Kconfig              |  10 +
>  drivers/i2c/busses/Makefile             |   3 +
>  drivers/i2c/busses/i2c-viai2c-common.c  | 256 ++++++++++++++
>  drivers/i2c/busses/i2c-viai2c-common.h  |  85 +++++
>  drivers/i2c/busses/i2c-viai2c-wmt.c     | 148 +++++++++
>  drivers/i2c/busses/i2c-viai2c-zhaoxin.c | 298 +++++++++++++++++
>  drivers/i2c/busses/i2c-wmt.c            | 421 ------------------------
>  8 files changed, 809 insertions(+), 422 deletions(-)
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-common.c
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-common.h
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-wmt.c
>  create mode 100644 drivers/i2c/busses/i2c-viai2c-zhaoxin.c
>  delete mode 100644 drivers/i2c/busses/i2c-wmt.c
> 
> -- 
> 2.34.1
> 

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

end of thread, other threads:[~2024-04-29  0:20 UTC | newest]

Thread overview: 133+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-02  2:53 [PATCH v3 00/12] i2c: add zhaoxin i2c controller driver Hans Hu
2023-11-02  2:53 ` [PATCH v3 01/12] i2c: wmt: Reduce redundant: bus busy check Hans Hu
2023-12-22  9:33   ` Wolfram Sang
2023-11-02  2:53 ` [PATCH v3 02/12] i2c: wmt: Reduce redundant: wait event complete Hans Hu
2023-12-22  9:34   ` Wolfram Sang
2023-11-02  2:53 ` [PATCH v3 03/12] i2c: wmt: Reduce redundant: clock mode setting Hans Hu
2023-12-22  9:36   ` Wolfram Sang
2023-11-02  2:53 ` [PATCH v3 04/12] i2c: wmt: Reduce redundant: REG_CR setting Hans Hu
2023-12-22  9:38   ` Wolfram Sang
2023-12-22 10:15     ` Wolfram Sang
2023-11-02  2:53 ` [PATCH v3 05/12] i2c: wmt: Reduce redundant: function parameter Hans Hu
2023-12-22  9:48   ` Wolfram Sang
2023-11-02  2:53 ` [PATCH v3 06/12] i2c: wmt: delete .remove_new Hans Hu
2023-12-22  9:51   ` Wolfram Sang
2023-11-02  2:53 ` [PATCH v3 07/12] i2c: wmt: create wmt_i2c_init for general init Hans Hu
2023-12-22 10:26   ` Wolfram Sang
2023-12-22 10:55     ` Hans Hu
2023-12-22 11:00       ` Wolfram Sang
2023-11-02  2:53 ` [PATCH v3 08/12] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
2023-11-02  2:53 ` [PATCH v3 09/12] i2c: wmt: adjust line length to meet style Hans Hu
2023-11-02  2:54 ` [PATCH v3 10/12] i2c: wmt: split out common files Hans Hu
2023-11-02  2:54 ` [PATCH v3 11/12] i2c: via-common: add zhaoxin platform Hans Hu
2023-11-02  2:54 ` [PATCH v3 12/12] i2c: add zhaoxin i2c controller driver Hans Hu
2023-11-08  9:50 ` [PATCH v3 00/12] " Wolfram Sang
2023-12-27  4:39 ` [PATCH v4 0/8] " Hans Hu
2023-12-27  4:39   ` [PATCH v4 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
2023-12-27 19:00     ` Wolfram Sang
2023-12-28  2:05       ` Hans Hu
2023-12-27  4:39   ` [PATCH v4 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
2023-12-27  4:39   ` [PATCH v4 3/8] i2c: wmt: adjust line length to meet style Hans Hu
2023-12-27  4:39   ` [PATCH v4 4/8] i2c: wmt: split out common files Hans Hu
2023-12-27  4:39   ` [PATCH v4 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
2023-12-27  4:39   ` [PATCH v4 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
2023-12-27  4:39   ` [PATCH v4 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
2023-12-27  4:39   ` [PATCH v4 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
2023-12-28  3:17   ` [PATCH v5 0/8] " Hans Hu
2023-12-28  3:17     ` [PATCH v5 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
2023-12-28  3:17     ` [PATCH v5 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
2023-12-28  3:17     ` [PATCH v5 3/8] i2c: wmt: adjust line length to meet style Hans Hu
2023-12-28  3:17     ` [PATCH v5 4/8] i2c: wmt: split out common files Hans Hu
2023-12-28  3:17     ` [PATCH v5 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
2023-12-28  3:17     ` [PATCH v5 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
2023-12-28  3:17     ` [PATCH v5 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
2023-12-28  3:17     ` [PATCH v5 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
2023-12-29  5:17       ` kernel test robot
2023-12-29  6:30     ` [PATCH v6 0/8] " Hans Hu
2023-12-29  6:30       ` [PATCH v6 1/8] i2c: wmt: create wmt_i2c_init for general init Hans Hu
2024-01-03 12:56         ` Andi Shyti
2024-01-04  1:44           ` Hans Hu
2023-12-29  6:30       ` [PATCH v6 2/8] i2c: wmt: rename marcos with prefix WMTI2C_ Hans Hu
2024-01-03 13:29         ` Andi Shyti
2023-12-29  6:30       ` [PATCH v6 3/8] i2c: wmt: adjust line length to meet style Hans Hu
2024-01-03 16:52         ` Andi Shyti
2024-01-04  1:49           ` Hans Hu
2023-12-29  6:30       ` [PATCH v6 4/8] i2c: wmt: split out common files Hans Hu
2024-01-03 17:21         ` Andi Shyti
2024-01-04  2:04           ` Hans Hu
2024-01-04  9:22             ` Andi Shyti
2024-01-04  9:45               ` Hans Hu
2024-01-04 12:36                 ` Andi Shyti
2023-12-29  6:30       ` [PATCH v6 5/8] i2c: wmt: rename with prefix VIAI2C_ and viai2c_ Hans Hu
2024-01-03 18:45         ` Andi Shyti
2024-01-04  2:12           ` Hans Hu
2023-12-29  6:30       ` [PATCH v6 6/8] i2c: wmt: fix a bug when thread blocked Hans Hu
2024-01-03 19:39         ` Andi Shyti
2024-01-04  2:30           ` Hans Hu
2024-01-04  9:18             ` Andi Shyti
2024-01-04 10:02               ` Hans Hu
2024-01-04 12:37                 ` Andi Shyti
2023-12-29  6:30       ` [PATCH v6 7/8] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
2023-12-29  6:30       ` [PATCH v6 8/8] i2c: add zhaoxin i2c controller driver Hans Hu
2024-01-03 20:02         ` Andi Shyti
2024-01-04  2:40           ` Hans Hu
2024-01-03 20:03       ` [PATCH v6 0/8] " Andi Shyti
2024-01-05  7:51       ` [PATCH v7 0/6] " Hans Hu
2024-01-05  7:51         ` [PATCH v7 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
2024-01-15 15:17           ` Krzysztof Kozlowski
2024-01-16  1:43             ` Hans Hu
2024-01-21 23:56               ` Andi Shyti
2024-02-21 12:10           ` Wolfram Sang
2024-01-05  7:51         ` [PATCH v7 2/6] i2c: wmt: split out common files Hans Hu
2024-02-21 12:19           ` Wolfram Sang
2024-01-05  7:51         ` [PATCH v7 3/6] i2c: wmt: rename something Hans Hu
2024-02-21 12:34           ` Wolfram Sang
2024-01-05  7:51         ` [PATCH v7 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
2024-02-21 12:37           ` Wolfram Sang
2024-02-22  9:03             ` Hans Hu
2024-02-22  9:37               ` Wolfram Sang
2024-02-22 10:42                 ` Hans Hu
2024-02-22 17:26                   ` Wolfram Sang
2024-01-05  7:51         ` [PATCH v7 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
2024-02-21 12:39           ` Wolfram Sang
2024-02-22  8:50             ` Hans Hu
2024-01-05  7:51         ` [PATCH v7 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
2024-02-21 12:44           ` Wolfram Sang
2024-02-22  8:49             ` Hans Hu
2024-02-27  6:36         ` [PATCH v8 0/6] " Hans Hu
2024-02-27  6:36           ` [PATCH v8 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
2024-02-27  6:36           ` [PATCH v8 2/6] i2c: wmt: split out common files Hans Hu
2024-02-27  6:36           ` [PATCH v8 3/6] i2c: wmt: rename something Hans Hu
2024-02-27  6:36           ` [PATCH v8 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
2024-03-04  9:41             ` Wolfram Sang
2024-02-27  6:36           ` [PATCH v8 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
2024-03-04  9:46             ` Wolfram Sang
2024-02-27  6:36           ` [PATCH v8 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
2024-03-04  9:49             ` Wolfram Sang
2024-03-04 23:01               ` [SPAM] " Andi Shyti
2024-03-05  2:45                 ` Hans Hu
2024-03-06 11:50                   ` Andi Shyti
2024-03-06 16:54                   ` Wolfram Sang
2024-03-06 21:24           ` [PATCH v9 0/6] " Andi Shyti
2024-03-06 21:24             ` [PATCH v9 1/6] i2c: wmt: create wmt_i2c_init for general init Andi Shyti
2024-03-06 21:24             ` [PATCH v9 2/6] i2c: wmt: split out common files Andi Shyti
2024-03-06 21:24             ` [PATCH v9 3/6] i2c: wmt: rename something Andi Shyti
2024-03-06 21:24             ` [PATCH v9 4/6] i2c: wmt: fix a bug when thread blocked Andi Shyti
2024-03-06 21:24             ` [PATCH v9 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Andi Shyti
2024-03-06 21:24             ` [PATCH v9 6/6] i2c: add zhaoxin i2c controller driver Andi Shyti
2024-03-08  1:22             ` [PATCH v9 0/6] " Hans Hu
2024-03-08 12:30               ` Andi Shyti
2024-04-03 23:29               ` Andi Shyti
2024-04-07  1:36                 ` Hans Hu
2024-04-08  2:54             ` [PATCH v10 " Hans Hu
2024-04-08  2:54               ` [PATCH v10 1/6] i2c: wmt: create wmt_i2c_init for general init Hans Hu
2024-04-23 11:23                 ` Andi Shyti
2024-04-08  2:54               ` [PATCH v10 2/6] i2c: wmt: split out common files Hans Hu
2024-04-08  2:54               ` [PATCH v10 3/6] i2c: wmt: rename something Hans Hu
2024-04-23 11:54                 ` Andi Shyti
2024-04-08  2:54               ` [PATCH v10 4/6] i2c: wmt: fix a bug when thread blocked Hans Hu
2024-04-08  2:54               ` [PATCH v10 5/6] i2c: wmt: add platform type VIAI2C_PLAT_WMT Hans Hu
2024-04-08  2:54               ` [PATCH v10 6/6] i2c: add zhaoxin i2c controller driver Hans Hu
2024-04-23 12:02               ` [PATCH v10 0/6] " Andi Shyti
2024-04-23 12:16                 ` Hans Hu
2024-04-29  0:20               ` Andi Shyti

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).