Linux I2C development
 help / color / mirror / Atom feed
* [PATCH v2 3/8] i2c: bcm2835: Use ratelimited logging on transfer errors
From: Noralf Trønnes @ 2016-09-27 11:57 UTC (permalink / raw)
  To: wsa, swarren, eric
  Cc: linux-kernel, linux-i2c, linux-arm-kernel, linux-rpi-kernel,
	Noralf Trønnes
In-Reply-To: <1474977426-3272-1-git-send-email-noralf@tronnes.org>

Writing to an AT24C32 generates on average 2x i2c transfer errors per
32-byte page write. Which amounts to a lot for a 4k write. This is due
to the fact that the chip doesn't respond during it's internal write
cycle when the at24 driver tries and retries the next write.
Reduce this flooding of the log by using dev_err_ratelimited().

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
---
 drivers/i2c/busses/i2c-bcm2835.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index df036ed..370a322 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -207,7 +207,8 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
 	    (msg->flags & I2C_M_IGNORE_NAK))
 		return 0;
 
-	dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err);
+	dev_err_ratelimited(i2c_dev->dev, "i2c transfer failed: %x\n",
+			    i2c_dev->msg_err);
 
 	if (i2c_dev->msg_err & BCM2835_I2C_S_ERR)
 		return -EREMOTEIO;
-- 
2.8.2

^ permalink raw reply related

* [PATCH v2 4/8] i2c: bcm2835: Can't support I2C_M_IGNORE_NAK
From: Noralf Trønnes @ 2016-09-27 11:57 UTC (permalink / raw)
  To: wsa, swarren, eric
  Cc: linux-kernel, linux-i2c, linux-arm-kernel, linux-rpi-kernel,
	Noralf Trønnes
In-Reply-To: <1474977426-3272-1-git-send-email-noralf@tronnes.org>

The controller can't support this flag, so remove it.

Documentation/i2c/i2c-protocol states that all of the message is sent:

I2C_M_IGNORE_NAK:
    Normally message is interrupted immediately if there is [NA] from the
    client. Setting this flag treats any [NA] as [A], and all of
    message is sent.

>From the BCM2835 ARM Peripherals datasheet:

    The ERR field is set when the slave fails to acknowledge either
    its address or a data byte written to it.

So when the controller doesn't receive an ack, it sets ERR and raises
an interrupt. In other words, the whole message is not sent.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/i2c/busses/i2c-bcm2835.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 370a322..4e08add 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -203,10 +203,6 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
 	if (likely(!i2c_dev->msg_err))
 		return 0;
 
-	if ((i2c_dev->msg_err & BCM2835_I2C_S_ERR) &&
-	    (msg->flags & I2C_M_IGNORE_NAK))
-		return 0;
-
 	dev_err_ratelimited(i2c_dev->dev, "i2c transfer failed: %x\n",
 			    i2c_dev->msg_err);
 
-- 
2.8.2

^ permalink raw reply related

* [PATCH v2 0/8] i2c: bcm2835: Bring in changes from downstream
From: Noralf Trønnes @ 2016-09-27 11:56 UTC (permalink / raw)
  To: wsa, swarren, eric
  Cc: linux-kernel, linux-i2c, linux-arm-kernel, linux-rpi-kernel,
	Noralf Trønnes

This patchset tries to bring in the lessons learned in the downstream
driver i2c-bcm2708. The downstream clock stretcing timeout patch has
been left out since clock stretching is broken/unreliable on this
controller, so no point in setting it.

This second version of the patchset has been expanded to try and
encompass all the differences between mainline and downstream.
Hopefully downstream can now start using this driver.

Thanks to Martin for jogging my memory with his comments which led to
the discovery that interrupt could be used instead of polling for the
Transfer Active state.

Noralf.


Noralf Trønnes (8):
  i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
  i2c: bcm2835: Protect against unexpected TXW/RXR interrupts
  i2c: bcm2835: Use ratelimited logging on transfer errors
  i2c: bcm2835: Can't support I2C_M_IGNORE_NAK
  i2c: bcm2835: Add support for Repeated Start Condition
  i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT
  i2c: bcm2835: Add support for dynamic clock
  ARM: bcm2835: Disable i2c2 in the Device Tree

 arch/arm/boot/dts/bcm2835-rpi.dtsi |   4 -
 drivers/i2c/busses/i2c-bcm2835.c   | 210 +++++++++++++++++++++++--------------
 2 files changed, 131 insertions(+), 83 deletions(-)

--
2.8.2

^ permalink raw reply

* [PATCH v2 8/8] ARM: bcm2835: Disable i2c2 in the Device Tree
From: Noralf Trønnes @ 2016-09-27 11:57 UTC (permalink / raw)
  To: wsa, swarren, eric
  Cc: linux-rpi-kernel, Noralf Trønnes, linux-kernel,
	linux-arm-kernel, linux-i2c
In-Reply-To: <1474977426-3272-1-git-send-email-noralf@tronnes.org>

i2c2 is connected to the HDMI connector and is controlled by the
firmware. Disable it to stay out of harms way.

From the downstream commit:
i2c-bcm2708/BCM270X_DT: Add support for I2C2

The third I2C bus (I2C2) is normally reserved for HDMI use. Careless
use of this bus can break an attached display - use with caution.

It is recommended to disable accesses by VideoCore by setting
hdmi_ignore_edid=1 or hdmi_edid_file=1 in config.txt.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index e9b47b2..8bffbee 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -59,10 +59,6 @@
 	clock-frequency = <100000>;
 };
 
-&i2c2 {
-	status = "okay";
-};
-
 &sdhci {
 	status = "okay";
 	bus-width = <4>;
-- 
2.8.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v2 6/8] i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT
From: Noralf Trønnes @ 2016-09-27 11:57 UTC (permalink / raw)
  To: wsa, swarren, eric
  Cc: linux-rpi-kernel, Noralf Trønnes, linux-kernel,
	linux-arm-kernel, linux-i2c
In-Reply-To: <1474977426-3272-1-git-send-email-noralf@tronnes.org>

Use i2c_adapter->timeout for the completion timeout value. The core
default is 1 second.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/i2c/busses/i2c-bcm2835.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index f3a1472..79dd15f 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -53,8 +53,6 @@
 #define BCM2835_I2C_CDIV_MIN	0x0002
 #define BCM2835_I2C_CDIV_MAX	0xFFFE
 
-#define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000))
-
 struct bcm2835_i2c_dev {
 	struct device *dev;
 	void __iomem *regs;
@@ -233,7 +231,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
 	bcm2835_i2c_start_transfer(i2c_dev);
 
 	time_left = wait_for_completion_timeout(&i2c_dev->completion,
-						BCM2835_I2C_TIMEOUT);
+						adap->timeout);
 	if (!time_left) {
 		bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
 				   BCM2835_I2C_C_CLEAR);
-- 
2.8.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v2 2/8] i2c: bcm2835: Protect against unexpected TXW/RXR interrupts
From: Noralf Trønnes @ 2016-09-27 11:57 UTC (permalink / raw)
  To: wsa, swarren, eric
  Cc: linux-kernel, linux-i2c, linux-arm-kernel, linux-rpi-kernel,
	Noralf Trønnes
In-Reply-To: <1474977426-3272-1-git-send-email-noralf@tronnes.org>

If an unexpected TXW or RXR interrupt occurs (msg_buf_remaining == 0),
the driver has no way to fill/drain the FIFO to stop the interrupts.
In this case the controller has to be disabled and the transfer
completed to avoid hang.

(CLKT | ERR) and DONE interrupts are completed in their own paths, and
the controller is disabled in the transfer function after completion.
Unite the code paths and do disabling inside the interrupt routine.

Clear interrupt status bits in the united completion path instead of
trying to do it on every interrupt which isn't necessary.
Only CLKT, ERR and DONE can be cleared that way.

Add the status value to the error value in case of TXW/RXR errors to
distinguish them from the other S_LEN error.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
 drivers/i2c/busses/i2c-bcm2835.c | 31 ++++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index f283b71..df036ed 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -50,8 +50,6 @@
 #define BCM2835_I2C_S_CLKT	BIT(9)
 #define BCM2835_I2C_S_LEN	BIT(10) /* Fake bit for SW error reporting */
 
-#define BCM2835_I2C_BITMSK_S	0x03FF
-
 #define BCM2835_I2C_CDIV_MIN	0x0002
 #define BCM2835_I2C_CDIV_MAX	0xFFFE
 
@@ -117,14 +115,11 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
 	u32 val, err;
 
 	val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
-	val &= BCM2835_I2C_BITMSK_S;
-	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val);
 
 	err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR);
 	if (err) {
 		i2c_dev->msg_err = err;
-		complete(&i2c_dev->completion);
-		return IRQ_HANDLED;
+		goto complete;
 	}
 
 	if (val & BCM2835_I2C_S_DONE) {
@@ -137,21 +132,38 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
 			i2c_dev->msg_err = BCM2835_I2C_S_LEN;
 		else
 			i2c_dev->msg_err = 0;
-		complete(&i2c_dev->completion);
-		return IRQ_HANDLED;
+		goto complete;
 	}
 
 	if (val & BCM2835_I2C_S_TXW) {
+		if (!i2c_dev->msg_buf_remaining) {
+			i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
+			goto complete;
+		}
+
 		bcm2835_fill_txfifo(i2c_dev);
 		return IRQ_HANDLED;
 	}
 
 	if (val & BCM2835_I2C_S_RXR) {
+		if (!i2c_dev->msg_buf_remaining) {
+			i2c_dev->msg_err = val | BCM2835_I2C_S_LEN;
+			goto complete;
+		}
+
 		bcm2835_drain_rxfifo(i2c_dev);
 		return IRQ_HANDLED;
 	}
 
 	return IRQ_NONE;
+
+complete:
+	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
+	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT |
+			   BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE);
+	complete(&i2c_dev->completion);
+
+	return IRQ_HANDLED;
 }
 
 static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
@@ -181,8 +193,9 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
 
 	time_left = wait_for_completion_timeout(&i2c_dev->completion,
 						BCM2835_I2C_TIMEOUT);
-	bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR);
 	if (!time_left) {
+		bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C,
+				   BCM2835_I2C_C_CLEAR);
 		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
 		return -ETIMEDOUT;
 	}
-- 
2.8.2

^ permalink raw reply related

* [PATCH v2 1/8] i2c: bcm2835: Fix hang for writing messages larger than 16 bytes
From: Noralf Trønnes @ 2016-09-27 11:56 UTC (permalink / raw)
  To: wsa, swarren, eric
  Cc: linux-rpi-kernel, Noralf Trønnes, linux-kernel,
	linux-arm-kernel, linux-i2c
In-Reply-To: <1474977426-3272-1-git-send-email-noralf@tronnes.org>

Writing messages larger than the FIFO size results in a hang, rendering
the machine unusable. This is because the RXD status flag is set on the
first interrupt which results in bcm2835_drain_rxfifo() stealing bytes
from the buffer. The controller continues to trigger interrupts waiting
for the missing bytes, but bcm2835_fill_txfifo() has none to give.
In this situation wait_for_completion_timeout() apparently is unable to
stop the madness.

The BCM2835 ARM Peripherals datasheet has this to say about the flags:
  TXD: is set when the FIFO has space for at least one byte of data.
  RXD: is set when the FIFO contains at least one byte of data.
  TXW: is set during a write transfer and the FIFO is less than full.
  RXR: is set during a read transfer and the FIFO is or more full.

Implementing the logic from the downstream i2c-bcm2708 driver solved
the hang problem.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Martin Sperl <kernel@martin.sperl.org>
---
 drivers/i2c/busses/i2c-bcm2835.c | 22 ++++++++++++++--------
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index d4f3239..f283b71 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -64,6 +64,7 @@ struct bcm2835_i2c_dev {
 	int irq;
 	struct i2c_adapter adapter;
 	struct completion completion;
+	struct i2c_msg *curr_msg;
 	u32 msg_err;
 	u8 *msg_buf;
 	size_t msg_buf_remaining;
@@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
 		return IRQ_HANDLED;
 	}
 
-	if (val & BCM2835_I2C_S_RXD) {
-		bcm2835_drain_rxfifo(i2c_dev);
-		if (!(val & BCM2835_I2C_S_DONE))
-			return IRQ_HANDLED;
-	}
-
 	if (val & BCM2835_I2C_S_DONE) {
-		if (i2c_dev->msg_buf_remaining)
+		if (i2c_dev->curr_msg->flags & I2C_M_RD) {
+			bcm2835_drain_rxfifo(i2c_dev);
+			val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
+		}
+
+		if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining)
 			i2c_dev->msg_err = BCM2835_I2C_S_LEN;
 		else
 			i2c_dev->msg_err = 0;
@@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
 		return IRQ_HANDLED;
 	}
 
-	if (val & BCM2835_I2C_S_TXD) {
+	if (val & BCM2835_I2C_S_TXW) {
 		bcm2835_fill_txfifo(i2c_dev);
 		return IRQ_HANDLED;
 	}
 
+	if (val & BCM2835_I2C_S_RXR) {
+		bcm2835_drain_rxfifo(i2c_dev);
+		return IRQ_HANDLED;
+	}
+
 	return IRQ_NONE;
 }
 
@@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
 	u32 c;
 	unsigned long time_left;
 
+	i2c_dev->curr_msg = msg;
 	i2c_dev->msg_buf = msg->buf;
 	i2c_dev->msg_buf_remaining = msg->len;
 	reinit_completion(&i2c_dev->completion);
-- 
2.8.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v4] i2c: hibvt: add Hisilicon BVT I2C controller driver
From: Pan Wen @ 2016-09-27  6:51 UTC (permalink / raw)
  To: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	howell.yang-C8/M+/jPZTeaMJb+Lgu22Q,
	xuejiancheng-C8/M+/jPZTeaMJb+Lgu22Q,
	jalen.hsu-C8/M+/jPZTeaMJb+Lgu22Q,
	lvkuanliang-C8/M+/jPZTeaMJb+Lgu22Q,
	suwenping-C8/M+/jPZTeaMJb+Lgu22Q, raojun-C8/M+/jPZTeaMJb+Lgu22Q,
	kevin.lixu-C8/M+/jPZTeaMJb+Lgu22Q, wenpan-C8/M+/jPZTeaMJb+Lgu22Q

add Hisilicon BVT I2C controller driver support.

Signed-off-by: Pan Wen <wenpan-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
---
change log
v4:
Modify the default frequency to 100KHz.
v3:
Add a SoC specific compatible string.
v2:
1)Fixed a compile error.
2)Dropped the clock-names property.
 .../devicetree/bindings/i2c/i2c-hibvt.txt          |  24 +
 drivers/i2c/busses/Kconfig                         |  10 +
 drivers/i2c/busses/Makefile                        |   1 +
 drivers/i2c/busses/i2c-hibvt.c                     | 737 +++++++++++++++++++++
 4 files changed, 772 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hibvt.txt
 create mode 100644 drivers/i2c/busses/i2c-hibvt.c

diff --git a/Documentation/devicetree/bindings/i2c/i2c-hibvt.txt b/Documentation/devicetree/bindings/i2c/i2c-hibvt.txt
new file mode 100644
index 0000000..db3d2e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-hibvt.txt
@@ -0,0 +1,24 @@
+Hisilicon BVT I2C master controller
+
+Required properties:
+- compatible: should be "hisilicon,hibvt-i2c" and one of the following:
+	"hisilicon,hi3516cv300-i2c"
+- reg: physical base address of the controller and length of memory mapped.
+     region.
+- interrupts: interrupt number to the cpu.
+- clocks: phandles to input clocks.
+
+Optional properties:
+- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000.
+
+Other properties:
+see Documentation/devicetree/bindings/i2c/i2c.txt.
+
+Examples:
+i2c_bus0: i2c@12110000 {
+	compatible = "hisilicon,hi3516cv300-i2c", "hisilicon,hibvt-i2c";
+	reg = <0x12110000 0x100>;
+	interrupts = <20>;
+	clocks = <&crg_ctrl HI3516CV300_APB_CLK>;
+	clock-frequency = <100000>;
+};
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5c3993b..fc1b679 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -555,6 +555,16 @@ config I2C_GPIO
 	  This is a very simple bitbanging I2C driver utilizing the
 	  arch-neutral GPIO API to control the SCL and SDA lines.
 
+config I2C_HIBVT
+	tristate "Hisilicon BVT I2C Controller"
+	depends on ARCH_HISI
+	help
+	  Say Y here to include support for Hisilicon BVT I2C controller in the
+	  Hisilicon BVT SoCs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-hibvt.
+
 config I2C_HIGHLANDER
 	tristate "Highlander FPGA SMBus interface"
 	depends on SH_HIGHLANDER
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 37f2819..42ef2e0 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_I2C_EG20T)		+= i2c-eg20t.o
 obj-$(CONFIG_I2C_EMEV2)		+= i2c-emev2.o
 obj-$(CONFIG_I2C_EXYNOS5)	+= i2c-exynos5.o
 obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
+obj-$(CONFIG_I2C_HIBVT)		+= i2c-hibvt.o
 obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
 obj-$(CONFIG_I2C_HIX5HD2)	+= i2c-hix5hd2.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
diff --git a/drivers/i2c/busses/i2c-hibvt.c b/drivers/i2c/busses/i2c-hibvt.c
new file mode 100644
index 0000000..e8af63e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-hibvt.c
@@ -0,0 +1,737 @@
+/*
+ * Hisilicon BVT I2C Controller Driver
+ *
+ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd.
+ *
+ * Authors: wenpan-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+/*
+ * I2C Registers offsets
+ */
+#define HIBVT_I2C_GLB		0x0
+#define HIBVT_I2C_SCL_H		0x4
+#define HIBVT_I2C_SCL_L		0x8
+#define HIBVT_I2C_DATA1		0x10
+#define HIBVT_I2C_TXF		0x20
+#define HIBVT_I2C_RXF		0x24
+#define HIBVT_I2C_CMD_BASE	0x30
+#define HIBVT_I2C_LOOP1		0xb0
+#define HIBVT_I2C_DST1		0xb4
+#define HIBVT_I2C_TX_WATER	0xc8
+#define HIBVT_I2C_RX_WATER	0xcc
+#define HIBVT_I2C_CTRL1		0xd0
+#define HIBVT_I2C_STAT		0xd8
+#define HIBVT_I2C_INTR_RAW	0xe0
+#define HIBVT_I2C_INTR_EN	0xe4
+#define HIBVT_I2C_INTR_STAT	0xe8
+
+/*
+ * I2C Global Config Register -- HIBVT_I2C_GLB
+ */
+#define GLB_EN_MASK		BIT(0)
+#define GLB_SDA_HOLD_MASK	GENMASK(23, 8)
+#define GLB_SDA_HOLD_SHIFT	(8)
+
+/*
+ * I2C Timing CMD Register -- HIBVT_I2C_CMD_BASE + n * 4 (n = 0, 1, 2, ... 31)
+ */
+#define CMD_EXIT	0x0
+#define CMD_TX_S	0x1
+#define CMD_TX_D1_2	0x4
+#define CMD_TX_D1_1	0x5
+#define CMD_TX_FIFO	0x9
+#define CMD_RX_FIFO	0x12
+#define CMD_RX_ACK	0x13
+#define CMD_IGN_ACK	0x15
+#define CMD_TX_ACK	0x16
+#define CMD_TX_NACK	0x17
+#define CMD_JMP1	0x18
+#define CMD_UP_TXF	0x1d
+#define CMD_TX_RS	0x1e
+#define CMD_TX_P	0x1f
+
+/*
+ * I2C Control Register 1 -- HIBVT_I2C_CTRL1
+ */
+#define CTRL1_CMD_START_MASK	BIT(0)
+
+/*
+ * I2C Status Register -- HIBVT_I2C_STAT
+ */
+#define STAT_RXF_NOE_MASK	BIT(16) /* RX FIFO not empty flag */
+#define STAT_TXF_NOF_MASK	BIT(19) /* TX FIFO not full flag */
+
+
+/*
+ * I2C Interrupt status and mask Register --
+ * HIBVT_I2C_INTR_RAW, HIBVT_I2C_STAT, HIBVT_I2C_INTR_STAT
+ */
+#define INTR_ABORT_MASK		(BIT(0) | BIT(11))
+#define INTR_RX_MASK		BIT(2)
+#define INTR_TX_MASK		BIT(4)
+#define INTR_CMD_DONE_MASK	BIT(12)
+#define INTR_USE_MASK		(INTR_ABORT_MASK \
+				|INTR_RX_MASK \
+				| INTR_TX_MASK \
+				| INTR_CMD_DONE_MASK)
+#define INTR_ALL_MASK		GENMASK(31, 0)
+
+#define I2C_DEFAULT_FREQUENCY	100000
+#define I2C_TXF_DEPTH		64
+#define I2C_RXF_DEPTH		64
+#define I2C_TXF_WATER		32
+#define I2C_RXF_WATER		32
+#define I2C_WAIT_TIMEOUT	0x10000
+#define I2C_IRQ_TIMEOUT		(msecs_to_jiffies(1000))
+
+
+struct hibvt_i2c_dev {
+	struct device		*dev;
+	struct i2c_adapter	adap;
+	void __iomem		*base;
+	struct clk		*clk;
+	int			irq;
+
+	unsigned int		freq;
+	struct i2c_msg		*msg;
+	unsigned int		msg_num;
+	unsigned int		msg_idx;
+	unsigned int		msg_buf_ptr;
+	struct completion	msg_complete;
+
+	spinlock_t		lock;
+	int			status;
+};
+
+static inline void hibvt_i2c_disable(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int val;
+
+	val = readl(i2c->base + HIBVT_I2C_GLB);
+	val &= ~GLB_EN_MASK;
+	writel(val, i2c->base + HIBVT_I2C_GLB);
+}
+
+static inline void hibvt_i2c_enable(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int val;
+
+	val = readl(i2c->base + HIBVT_I2C_GLB);
+	val |= GLB_EN_MASK;
+	writel(val, i2c->base + HIBVT_I2C_GLB);
+}
+
+static inline void hibvt_i2c_cfg_irq(struct hibvt_i2c_dev *i2c,
+		unsigned int flag)
+{
+	writel(flag, i2c->base + HIBVT_I2C_INTR_EN);
+}
+
+static inline void hibvt_i2c_disable_irq(struct hibvt_i2c_dev *i2c,
+		unsigned int flag)
+{
+	unsigned int val;
+
+	val = readl(i2c->base + HIBVT_I2C_INTR_EN);
+	val &= ~flag;
+	writel(val, i2c->base + HIBVT_I2C_INTR_EN);
+}
+
+static inline unsigned int hibvt_i2c_clr_irq(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int val;
+
+	val = readl(i2c->base + HIBVT_I2C_INTR_STAT);
+	writel(INTR_ALL_MASK, i2c->base + HIBVT_I2C_INTR_RAW);
+
+	return val;
+}
+
+static inline void hibvt_i2c_cmdreg_set(struct hibvt_i2c_dev *i2c,
+		unsigned int cmd, unsigned int *offset)
+{
+	dev_dbg(i2c->dev, "hii2c reg: offset=0x%x, cmd=0x%x...\n",
+			*offset * 4, cmd);
+	writel(cmd, i2c->base + HIBVT_I2C_CMD_BASE + *offset * 4);
+	(*offset)++;
+}
+
+/*
+ * config i2c slave addr
+ */
+static inline void hibvt_i2c_set_addr(struct hibvt_i2c_dev *i2c)
+{
+	struct i2c_msg *msg = i2c->msg;
+	u16 addr;
+
+	if (msg->flags & I2C_M_TEN) {
+		/* First byte is 11110XX0 where XX is upper 2 bits */
+		addr = ((msg->addr & 0x300) << 1) | 0xf000;
+		if (msg->flags & I2C_M_RD)
+			addr |= 1 << 8;
+
+		/* Second byte is the remaining 8 bits */
+		addr |= msg->addr & 0xff;
+	} else {
+		addr = (msg->addr & 0x7f) << 1;
+		if (msg->flags & I2C_M_RD)
+			addr |= 1;
+	}
+
+	writel(addr, i2c->base + HIBVT_I2C_DATA1);
+}
+
+/*
+ * Start command sequence
+ */
+static inline void hibvt_i2c_start_cmd(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int val;
+
+	val = readl(i2c->base + HIBVT_I2C_CTRL1);
+	val |= CTRL1_CMD_START_MASK;
+	writel(val, i2c->base + HIBVT_I2C_CTRL1);
+}
+
+static int hibvt_i2c_wait_rx_noempty(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int time_cnt = 0;
+	unsigned int val;
+
+	do {
+		val = readl(i2c->base + HIBVT_I2C_STAT);
+		if (val & STAT_RXF_NOE_MASK)
+			return 0;
+
+		udelay(50);
+	} while (time_cnt++ < I2C_WAIT_TIMEOUT);
+
+	dev_err(i2c->dev, "wait rx no empty timeout, RIS: 0x%x, SR: 0x%x\n",
+			readl(i2c->base + HIBVT_I2C_INTR_RAW), val);
+	return -EIO;
+}
+
+static int hibvt_i2c_wait_tx_nofull(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int time_cnt = 0;
+	unsigned int val;
+
+	do {
+		val = readl(i2c->base + HIBVT_I2C_STAT);
+		if (val & STAT_TXF_NOF_MASK)
+			return 0;
+
+		udelay(50);
+	} while (time_cnt++ < I2C_WAIT_TIMEOUT);
+
+	dev_err(i2c->dev, "wait rx no empty timeout, RIS: 0x%x, SR: 0x%x\n",
+			readl(i2c->base + HIBVT_I2C_INTR_RAW), val);
+	return -EIO;
+}
+
+static int hibvt_i2c_wait_idle(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int time_cnt = 0;
+	unsigned int val;
+
+	do {
+		val = readl(i2c->base + HIBVT_I2C_INTR_RAW);
+		if (val & (INTR_ABORT_MASK)) {
+			dev_err(i2c->dev, "wait idle abort!, RIS: 0x%x\n",
+					val);
+			return -EIO;
+		}
+
+		if (val & INTR_CMD_DONE_MASK)
+			return 0;
+
+		udelay(50);
+	} while (time_cnt++ < I2C_WAIT_TIMEOUT);
+
+	dev_err(i2c->dev, "wait idle timeout, RIS: 0x%x, SR: 0x%x\n",
+			val, readl(i2c->base + HIBVT_I2C_STAT));
+
+	return -EIO;
+}
+
+static void hibvt_i2c_set_freq(struct hibvt_i2c_dev *i2c)
+{
+	unsigned int max_freq, freq;
+	unsigned int clk_rate;
+	unsigned int val, sda_hold;
+
+	freq = i2c->freq;
+	clk_rate = clk_get_rate(i2c->clk);
+	max_freq = clk_rate >> 1;
+
+	if (freq > max_freq) {
+		i2c->freq = max_freq;
+		freq = i2c->freq;
+	}
+
+	if (freq <= 100000) {
+		val = clk_rate / (freq * 2) - 1;
+		writel(val, i2c->base + HIBVT_I2C_SCL_H);
+		writel(val, i2c->base + HIBVT_I2C_SCL_L);
+	} else {
+		val = (clk_rate * 36) / (freq * 100);
+		writel(val, i2c->base + HIBVT_I2C_SCL_H);
+		val = (clk_rate * 64) / (freq * 100);
+		writel(val, i2c->base + HIBVT_I2C_SCL_L);
+	}
+
+	sda_hold = val * 3 / 10;
+	sda_hold = (sda_hold << GLB_SDA_HOLD_SHIFT) & GLB_SDA_HOLD_MASK;
+	val = readl(i2c->base + HIBVT_I2C_GLB);
+	val &= ~GLB_SDA_HOLD_MASK;
+	val |= sda_hold;
+	writel(val, i2c->base + HIBVT_I2C_GLB);
+}
+
+/*
+ * set i2c controller TX and RX FIFO water
+ */
+static inline void hibvt_i2c_set_water(struct hibvt_i2c_dev *i2c)
+{
+	writel(I2C_TXF_WATER, i2c->base + HIBVT_I2C_TX_WATER);
+	writel(I2C_RXF_WATER, i2c->base + HIBVT_I2C_RX_WATER);
+}
+
+/*
+ * initialise the controller, set i2c bus interface freq
+ */
+static void hibvt_i2c_hw_init(struct hibvt_i2c_dev *i2c)
+{
+	hibvt_i2c_disable(i2c);
+	hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
+	hibvt_i2c_set_freq(i2c);
+	hibvt_i2c_set_water(i2c);
+}
+
+/*
+ * hibvt_i2c_cfg_cmd - config i2c controller command sequence
+ *
+ * After all the timing command is configured,
+ * and then start the command, you can i2c communication,
+ * and then only need to read and write i2c fifo.
+ */
+static void hibvt_i2c_cfg_cmd(struct hibvt_i2c_dev *i2c)
+{
+	struct i2c_msg *msg = i2c->msg;
+	int offset = 0;
+
+	if (i2c->msg_idx == 0)
+		hibvt_i2c_cmdreg_set(i2c, CMD_TX_S, &offset);
+	else
+		hibvt_i2c_cmdreg_set(i2c, CMD_TX_RS, &offset);
+
+	if (msg->flags & I2C_M_TEN) {
+		if (i2c->msg_idx == 0) {
+			hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset);
+			hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset);
+		} else {
+			hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_2, &offset);
+		}
+	} else {
+		hibvt_i2c_cmdreg_set(i2c, CMD_TX_D1_1, &offset);
+	}
+
+	if (msg->flags & I2C_M_IGNORE_NAK)
+		hibvt_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset);
+	else
+		hibvt_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset);
+
+	if (msg->flags & I2C_M_RD) {
+		if (msg->len >= 2) {
+			writel(offset, i2c->base + HIBVT_I2C_DST1);
+			writel(msg->len - 2, i2c->base + HIBVT_I2C_LOOP1);
+			hibvt_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset);
+			hibvt_i2c_cmdreg_set(i2c, CMD_TX_ACK, &offset);
+			hibvt_i2c_cmdreg_set(i2c, CMD_JMP1, &offset);
+		}
+		hibvt_i2c_cmdreg_set(i2c, CMD_RX_FIFO, &offset);
+		hibvt_i2c_cmdreg_set(i2c, CMD_TX_NACK, &offset);
+	} else {
+		writel(offset, i2c->base + HIBVT_I2C_DST1);
+		writel(msg->len - 1, i2c->base + HIBVT_I2C_LOOP1);
+		hibvt_i2c_cmdreg_set(i2c, CMD_UP_TXF, &offset);
+		hibvt_i2c_cmdreg_set(i2c, CMD_TX_FIFO, &offset);
+
+		if (msg->flags & I2C_M_IGNORE_NAK)
+			hibvt_i2c_cmdreg_set(i2c, CMD_IGN_ACK, &offset);
+		else
+			hibvt_i2c_cmdreg_set(i2c, CMD_RX_ACK, &offset);
+
+		hibvt_i2c_cmdreg_set(i2c, CMD_JMP1, &offset);
+	}
+
+	if ((i2c->msg_idx == (i2c->msg_num - 1)) || (msg->flags & I2C_M_STOP)) {
+		dev_dbg(i2c->dev, "run to %s %d...TX STOP\n",
+				__func__, __LINE__);
+		hibvt_i2c_cmdreg_set(i2c, CMD_TX_P, &offset);
+	}
+
+	hibvt_i2c_cmdreg_set(i2c, CMD_EXIT, &offset);
+}
+
+static int hibvt_i2c_polling_xfer_one_msg(struct hibvt_i2c_dev *i2c)
+{
+	int status;
+	unsigned int val;
+	struct i2c_msg *msg = i2c->msg;
+
+	dev_dbg(i2c->dev, "[%s,%d]msg->flags=0x%x, len=0x%x\n",
+			__func__, __LINE__, msg->flags, msg->len);
+
+	hibvt_i2c_enable(i2c);
+	hibvt_i2c_clr_irq(i2c);
+	hibvt_i2c_set_addr(i2c);
+	hibvt_i2c_cfg_cmd(i2c);
+	hibvt_i2c_start_cmd(i2c);
+
+	i2c->msg_buf_ptr = 0;
+
+	if (msg->flags & I2C_M_RD) {
+		while (i2c->msg_buf_ptr < msg->len) {
+			status = hibvt_i2c_wait_rx_noempty(i2c);
+			if (status)
+				goto end;
+
+			val = readl(i2c->base + HIBVT_I2C_RXF);
+			msg->buf[i2c->msg_buf_ptr] = val;
+			i2c->msg_buf_ptr++;
+
+		}
+	} else {
+		while (i2c->msg_buf_ptr < msg->len) {
+			status = hibvt_i2c_wait_tx_nofull(i2c);
+			if (status)
+				goto end;
+
+			val = msg->buf[i2c->msg_buf_ptr];
+			writel(val, i2c->base + HIBVT_I2C_TXF);
+			i2c->msg_buf_ptr++;
+		}
+	}
+
+	status = hibvt_i2c_wait_idle(i2c);
+end:
+	hibvt_i2c_disable(i2c);
+
+	return status;
+}
+
+static irqreturn_t hibvt_i2c_isr(int irq, void *dev_id)
+{
+	struct hibvt_i2c_dev *i2c = dev_id;
+	unsigned int irq_status;
+	struct i2c_msg *msg = i2c->msg;
+
+	spin_lock(&i2c->lock);
+
+	irq_status = hibvt_i2c_clr_irq(i2c);
+	dev_dbg(i2c->dev, "%s RIS:  0x%x\n", __func__, irq_status);
+
+	if (!irq_status) {
+		dev_dbg(i2c->dev, "no irq\n");
+		goto end;
+	}
+
+	if (irq_status & INTR_ABORT_MASK) {
+		dev_err(i2c->dev, "irq handle abort, RIS: 0x%x\n",
+				irq_status);
+		i2c->status = -EIO;
+		hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
+
+		complete(&i2c->msg_complete);
+		goto end;
+	}
+
+	if (msg->flags & I2C_M_RD) {
+		while ((readl(i2c->base + HIBVT_I2C_STAT) & STAT_RXF_NOE_MASK)
+				&& (i2c->msg_buf_ptr < msg->len)) {
+			msg->buf[i2c->msg_buf_ptr] =
+				readl(i2c->base + HIBVT_I2C_RXF);
+			i2c->msg_buf_ptr++;
+		}
+	} else {
+		while ((readl(i2c->base + HIBVT_I2C_STAT) & STAT_TXF_NOF_MASK)
+				&& (i2c->msg_buf_ptr < msg->len)) {
+			writel(msg->buf[i2c->msg_buf_ptr],
+					i2c->base + HIBVT_I2C_TXF);
+			i2c->msg_buf_ptr++;
+		}
+	}
+
+	if (i2c->msg_buf_ptr >= msg->len)
+		hibvt_i2c_disable_irq(i2c, INTR_TX_MASK | INTR_RX_MASK);
+
+	if (irq_status & INTR_CMD_DONE_MASK) {
+		dev_dbg(i2c->dev, "cmd done\n");
+		i2c->status =  0;
+		hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
+
+		complete(&i2c->msg_complete);
+	}
+
+end:
+	spin_unlock(&i2c->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int hibvt_i2c_interrupt_xfer_one_msg(struct hibvt_i2c_dev *i2c)
+{
+	int status;
+	struct i2c_msg *msg = i2c->msg;
+	unsigned long timeout;
+	unsigned long flags;
+
+	dev_dbg(i2c->dev, "[%s,%d]msg->flags=0x%x, len=0x%x\n",
+			__func__, __LINE__, msg->flags, msg->len);
+
+	reinit_completion(&i2c->msg_complete);
+	i2c->msg_buf_ptr = 0;
+	i2c->status = -EIO;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+	hibvt_i2c_enable(i2c);
+	hibvt_i2c_clr_irq(i2c);
+	if (msg->flags & I2C_M_RD)
+		hibvt_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_TX_MASK);
+	else
+		hibvt_i2c_cfg_irq(i2c, INTR_USE_MASK & ~INTR_RX_MASK);
+
+	hibvt_i2c_set_addr(i2c);
+	hibvt_i2c_cfg_cmd(i2c);
+	hibvt_i2c_start_cmd(i2c);
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	timeout = wait_for_completion_timeout(&i2c->msg_complete,
+			I2C_IRQ_TIMEOUT);
+
+	if (timeout == 0) {
+		hibvt_i2c_disable_irq(i2c, INTR_ALL_MASK);
+		status = -EIO;
+		dev_err(i2c->dev, "%s timeout\n",
+			 msg->flags & I2C_M_RD ? "rx" : "tx");
+	} else {
+		status = i2c->status;
+	}
+
+	hibvt_i2c_disable(i2c);
+
+	return status;
+}
+
+/*
+ * Master transfer function
+ */
+static int hibvt_i2c_xfer(struct i2c_adapter *adap,
+			struct i2c_msg *msgs, int num)
+{
+	struct hibvt_i2c_dev *i2c = i2c_get_adapdata(adap);
+	int status;
+
+	if (!msgs) {
+		dev_err(i2c->dev, "msgs == NULL\n");
+		return -EIO;
+	}
+
+	i2c->msg = msgs;
+	i2c->msg_num = num;
+	i2c->msg_idx = 0;
+
+	if (i2c->irq >= 0) {
+		while (i2c->msg_idx < i2c->msg_num) {
+			status = hibvt_i2c_interrupt_xfer_one_msg(i2c);
+			if (status)
+				break;
+
+			i2c->msg++;
+			i2c->msg_idx++;
+		}
+	} else {
+		while (i2c->msg_idx < i2c->msg_num) {
+			status = hibvt_i2c_polling_xfer_one_msg(i2c);
+			if (status)
+				break;
+
+			i2c->msg++;
+			i2c->msg_idx++;
+		}
+	}
+
+	if (!status || i2c->msg_idx > 0)
+		status = i2c->msg_idx;
+
+	return status;
+}
+
+static u32 hibvt_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR
+		| I2C_FUNC_PROTOCOL_MANGLING;
+}
+
+static const struct i2c_algorithm hibvt_i2c_algo = {
+	.master_xfer		= hibvt_i2c_xfer,
+	.functionality		= hibvt_i2c_func,
+};
+
+static int hibvt_i2c_probe(struct platform_device *pdev)
+{
+	int status;
+	struct hibvt_i2c_dev *i2c;
+	struct i2c_adapter *adap;
+	struct resource *res;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, i2c);
+	i2c->dev = &pdev->dev;
+	spin_lock_init(&i2c->lock);
+	init_completion(&i2c->msg_complete);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	i2c->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(i2c->base)) {
+		dev_err(i2c->dev, "cannot ioremap resource\n");
+		return -ENOMEM;
+	}
+
+	i2c->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2c->clk)) {
+		dev_err(i2c->dev, "cannot get clock\n");
+		return -ENOENT;
+	}
+	clk_prepare_enable(i2c->clk);
+
+	if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+				&i2c->freq)) {
+		dev_warn(i2c->dev, "setting default clock-frequency@%dHz\n",
+				I2C_DEFAULT_FREQUENCY);
+		i2c->freq = I2C_DEFAULT_FREQUENCY;
+	}
+
+	/* i2c controller initialization, disable interrupt */
+	hibvt_i2c_hw_init(i2c);
+
+	i2c->irq = platform_get_irq(pdev, 0);
+	status = devm_request_irq(&pdev->dev, i2c->irq, hibvt_i2c_isr,
+			IRQF_SHARED, dev_name(&pdev->dev), i2c);
+	if (status) {
+		dev_dbg(i2c->dev, "falling back to polling mode");
+		i2c->irq = -1;
+	}
+
+	adap = &i2c->adap;
+	i2c_set_adapdata(adap, i2c);
+	adap->owner = THIS_MODULE;
+	strlcpy(adap->name, "hibvt-i2c", sizeof(adap->name));
+	adap->dev.parent = &pdev->dev;
+	adap->dev.of_node = pdev->dev.of_node;
+	adap->algo = &hibvt_i2c_algo;
+
+	/* Add the i2c adapter */
+	status = i2c_add_adapter(adap);
+	if (status) {
+		dev_err(i2c->dev, "failed to add bus to i2c core\n");
+		goto err_add_adapter;
+	}
+
+	dev_info(i2c->dev, "%s%d@%dhz registered\n",
+			adap->name, adap->nr, i2c->freq);
+
+	return 0;
+
+err_add_adapter:
+	clk_disable_unprepare(i2c->clk);
+	return status;
+}
+
+static int hibvt_i2c_remove(struct platform_device *pdev)
+{
+	struct hibvt_i2c_dev *i2c = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adap);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int hibvt_i2c_suspend(struct device *dev)
+{
+	struct hibvt_i2c_dev *i2c = dev_get_drvdata(dev);
+
+	i2c_lock_adapter(&i2c->adap);
+	clk_disable_unprepare(i2c->clk);
+	i2c_unlock_adapter(&i2c->adap);
+
+	return 0;
+}
+
+static int hibvt_i2c_resume(struct device *dev)
+{
+	struct hibvt_i2c_dev *i2c = dev_get_drvdata(dev);
+
+	i2c_lock_adapter(&i2c->adap);
+	clk_prepare_enable(i2c->clk);
+	hibvt_i2c_hw_init(i2c);
+	i2c_unlock_adapter(&i2c->adap);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(hibvt_i2c_dev_pm, hibvt_i2c_suspend,
+		hibvt_i2c_resume);
+
+static const struct of_device_id hibvt_i2c_match[] = {
+	{ .compatible = "hisilicon,hibvt-i2c"},
+	{ .compatible = "hisilicon,hi3516cv300-i2c"},
+	{},
+};
+MODULE_DEVICE_TABLE(of, hibvt_i2c_match);
+
+static struct platform_driver hibvt_i2c_driver = {
+	.driver		= {
+		.name	= "hibvt-i2c",
+		.of_match_table = hibvt_i2c_match,
+		.pm	= &hibvt_i2c_dev_pm,
+	},
+	.probe		= hibvt_i2c_probe,
+	.remove		= hibvt_i2c_remove,
+};
+
+module_platform_driver(hibvt_i2c_driver);
+
+MODULE_AUTHOR("Pan Wen, <wenpan-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>");
+MODULE_DESCRIPTION("HISILICON BVT I2C Bus driver");
+MODULE_LICENSE("GPL v2");
-- 
2.9.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH] i2c: imx: defer probe if bus recovery GPIOs are not ready
From: Uwe Kleine-König @ 2016-09-27  6:44 UTC (permalink / raw)
  To: Stefan Agner; +Cc: wsa, leoyang.li, linux-i2c, linux-kernel
In-Reply-To: <20160927001858.11601-1-stefan@agner.ch>

Hello Stefan,

On Mon, Sep 26, 2016 at 05:18:58PM -0700, Stefan Agner wrote:
> Some SoC might load the GPIO driver after the I2C driver and
> using the I2C bus recovery mechanism via GPIOs. In this case
> it is crucial to defer probing if the GPIO request functions
> do so, otherwise the I2C driver gets loaded without recovery
> mechanisms enabled.
> 
> Signed-off-by: Stefan Agner <stefan@agner.ch>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Thanks
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply

* [PATCH] i2c: imx: defer probe if bus recovery GPIOs are not ready
From: Stefan Agner @ 2016-09-27  0:18 UTC (permalink / raw)
  To: wsa; +Cc: leoyang.li, linux-i2c, u.kleine-koenig, linux-kernel,
	Stefan Agner

Some SoC might load the GPIO driver after the I2C driver and
using the I2C bus recovery mechanism via GPIOs. In this case
it is crucial to defer probing if the GPIO request functions
do so, otherwise the I2C driver gets loaded without recovery
mechanisms enabled.

Signed-off-by: Stefan Agner <stefan@agner.ch>
---
This is an actual issue on NXP Vybrid devices on which the GPIO
driver gets loaded rather later.

--
Stefan

 drivers/i2c/busses/i2c-imx.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 592a8f2..47fc1f1 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -1009,10 +1009,13 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
 	rinfo->sda_gpio = of_get_named_gpio(pdev->dev.of_node, "sda-gpios", 0);
 	rinfo->scl_gpio = of_get_named_gpio(pdev->dev.of_node, "scl-gpios", 0);
 
-	if (!gpio_is_valid(rinfo->sda_gpio) ||
-	    !gpio_is_valid(rinfo->scl_gpio) ||
-	    IS_ERR(i2c_imx->pinctrl_pins_default) ||
-	    IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
+	if (rinfo->sda_gpio == -EPROBE_DEFER ||
+	    rinfo->scl_gpio == -EPROBE_DEFER) {
+		return -EPROBE_DEFER;
+	} else if (!gpio_is_valid(rinfo->sda_gpio) ||
+		   !gpio_is_valid(rinfo->scl_gpio) ||
+		   IS_ERR(i2c_imx->pinctrl_pins_default) ||
+		   IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
 		dev_dbg(&pdev->dev, "recovery information incomplete\n");
 		return 0;
 	}
-- 
2.10.0

^ permalink raw reply related

* [PATCH v2] i2c: xlp9xx: ACPI support for I2C clients
From: Tanmay Jagdale @ 2016-09-26 10:43 UTC (permalink / raw)
  To: wsa; +Cc: linux-i2c, jayachandran.chandrashekaran, Tanmay Jagdale
In-Reply-To: <20160921211725.GI1513@katana>

The ACPI companion of the adapter has to be set for I2C controller
code to read and attach the slave devices described in the ACPI table
with the I2CSerialBus resource descriptor. Used ACPI_COMPANION_SET
macro to set this.

Signed-off-by: Tanmay Jagdale <tanmay.jagdale@broadcom.com>
---
Changes in v2
	- Fixed parenthesis

 drivers/i2c/busses/i2c-xlp9xx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
index 55a7bef..10e47dd 100644
--- a/drivers/i2c/busses/i2c-xlp9xx.c
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -393,6 +393,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev)
 	init_completion(&priv->msg_complete);
 	priv->adapter.dev.parent = &pdev->dev;
 	priv->adapter.algo = &xlp9xx_i2c_algo;
+	ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
 	priv->adapter.dev.of_node = pdev->dev.of_node;
 	priv->dev = &pdev->dev;
 
-- 
2.1.0

^ permalink raw reply related

* Re: [PATCH] gpio: pca953x: add a comment explaining the need for a lockdep subclass
From: Wolfram Sang @ 2016-09-26 10:00 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Alexandre Courbot, Andy Shevchenko, Vignesh R,
	Yong Li, Geert Uytterhoeven, Peter Zijlstra, Ingo Molnar,
	Peter Rosin, linux-i2c, linux-gpio, LKML
In-Reply-To: <1474883655-15824-2-git-send-email-bgolaszewski@baylibre.com>

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

On Mon, Sep 26, 2016 at 11:54:15AM +0200, Bartosz Golaszewski wrote:
> This is a follow-up to commit 559b46990e76 ("gpio: pca953x: fix an
> incorrect lockdep warning"). The reason for calling
> lockdep_set_subclass() in pca953x_probe() is not explained in
> the code.
> 
> Add a comment describing the problem, partial solution and required
> future extensions.
> 
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Acked-by: Wolfram Sang <wsa@the-dreams.de>

Linus, because of dependencies, I should probably pick it up?


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

^ permalink raw reply

* [PATCH] gpio: pca953x: add a comment explaining the need for a lockdep subclass
From: Bartosz Golaszewski @ 2016-09-26  9:54 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Andy Shevchenko, Vignesh R,
	Yong Li, Geert Uytterhoeven, Peter Zijlstra, Ingo Molnar,
	Wolfram Sang, Peter Rosin
  Cc: linux-i2c, linux-gpio, LKML, Bartosz Golaszewski

Since there's an rc8 I thought I'd send a follow-up patch to the
series addressing the lockdep false positive in pca953x.

The reason for setting the subclass in the probe function is not
explained in the code nor is it obvious at first glance. This patch
adds a comment explaining the problem.

Rebased on top of current i2c/for-next.

Bartosz Golaszewski (1):
  gpio: pca953x: add a comment explaining the need for a lockdep
    subclass

 drivers/gpio/gpio-pca953x.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

-- 
2.7.4

^ permalink raw reply

* [PATCH] gpio: pca953x: add a comment explaining the need for a lockdep subclass
From: Bartosz Golaszewski @ 2016-09-26  9:54 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Andy Shevchenko, Vignesh R,
	Yong Li, Geert Uytterhoeven, Peter Zijlstra, Ingo Molnar,
	Wolfram Sang, Peter Rosin
  Cc: linux-i2c, linux-gpio, LKML, Bartosz Golaszewski
In-Reply-To: <1474883655-15824-1-git-send-email-bgolaszewski@baylibre.com>

This is a follow-up to commit 559b46990e76 ("gpio: pca953x: fix an
incorrect lockdep warning"). The reason for calling
lockdep_set_subclass() in pca953x_probe() is not explained in
the code.

Add a comment describing the problem, partial solution and required
future extensions.

Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 drivers/gpio/gpio-pca953x.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 018f39c..f306909 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -786,6 +786,22 @@ static int pca953x_probe(struct i2c_client *client,
 	chip->chip_type = PCA_CHIP_TYPE(chip->driver_data);
 
 	mutex_init(&chip->i2c_lock);
+	/*
+	 * In case we have an i2c-mux controlled by a GPIO provided by an
+	 * expander using the same driver higher on the device tree, read the
+	 * i2c adapter nesting depth and use the retrieved value as lockdep
+	 * subclass for chip->i2c_lock.
+	 *
+	 * REVISIT: This solution is not complete. It protects us from lockdep
+	 * false positives when the expander controlling the i2c-mux is on
+	 * a different level on the device tree, but not when it's on the same
+	 * level on a different branch (in which case the subclass number
+	 * would be the same).
+	 *
+	 * TODO: Once a correct solution is developed, a similar fix should be
+	 * applied to all other i2c-controlled GPIO expanders (and potentially
+	 * regmap-i2c).
+	 */
 	lockdep_set_subclass(&chip->i2c_lock,
 			     i2c_adapter_depth(client->adapter));
 
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v2 1/2] i2c: octeon: thunderx: Check bus state before starting a transaction
From: Jan Glauber @ 2016-09-26  5:58 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: linux-kernel, linux-i2c, Dmitry Bazhenov
In-Reply-To: <20160924092418.GG1434@katana>

On Sat, Sep 24, 2016 at 11:24:19AM +0200, Wolfram Sang wrote:
> On Fri, Sep 23, 2016 at 11:40:38AM +0200, Jan Glauber wrote:
> > Add an additional status check before starting a transaction. If the
> > check fails wait for some time to tolerate multi-master mode. After the
> > timeout expires trigger the recovery.
> > 
> > Signed-off-by: Jan Glauber <jglauber@cavium.com>
> 
> Need to think more about it, needs to wait for next cycle.
> 

OK, please share your thoughts when you get to it.

--Jan

^ permalink raw reply

* RE: [v12, 0/8] Fix eSDHC host version register bug
From: Y.B. Lu @ 2016-09-26  3:14 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org, Scott Wood,
	Arnd Bergmann
  Cc: linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Mark Rutland,
	Rob Herring, Russell King, Jochen Friedrich, Joerg Roedel,
	Claudiu Manoil, Bhupesh Sharma
In-Reply-To: <1474441040-11946-1-git-send-email-yangbo.lu-3arQi8VN3Tc@public.gmane.org>

Any comments about this version patchset ?

:)


> -----Original Message-----
> From: Yangbo Lu [mailto:yangbo.lu-3arQi8VN3Tc@public.gmane.org]
> Sent: Wednesday, September 21, 2016 2:57 PM
> To: linux-mmc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org; Scott Wood; Arnd
> Bergmann
> Cc: linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org; devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-arm-
> kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org; linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-
> clk-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; iommu-cunTk1MwBs/ROKNJybVBZg@public.gmane.org
> foundation.org; netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Mark Rutland; Rob Herring;
> Russell King; Jochen Friedrich; Joerg Roedel; Claudiu Manoil; Bhupesh
> Sharma; Qiang Zhao; Kumar Gala; Santosh Shilimkar; Leo Li; X.B. Xie; M.H.
> Lian; Y.B. Lu
> Subject: [v12, 0/8] Fix eSDHC host version register bug
> 
> This patchset is used to fix a host version register bug in the T4240-
> R1.0-R2.0 eSDHC controller. To match the SoC version and revision, 10
> previous version patchsets had tried many methods but all of them were
> rejected by reviewers.
> Such as
> 	- dts compatible method
> 	- syscon method
> 	- ifdef PPC method
> 	- GUTS driver getting SVR method
> Anrd suggested a soc_device_match method in v10, and this is the only
> available method left now. This v11 patchset introduces the
> soc_device_match interface in soc driver.
> 
> The first six patches of Yangbo are to add the GUTS driver. This is used
> to register a soc device which contain soc version and revision
> information.
> The other two patches introduce the soc_device_match method in soc driver
> and apply it on esdhc driver to fix this bug.
> 
> Arnd Bergmann (1):
>   base: soc: introduce soc_device_match() interface
> 
> Yangbo Lu (7):
>   dt: bindings: update Freescale DCFG compatible
>   ARM64: dts: ls2080a: add device configuration node
>   dt: bindings: move guts devicetree doc out of powerpc directory
>   powerpc/fsl: move mpc85xx.h to include/linux/fsl
>   soc: fsl: add GUTS driver for QorIQ platforms
>   MAINTAINERS: add entry for Freescale SoC drivers
>   mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
> 
>  Documentation/devicetree/bindings/arm/fsl.txt      |   6 +-
>  .../bindings/{powerpc => soc}/fsl/guts.txt         |   3 +
>  MAINTAINERS                                        |  11 +-
>  arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi     |   6 +
>  arch/powerpc/kernel/cpu_setup_fsl_booke.S          |   2 +-
>  arch/powerpc/sysdev/fsl_pci.c                      |   2 +-
>  drivers/base/Kconfig                               |   1 +
>  drivers/base/soc.c                                 |  66 ++++++
>  drivers/clk/clk-qoriq.c                            |   3 +-
>  drivers/i2c/busses/i2c-mpc.c                       |   2 +-
>  drivers/iommu/fsl_pamu.c                           |   3 +-
>  drivers/mmc/host/Kconfig                           |   1 +
>  drivers/mmc/host/sdhci-of-esdhc.c                  |  20 ++
>  drivers/net/ethernet/freescale/gianfar.c           |   2 +-
>  drivers/soc/Kconfig                                |   2 +-
>  drivers/soc/fsl/Kconfig                            |  19 ++
>  drivers/soc/fsl/Makefile                           |   1 +
>  drivers/soc/fsl/guts.c                             | 257
> +++++++++++++++++++++
>  include/linux/fsl/guts.h                           | 125 ++++++----
>  .../asm/mpc85xx.h => include/linux/fsl/svr.h       |   4 +-
>  include/linux/sys_soc.h                            |   3 +
>  21 files changed, 478 insertions(+), 61 deletions(-)  rename
> Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
> create mode 100644 drivers/soc/fsl/Kconfig  create mode 100644
> drivers/soc/fsl/guts.c  rename arch/powerpc/include/asm/mpc85xx.h =>
> include/linux/fsl/svr.h (97%)
> 
> --
> 2.1.0.27.g96db324

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 4/4] gpio: pca953x: fix an incorrect lockdep warning
From: Geert Uytterhoeven @ 2016-09-24 14:26 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: Bartosz Golaszewski, Linus Walleij, Alexandre Courbot,
	Andy Shevchenko, Vignesh R, Yong Li, Geert Uytterhoeven,
	Peter Zijlstra, Ingo Molnar, Peter Rosin, linux-i2c, linux-gpio,
	LKML
In-Reply-To: <20160924091506.GE1434@katana>

On Sat, Sep 24, 2016 at 11:15 AM, Wolfram Sang <wsa@the-dreams.de> wrote:
>>  drivers/gpio/gpio-pca953x.c | 2 ++
>>  1 file changed, 2 insertions(+)
>
> FYI, my code checkers found this in this driver:
>
>     SMATCH
> drivers/gpio/gpio-pca953x.c:562 pca953x_irq_pending() error: buffer overflow 'cur_stat' 5 <= 8191
> drivers/gpio/gpio-pca953x.c:573 pca953x_irq_pending() warn: buffer overflow 'old_stat' 5 <= 8191
>
> Didn't check further. I fixed a sparse warning, though.

I guess those lines are

        memcpy(old_stat, chip->irq_stat, NBANK(chip));

and

        memcpy(chip->irq_stat, cur_stat, NBANK(chip));

?

#define NBANK(chip) DIV_ROUND_UP(chip->gpio_chip.ngpio, BANK_SZ)

ngpio is u16, BANK_SZ is 8, so smatch assumes someone may set
ngpio to 65535. Which someone could do through driver_data.
But none of the predefined entries in pca953x_dt_ids[] does.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH] i2c: axxia: disable clks in case of failure in probe
From: Wolfram Sang @ 2016-09-24  9:30 UTC (permalink / raw)
  To: Alexey Khoroshilov; +Cc: linux-i2c, linux-kernel, ldv-project
In-Reply-To: <1474622126-1996-1-git-send-email-khoroshilov@ispras.ru>

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

On Fri, Sep 23, 2016 at 11:15:26AM +0200, Alexey Khoroshilov wrote:
> axxia_i2c_probe() does not disable clock in case of failure
> in i2c_add_adapter(). Also it ignores returned value from
> clk_prepare_enable().
> 
> Found by Linux Driver Verification project (linuxtesting.org).
> 
> Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>

Applied to for-next, thanks!

Please use "V2" in subject (git has a '-v<n>' parameter for that) and
provide a changelog below "---" next time. Also, try to add the driver
author or recently active people on that driver so we can have tests on
HW.


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

^ permalink raw reply

* Re: [PATCH v2 2/2] i2c: octeon: thunderx: Limit register access retries
From: Wolfram Sang @ 2016-09-24  9:24 UTC (permalink / raw)
  To: Jan Glauber; +Cc: linux-kernel, linux-i2c, Dmitry Bazhenov
In-Reply-To: <1140690b8b727cd09afb9c5867983815f33a08c7.1474565039.git.jglauber@cavium.com>

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

On Fri, Sep 23, 2016 at 11:40:39AM +0200, Jan Glauber wrote:
> Do not infinitely retry register readq and writeq operations
> in order to not lock up the CPU in case the TWSI gets stuck.
> 
> Return -ETIMEDOUT in case of a failed data read. For all other
> cases just return so subsequent operations will fail
> and trigger the recovery.
> 
> Signed-off-by: Jan Glauber <jglauber@cavium.com>

Deleted the last 4 words from commit message (previous recovery patch
needs more discussion) and applied to for-next, thanks!


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

^ permalink raw reply

* Re: [PATCH v2 1/2] i2c: octeon: thunderx: Check bus state before starting a transaction
From: Wolfram Sang @ 2016-09-24  9:24 UTC (permalink / raw)
  To: Jan Glauber; +Cc: linux-kernel, linux-i2c, Dmitry Bazhenov
In-Reply-To: <ccf553c14d5220f3f9233ac7695d27ee0d55bcc7.1474565039.git.jglauber@cavium.com>

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

On Fri, Sep 23, 2016 at 11:40:38AM +0200, Jan Glauber wrote:
> Add an additional status check before starting a transaction. If the
> check fails wait for some time to tolerate multi-master mode. After the
> timeout expires trigger the recovery.
> 
> Signed-off-by: Jan Glauber <jglauber@cavium.com>

Need to think more about it, needs to wait for next cycle.


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

^ permalink raw reply

* Re: [PATCH v2] i2c: uniphier-f: fix misdetection of incomplete STOP condition
From: Wolfram Sang @ 2016-09-24  9:19 UTC (permalink / raw)
  To: Masahiro Yamada; +Cc: linux-i2c, linux-arm-kernel, linux-kernel
In-Reply-To: <1474637681-9589-1-git-send-email-yamada.masahiro@socionext.com>

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

On Fri, Sep 23, 2016 at 10:34:41PM +0900, Masahiro Yamada wrote:
> Currently, the status register FI2C_SR is checked immediately after
> a STOP condition is issued in case of the deferred STOP condition.
> It takes typically 5-10 usec until the corresponding bits in the
> register are set, so the error check for "stop condition was not
> completed" is very likely to be false positive.
> 
> Add wait code to relax the status register check.
> 
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>

Applied to for-next, thanks!


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

^ permalink raw reply

* Re: [PATCH v2 4/4] gpio: pca953x: fix an incorrect lockdep warning
From: Wolfram Sang @ 2016-09-24  9:15 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Alexandre Courbot, Andy Shevchenko, Vignesh R,
	Yong Li, Geert Uytterhoeven, Peter Zijlstra, Ingo Molnar,
	Peter Rosin, linux-i2c, linux-gpio, LKML
In-Reply-To: <1474041765-17818-5-git-send-email-bgolaszewski@baylibre.com>

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

>  drivers/gpio/gpio-pca953x.c | 2 ++
>  1 file changed, 2 insertions(+)

FYI, my code checkers found this in this driver:

    SMATCH
drivers/gpio/gpio-pca953x.c:562 pca953x_irq_pending() error: buffer overflow 'cur_stat' 5 <= 8191
drivers/gpio/gpio-pca953x.c:573 pca953x_irq_pending() warn: buffer overflow 'old_stat' 5 <= 8191

Didn't check further. I fixed a sparse warning, though.


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

^ permalink raw reply

* Re: [PATCH v2] i2c: i801: Add support for Kaby Lake PCH-H
From: Wolfram Sang @ 2016-09-24  8:57 UTC (permalink / raw)
  To: Mika Westerberg; +Cc: Jean Delvare, linux-i2c, Andy Shevchenko
In-Reply-To: <20160923085601.166121-1-mika.westerberg@linux.intel.com>

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

On Fri, Sep 23, 2016 at 11:56:01AM +0300, Mika Westerberg wrote:
> From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> 
> Intel Kaby Lake PCH-H has the same legacy SMBus host controller than Intel
> Sunrisepoint PCH. It also has same iTCO watchdog on the bus.
> 
> Add Kaby Lake PCH-H PCI ID to the list of supported devices.
> 
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>

Applied to for-next, thanks!


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

^ permalink raw reply

* Re: [PATCH v2 0/4] gpio: fix an incorrect lockdep warning
From: Wolfram Sang @ 2016-09-24  8:56 UTC (permalink / raw)
  To: Bartosz Golaszewski
  Cc: Linus Walleij, Alexandre Courbot, Andy Shevchenko, Vignesh R,
	Yong Li, Geert Uytterhoeven, Peter Zijlstra, Ingo Molnar,
	Peter Rosin, linux-i2c, linux-gpio, LKML
In-Reply-To: <1474041765-17818-1-git-send-email-bgolaszewski@baylibre.com>

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

On Fri, Sep 16, 2016 at 06:02:41PM +0200, Bartosz Golaszewski wrote:
> If an I2C GPIO multiplexer is driven by a GPIO provided by an expander
> when there's a second expander using the same device driver on one of
> the I2C bus segments, lockdep prints a deadlock warning when trying to
> set the direction or the value of the GPIOs provided by the second
> expander.
> 
> This series exports an already existing function from i2c-core as
> public API and reuses it in pca953x to pass a correct lock subclass
> to lockdep.
> 
> Note: if this series gets merged, I'll prepare follow-up patches for
> other expanders for which a similar problem could potentially occur.
> 
> Tested with the following setup:
> 
>  -------             ---------  Bus segment 1 |         |
> |       |           |         |---------------  Devices
> |       | SCL/SDA   |         |               |         |
> | Linux |-----------| I2C MUX |                - - - - -
> |       |    |      |         | Bus segment 2
> |       |    |      |         |-------------------
>  -------     |       ---------                    |
>              |           |                    - - - - -
>         ------------     | MUX GPIO          |         |
>        |            |    |                     Devices
>        |    GPIO    |    |                   |         |
>        | Expander 1 |----                     - - - - -
>        |            |                             |
>         ------------                              | SCL/SDA
>                                                   |
>                                              ------------
>                                             |            |
>                                             |    GPIO    |
>                                             | Expander 2 |
>                                             |            |
>                                              ------------
> 
> where expander 1 is a pca9534 and expander 2 is a pca9535.
> 
> v1 -> v2:
> - added patches 1/4, 2/4 & 3/4
> - used i2c_adapter_depth() in patch 4/4 in order to detect multiple
>   adapter nesting
> 
> Bartosz Golaszewski (4):
>   i2c: export i2c_adapter_depth()
>   lockdep: make MAX_LOCKDEP_SUBCLASSES unconditionally visible
>   i2c: add a warning to i2c_adapter_depth()
>   gpio: pca953x: fix an incorrect lockdep warning

Applied to for-next, thanks!


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

^ permalink raw reply

* Re: [PATCH v2 4/4] gpio: pca953x: fix an incorrect lockdep warning
From: Wolfram Sang @ 2016-09-24  8:55 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Bartosz Golaszewski, Alexandre Courbot, Andy Shevchenko,
	Vignesh R, Yong Li, Geert Uytterhoeven, Peter Zijlstra,
	Ingo Molnar, Peter Rosin, linux-i2c, linux-gpio, LKML
In-Reply-To: <CACRpkdbYgetpYntO6KsVLh1n_7DU+1AD3AwVVkmV5ud5A6Q31g@mail.gmail.com>

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

On Fri, Sep 23, 2016 at 10:10:57AM +0200, Linus Walleij wrote:
> On Wed, Sep 21, 2016 at 7:45 AM, Wolfram Sang <wsa@the-dreams.de> wrote:
> 
> >> In order to get rid of the warning, retrieve the adapter nesting depth
> >> and use it as lockdep subclass for chip->i2c_lock.
> >>
> >> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > Linus, we'd like that in 4.9. Can I get your ack for the gpio part?
> 
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
> 
> Sorry for not attending quick enough, I was down in the
> block layer.

Well, it was close but still quick enough. Glad to see that one can come
back from the depths of the block layer ;)


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

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox