All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] i2c: hix5hd2: add i2c controller driver
@ 2014-09-28  4:22 ` Zhangfei Gao
  0 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: Wolfram Sang, Arnd Bergmann, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Zhangfei Gao

v2: 
Modify according to Wolfram's comments 
including change vector name, coding style, return value etc.

Wei Yan (2):
  i2c: hix5hd2: add devicetree documentation
  i2c: hix5hd2: add i2c controller driver

Zhangfei Gao (1):
  ARM: dts: hix5hd2: add i2c node

 .../devicetree/bindings/i2c/i2c-hix5hd2.txt        |   31 ++
 arch/arm/boot/dts/hisi-x5hd2.dtsi                  |   60 +++
 drivers/i2c/busses/Kconfig                         |   10 +
 drivers/i2c/busses/Makefile                        |    1 +
 drivers/i2c/busses/i2c-hix5hd2.c                   |  555 ++++++++++++++++++++
 5 files changed, 657 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt
 create mode 100644 drivers/i2c/busses/i2c-hix5hd2.c

-- 
1.7.9.5

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

* [PATCH v2 0/3] i2c: hix5hd2: add i2c controller driver
@ 2014-09-28  4:22 ` Zhangfei Gao
  0 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: linux-arm-kernel

v2: 
Modify according to Wolfram's comments 
including change vector name, coding style, return value etc.

Wei Yan (2):
  i2c: hix5hd2: add devicetree documentation
  i2c: hix5hd2: add i2c controller driver

Zhangfei Gao (1):
  ARM: dts: hix5hd2: add i2c node

 .../devicetree/bindings/i2c/i2c-hix5hd2.txt        |   31 ++
 arch/arm/boot/dts/hisi-x5hd2.dtsi                  |   60 +++
 drivers/i2c/busses/Kconfig                         |   10 +
 drivers/i2c/busses/Makefile                        |    1 +
 drivers/i2c/busses/i2c-hix5hd2.c                   |  555 ++++++++++++++++++++
 5 files changed, 657 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt
 create mode 100644 drivers/i2c/busses/i2c-hix5hd2.c

-- 
1.7.9.5

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

* [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
  2014-09-28  4:22 ` Zhangfei Gao
@ 2014-09-28  4:22     ` Zhangfei Gao
  -1 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: Wolfram Sang, Arnd Bergmann, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Wei Yan, Zhangfei Gao

From: Wei Yan <sledge.yanwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>

Signed-off-by: Wei Yan <sledge.yanwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/i2c/i2c-hix5hd2.txt        |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt b/Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt
new file mode 100644
index 0000000..981a069
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt
@@ -0,0 +1,31 @@
+I2C for Hisilicon hix5hd2 chipset platforms (3716,3719,3798...)
+
+Required properties:
+- compatible: Must be "hisilicon,hix5hd2-i2c"
+  Specifically, the following versions of the chipset are supported:
+	  Hi3716CV200 (support six I2C module)
+	  Hi3719CV100 (support six I2C module)
+	  Hi3718CV100 (support six I2C module)
+	  Hi3719MV100 (support two I2C module)
+	  Hi3718MV100 (support two I2C module)
+- reg: physical base address of the controller and length of memory mapped
+     region.
+- interrupts: interrupt number to the cpu.
+- #address-cells = <1>;
+- #size-cells = <0>;
+- clocks: phandles to input clocks.
+
+Optional properties:
+- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000
+- Child nodes conforming to i2c bus binding
+
+Examples:
+I2C0@f8b10000 {
+	compatible = "hisilicon,hix5hd2-i2c";
+	reg = <0xf8b10000 0x1000>;
+	interrupts = <0 38 4>;
+	clocks = <&clock HIX5HD2_I2C0_RST>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "disabled";
+}
-- 
1.7.9.5

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

* [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
@ 2014-09-28  4:22     ` Zhangfei Gao
  0 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: linux-arm-kernel

From: Wei Yan <sledge.yanwei@huawei.com>

Signed-off-by: Wei Yan <sledge.yanwei@huawei.com>
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
---
 .../devicetree/bindings/i2c/i2c-hix5hd2.txt        |   31 ++++++++++++++++++++
 1 file changed, 31 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt

diff --git a/Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt b/Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt
new file mode 100644
index 0000000..981a069
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-hix5hd2.txt
@@ -0,0 +1,31 @@
+I2C for Hisilicon hix5hd2 chipset platforms (3716,3719,3798...)
+
+Required properties:
+- compatible: Must be "hisilicon,hix5hd2-i2c"
+  Specifically, the following versions of the chipset are supported:
+	  Hi3716CV200 (support six I2C module)
+	  Hi3719CV100 (support six I2C module)
+	  Hi3718CV100 (support six I2C module)
+	  Hi3719MV100 (support two I2C module)
+	  Hi3718MV100 (support two I2C module)
+- reg: physical base address of the controller and length of memory mapped
+     region.
+- interrupts: interrupt number to the cpu.
+- #address-cells = <1>;
+- #size-cells = <0>;
+- clocks: phandles to input clocks.
+
+Optional properties:
+- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000
+- Child nodes conforming to i2c bus binding
+
+Examples:
+I2C0 at f8b10000 {
+	compatible = "hisilicon,hix5hd2-i2c";
+	reg = <0xf8b10000 0x1000>;
+	interrupts = <0 38 4>;
+	clocks = <&clock HIX5HD2_I2C0_RST>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	status = "disabled";
+}
-- 
1.7.9.5

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

* [PATCH v2 2/3] i2c: hix5hd2: add i2c controller driver
  2014-09-28  4:22 ` Zhangfei Gao
@ 2014-09-28  4:22     ` Zhangfei Gao
  -1 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: Wolfram Sang, Arnd Bergmann, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Wei Yan, Zhangfei Gao

From: Wei Yan <sledge.yanwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>

I2C drivers for hix5hd2 soc series, including following chipset
Hi3716CV200, Hi3719CV100, Hi3718CV100, Hi3719MV100, Hi3718MV100.

Signed-off-by: Wei Yan <sledge.yanwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 drivers/i2c/busses/Kconfig       |   10 +
 drivers/i2c/busses/Makefile      |    1 +
 drivers/i2c/busses/i2c-hix5hd2.c |  554 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 565 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-hix5hd2.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 2ac87fa..ba0f43c 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -77,6 +77,16 @@ config I2C_AMD8111
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-amd8111.
 
+config I2C_HIX5HD2
+	tristate "Hix5hd2 high-speed I2C driver"
+	depends on ARCH_HIX5HD2
+	help
+	  Say Y here to include support for high-speed I2C controller in the
+	  Hisilicon based hix5hd2 SoCs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-hix5hd2.
+
 config I2C_I801
 	tristate "Intel 82801 (ICH/PCH)"
 	depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 49bf07e..9739938 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_I2C_EG20T)		+= i2c-eg20t.o
 obj-$(CONFIG_I2C_EXYNOS5)	+= i2c-exynos5.o
 obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
+obj-$(CONFIG_I2C_HIX5HD2)	+= i2c-hix5hd2.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c
new file mode 100644
index 0000000..4b18bde
--- /dev/null
+++ b/drivers/i2c/busses/i2c-hix5hd2.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * 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.
+ *
+ * Now only support 7 bit address.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* Register Map */
+#define HIX5I2C_CTRL		0x00
+#define HIX5I2C_COM		0x04
+#define HIX5I2C_ICR		0x08
+#define HIX5I2C_SR		0x0c
+#define HIX5I2C_SCL_H		0x10
+#define HIX5I2C_SCL_L		0x14
+#define HIX5I2C_TXR		0x18
+#define HIX5I2C_RXR		0x1c
+
+/* I2C_CTRL_REG */
+#define I2C_ENABLE		BIT(8)
+#define I2C_UNMASK_TOTAL	BIT(7)
+#define I2C_UNMASK_START	BIT(6)
+#define I2C_UNMASK_END		BIT(5)
+#define I2C_UNMASK_SEND		BIT(4)
+#define I2C_UNMASK_RECEIVE	BIT(3)
+#define I2C_UNMASK_ACK		BIT(2)
+#define I2C_UNMASK_ARBITRATE	BIT(1)
+#define I2C_UNMASK_OVER		BIT(0)
+#define I2C_UNMASK_ALL		(I2C_UNMASK_ACK | I2C_UNMASK_OVER)
+
+/* I2C_COM_REG */
+#define I2C_NO_ACK		BIT(4)
+#define I2C_START		BIT(3)
+#define I2C_READ		BIT(2)
+#define I2C_WRITE		BIT(1)
+#define I2C_STOP		BIT(0)
+
+/* I2C_ICR_REG */
+#define I2C_CLEAR_START		BIT(6)
+#define I2C_CLEAR_END		BIT(5)
+#define I2C_CLEAR_SEND		BIT(4)
+#define I2C_CLEAR_RECEIVE	BIT(3)
+#define I2C_CLEAR_ACK		BIT(2)
+#define I2C_CLEAR_ARBITRATE	BIT(1)
+#define I2C_CLEAR_OVER		BIT(0)
+#define I2C_CLEAR_ALL		(I2C_CLEAR_START | I2C_CLEAR_END | \
+				I2C_CLEAR_SEND | I2C_CLEAR_RECEIVE | \
+				I2C_CLEAR_ACK | I2C_CLEAR_ARBITRATE | \
+				I2C_CLEAR_OVER)
+
+/* I2C_SR_REG */
+#define I2C_BUSY		BIT(7)
+#define I2C_START_INTR		BIT(6)
+#define I2C_END_INTR		BIT(5)
+#define I2C_SEND_INTR		BIT(4)
+#define I2C_RECEIVE_INTR	BIT(3)
+#define I2C_ACK_INTR		BIT(2)
+#define I2C_ARBITRATE_INTR	BIT(1)
+#define I2C_OVER_INTR		BIT(0)
+
+#define HIX5I2C_MAX_FREQ	400000		/* 400k */
+#define HIX5I2C_READ_OPERATION	0x01
+
+enum hix5hd2_i2c_state {
+	HIX5I2C_STAT_RW_ERR = -1,
+	HIX5I2C_STAT_INIT,
+	HIX5I2C_STAT_RW,
+	HIX5I2C_STAT_SND_STOP,
+	HIX5I2C_STAT_RW_SUCCESS,
+};
+
+struct hix5hd2_i2c_priv {
+	struct i2c_adapter adap;
+	struct i2c_msg *msg;
+	struct completion msg_complete;
+	unsigned int msg_idx;
+	unsigned int msg_len;
+	int stop;
+	void __iomem *regs;
+	struct clk *clk;
+	struct device *dev;
+	spinlock_t lock;	/* IRQ synchronization */
+	int err;
+	unsigned int freq;
+	enum hix5hd2_i2c_state state;
+};
+
+static u32 hix5hd2_i2c_clr_pend_irq(struct hix5hd2_i2c_priv *priv)
+{
+	u32 val = readl_relaxed(priv->regs + HIX5I2C_SR);
+
+	writel_relaxed(val, priv->regs + HIX5I2C_ICR);
+
+	return val;
+}
+
+static void hix5hd2_i2c_clr_all_irq(struct hix5hd2_i2c_priv *priv)
+{
+	writel_relaxed(I2C_CLEAR_ALL, priv->regs + HIX5I2C_ICR);
+}
+
+static void hix5hd2_i2c_disable_irq(struct hix5hd2_i2c_priv *priv)
+{
+	writel_relaxed(0, priv->regs + HIX5I2C_CTRL);
+}
+
+static void hix5hd2_i2c_enable_irq(struct hix5hd2_i2c_priv *priv)
+{
+	writel_relaxed(I2C_ENABLE | I2C_UNMASK_TOTAL | I2C_UNMASK_ALL,
+		       priv->regs + HIX5I2C_CTRL);
+}
+
+static void hix5hd2_i2c_drv_setrate(struct hix5hd2_i2c_priv *priv)
+{
+	u32 rate, val;
+	u32 scl, sysclock;
+
+	/* close all i2c interrupt */
+	val = readl_relaxed(priv->regs + HIX5I2C_CTRL);
+	writel_relaxed(val & (~I2C_UNMASK_TOTAL), priv->regs + HIX5I2C_CTRL);
+
+	rate = priv->freq;
+	sysclock = clk_get_rate(priv->clk);
+	scl = (sysclock / (rate * 2)) / 2 - 1;
+	writel_relaxed(scl, priv->regs + HIX5I2C_SCL_H);
+	writel_relaxed(scl, priv->regs + HIX5I2C_SCL_L);
+
+	/* restore original interrupt*/
+	writel_relaxed(val, priv->regs + HIX5I2C_CTRL);
+
+	dev_dbg(priv->dev, "%s: sysclock=%d, rate=%d, scl=%d\n",
+		__func__, sysclock, rate, scl);
+}
+
+static void hix5hd2_i2c_init(struct hix5hd2_i2c_priv *priv)
+{
+	hix5hd2_i2c_disable_irq(priv);
+	hix5hd2_i2c_drv_setrate(priv);
+	hix5hd2_i2c_clr_all_irq(priv);
+	hix5hd2_i2c_enable_irq(priv);
+}
+
+static void hix5hd2_i2c_reset(struct hix5hd2_i2c_priv *priv)
+{
+	clk_disable_unprepare(priv->clk);
+	msleep(20);
+	clk_prepare_enable(priv->clk);
+	hix5hd2_i2c_init(priv);
+}
+
+static int hix5hd2_i2c_wait_bus_idle(struct hix5hd2_i2c_priv *priv)
+{
+	unsigned long stop_time;
+	u32 int_status;
+
+	/* wait for 100 milli seconds for the bus to be idle */
+	stop_time = jiffies + msecs_to_jiffies(100);
+	do {
+		int_status = hix5hd2_i2c_clr_pend_irq(priv);
+		if (!(int_status & I2C_BUSY))
+			return 0;
+
+		usleep_range(50, 200);
+	} while (time_before(jiffies, stop_time));
+
+	return -EBUSY;
+}
+
+static void hix5hd2_rw_over(struct hix5hd2_i2c_priv *priv)
+{
+	if (priv->state == HIX5I2C_STAT_SND_STOP)
+		dev_dbg(priv->dev, "%s: rw and send stop over\n", __func__);
+	else
+		dev_dbg(priv->dev, "%s: have not data to send\n", __func__);
+
+	priv->state = HIX5I2C_STAT_RW_SUCCESS;
+	priv->err = 0;
+}
+
+static void hix5hd2_rw_handle_stop(struct hix5hd2_i2c_priv *priv)
+{
+	if (priv->stop) {
+		priv->state = HIX5I2C_STAT_SND_STOP;
+		writel_relaxed(I2C_STOP, priv->regs + HIX5I2C_COM);
+	} else {
+		hix5hd2_rw_over(priv);
+	}
+}
+
+static void hix5hd2_read_handle(struct hix5hd2_i2c_priv *priv)
+{
+	if (priv->msg_len == 1) {
+		/* the last byte don't need send ACK */
+		writel_relaxed(I2C_READ | I2C_NO_ACK, priv->regs + HIX5I2C_COM);
+	} else if (priv->msg_len > 1) {
+		/* if i2c master receive data will send ACK */
+		writel_relaxed(I2C_READ, priv->regs + HIX5I2C_COM);
+	} else {
+		hix5hd2_rw_handle_stop(priv);
+	}
+}
+
+static void hix5hd2_write_handle(struct hix5hd2_i2c_priv *priv)
+{
+	u8 data;
+
+	if (priv->msg_len > 0) {
+		data = priv->msg->buf[priv->msg_idx++];
+		writel_relaxed(data, priv->regs + HIX5I2C_TXR);
+		writel_relaxed(I2C_WRITE, priv->regs + HIX5I2C_COM);
+	} else {
+		hix5hd2_rw_handle_stop(priv);
+	}
+}
+
+static int hix5hd2_rw_preprocess(struct hix5hd2_i2c_priv *priv)
+{
+	u8 data;
+
+	if (priv->state == HIX5I2C_STAT_INIT) {
+		priv->state = HIX5I2C_STAT_RW;
+	} else if (priv->state == HIX5I2C_STAT_RW) {
+		if (priv->msg->flags & I2C_M_RD) {
+			data = readl_relaxed(priv->regs + HIX5I2C_RXR);
+			priv->msg->buf[priv->msg_idx++] = data;
+		}
+		priv->msg_len--;
+	} else {
+		dev_dbg(priv->dev, "%s: error: priv->state = %d, msg_len = %d\n",
+			__func__, priv->state, priv->msg_len);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static irqreturn_t hix5hd2_i2c_irq(int irqno, void *dev_id)
+{
+	struct hix5hd2_i2c_priv *priv = dev_id;
+	u32 int_status;
+	int ret;
+
+	spin_lock(&priv->lock);
+
+	int_status = hix5hd2_i2c_clr_pend_irq(priv);
+
+	/* handle error */
+	if (int_status & I2C_ARBITRATE_INTR) {
+		/* bus error */
+		dev_dbg(priv->dev, "ARB bus loss\n");
+		priv->err = -EAGAIN;
+		priv->state = HIX5I2C_STAT_RW_ERR;
+		goto stop;
+	} else if (int_status & I2C_ACK_INTR) {
+		/* ack error */
+		dev_dbg(priv->dev, "No ACK from device\n");
+		priv->err = -ENXIO;
+		priv->state = HIX5I2C_STAT_RW_ERR;
+		goto stop;
+	}
+
+	if (int_status & I2C_OVER_INTR) {
+		if (priv->msg_len > 0) {
+			ret = hix5hd2_rw_preprocess(priv);
+			if (ret) {
+				priv->err = ret;
+				priv->state = HIX5I2C_STAT_RW_ERR;
+				goto stop;
+			}
+			if (priv->msg->flags & I2C_M_RD)
+				hix5hd2_read_handle(priv);
+			else
+				hix5hd2_write_handle(priv);
+		} else {
+			hix5hd2_rw_over(priv);
+		}
+	}
+
+stop:
+	if ((priv->state == HIX5I2C_STAT_RW_SUCCESS &&
+	     priv->msg->len == priv->msg_idx) ||
+	    (priv->state == HIX5I2C_STAT_RW_ERR)) {
+		hix5hd2_i2c_disable_irq(priv);
+		hix5hd2_i2c_clr_pend_irq(priv);
+		complete(&priv->msg_complete);
+	}
+
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	hix5hd2_i2c_clr_all_irq(priv);
+	hix5hd2_i2c_enable_irq(priv);
+
+	if (priv->msg->flags & I2C_M_RD)
+		writel_relaxed((priv->msg->addr << 1) | HIX5I2C_READ_OPERATION,
+			       priv->regs + HIX5I2C_TXR);
+	else
+		writel_relaxed(priv->msg->addr << 1,
+			       priv->regs + HIX5I2C_TXR);
+
+	writel_relaxed(I2C_WRITE | I2C_START, priv->regs + HIX5I2C_COM);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv,
+				struct i2c_msg *msgs, int stop)
+{
+	unsigned long timeout;
+	int ret;
+
+	priv->msg = msgs;
+	priv->msg_idx = 0;
+	priv->msg_len = priv->msg->len;
+	priv->stop = stop;
+	priv->err = 0;
+	priv->state = HIX5I2C_STAT_INIT;
+
+	reinit_completion(&priv->msg_complete);
+	hix5hd2_i2c_message_start(priv, stop);
+
+	timeout = wait_for_completion_timeout(&priv->msg_complete,
+					      priv->adap.timeout);
+	if (timeout == 0) {
+		priv->state = HIX5I2C_STAT_RW_ERR;
+		priv->err = -ETIMEDOUT;
+		dev_warn(priv->dev, "%s timeout=%d\n",
+			 msgs->flags & I2C_M_RD ? "rx" : "tx",
+			 priv->adap.timeout);
+	}
+	ret = priv->state;
+
+	/*
+	 * If this is the last message to be transfered (stop == 1)
+	 * Then check if the bus can be brought back to idle.
+	 */
+	if (priv->state == HIX5I2C_STAT_RW_SUCCESS && stop)
+		ret = hix5hd2_i2c_wait_bus_idle(priv);
+
+	if (ret < 0)
+		hix5hd2_i2c_reset(priv);
+
+	return priv->err;
+}
+
+static int hix5hd2_i2c_xfer(struct i2c_adapter *adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct hix5hd2_i2c_priv *priv = i2c_get_adapdata(adap);
+	int i, ret, stop;
+
+	pm_runtime_get_sync(priv->dev);
+
+	for (i = 0; i < num; i++, msgs++) {
+		stop = (i == num - 1);
+		ret = hix5hd2_i2c_xfer_msg(priv, msgs, stop);
+		if (ret < 0)
+			goto out;
+	}
+
+	if (i == num) {
+		ret = num;
+	} else {
+		/* Only one message, cannot access the device */
+		if (i == 1)
+			ret = -EREMOTEIO;
+		else
+			ret = i;
+
+		dev_warn(priv->dev, "xfer message failed\n");
+	}
+
+out:
+	pm_runtime_mark_last_busy(priv->dev);
+	pm_runtime_put_autosuspend(priv->dev);
+	return ret;
+}
+
+static u32 hix5hd2_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm hix5hd2_i2c_algorithm = {
+	.master_xfer		= hix5hd2_i2c_xfer,
+	.functionality		= hix5hd2_i2c_func,
+};
+
+static int hix5hd2_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct hix5hd2_i2c_priv *priv;
+	struct resource *mem;
+	unsigned int freq;
+	int irq, ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (of_property_read_u32(np, "clock-frequency", &freq)) {
+		/* use 100k as default value */
+		priv->freq = 100000;
+	} else {
+		if (freq > HIX5I2C_MAX_FREQ) {
+			priv->freq = HIX5I2C_MAX_FREQ;
+			dev_warn(priv->dev, "use max freq %d instead\n",
+				 HIX5I2C_MAX_FREQ);
+		} else {
+			priv->freq = freq;
+		}
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->regs = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(priv->regs))
+		return PTR_ERR(priv->regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0) {
+		dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
+		return irq;
+	}
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		return PTR_ERR(priv->clk);
+	}
+	clk_prepare_enable(priv->clk);
+
+	strlcpy(priv->adap.name, "hix5hd2-i2c", sizeof(priv->adap.name));
+	priv->dev = &pdev->dev;
+	priv->adap.owner = THIS_MODULE;
+	priv->adap.algo = &hix5hd2_i2c_algorithm;
+	priv->adap.retries = 3;
+	priv->adap.dev.of_node = np;
+	priv->adap.algo_data = priv;
+	priv->adap.dev.parent = &pdev->dev;
+	i2c_set_adapdata(&priv->adap, priv);
+	platform_set_drvdata(pdev, priv);
+	spin_lock_init(&priv->lock);
+	init_completion(&priv->msg_complete);
+
+	hix5hd2_i2c_init(priv);
+
+	ret = devm_request_irq(&pdev->dev, irq, hix5hd2_i2c_irq,
+			       IRQF_NO_SUSPEND | IRQF_ONESHOT,
+			       dev_name(&pdev->dev), priv);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", irq);
+		goto err_clk;
+	}
+
+	ret = i2c_add_adapter(&priv->adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+		goto err_clk;
+	}
+
+	pm_suspend_ignore_children(&pdev->dev, true);
+	pm_runtime_set_autosuspend_delay(priv->dev, MSEC_PER_SEC);
+	pm_runtime_use_autosuspend(priv->dev);
+	pm_runtime_set_active(priv->dev);
+	pm_runtime_enable(priv->dev);
+
+	return ret;
+
+err_clk:
+	clk_disable_unprepare(priv->clk);
+	return ret;
+}
+
+static int hix5hd2_i2c_remove(struct platform_device *pdev)
+{
+	struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&priv->adap);
+	pm_runtime_disable(priv->dev);
+	pm_runtime_set_suspended(priv->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int hix5hd2_i2c_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+static int hix5hd2_i2c_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
+
+	clk_prepare_enable(priv->clk);
+	hix5hd2_i2c_init(priv);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops hix5hd2_i2c_pm_ops = {
+	SET_PM_RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend,
+			      hix5hd2_i2c_runtime_resume,
+			      NULL)
+};
+
+static const struct of_device_id hix5hd2_i2c_match[] = {
+	{ .compatible = "hisilicon,hix5hd2-i2c" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hix5hd2_i2c_match);
+
+static struct platform_driver hix5hd2_i2c_driver = {
+	.probe		= hix5hd2_i2c_probe,
+	.remove		= hix5hd2_i2c_remove,
+	.driver		= {
+		.name	= "hix5hd2-i2c",
+		.pm	= &hix5hd2_i2c_pm_ops,
+		.of_match_table = hix5hd2_i2c_match,
+	},
+};
+
+module_platform_driver(hix5hd2_i2c_driver);
+
+MODULE_DESCRIPTION("Hix5hd2 I2C Bus driver");
+MODULE_AUTHOR("Wei Yan <sledge.yanwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-hix5hd2");
-- 
1.7.9.5

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

* [PATCH v2 2/3] i2c: hix5hd2: add i2c controller driver
@ 2014-09-28  4:22     ` Zhangfei Gao
  0 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: linux-arm-kernel

From: Wei Yan <sledge.yanwei@huawei.com>

I2C drivers for hix5hd2 soc series, including following chipset
Hi3716CV200, Hi3719CV100, Hi3718CV100, Hi3719MV100, Hi3718MV100.

Signed-off-by: Wei Yan <sledge.yanwei@huawei.com>
Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
---
 drivers/i2c/busses/Kconfig       |   10 +
 drivers/i2c/busses/Makefile      |    1 +
 drivers/i2c/busses/i2c-hix5hd2.c |  554 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 565 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-hix5hd2.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 2ac87fa..ba0f43c 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -77,6 +77,16 @@ config I2C_AMD8111
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-amd8111.
 
+config I2C_HIX5HD2
+	tristate "Hix5hd2 high-speed I2C driver"
+	depends on ARCH_HIX5HD2
+	help
+	  Say Y here to include support for high-speed I2C controller in the
+	  Hisilicon based hix5hd2 SoCs.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-hix5hd2.
+
 config I2C_I801
 	tristate "Intel 82801 (ICH/PCH)"
 	depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 49bf07e..9739938 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_I2C_EG20T)		+= i2c-eg20t.o
 obj-$(CONFIG_I2C_EXYNOS5)	+= i2c-exynos5.o
 obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o
+obj-$(CONFIG_I2C_HIX5HD2)	+= i2c-hix5hd2.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c
new file mode 100644
index 0000000..4b18bde
--- /dev/null
+++ b/drivers/i2c/busses/i2c-hix5hd2.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * 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.
+ *
+ * Now only support 7 bit address.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* Register Map */
+#define HIX5I2C_CTRL		0x00
+#define HIX5I2C_COM		0x04
+#define HIX5I2C_ICR		0x08
+#define HIX5I2C_SR		0x0c
+#define HIX5I2C_SCL_H		0x10
+#define HIX5I2C_SCL_L		0x14
+#define HIX5I2C_TXR		0x18
+#define HIX5I2C_RXR		0x1c
+
+/* I2C_CTRL_REG */
+#define I2C_ENABLE		BIT(8)
+#define I2C_UNMASK_TOTAL	BIT(7)
+#define I2C_UNMASK_START	BIT(6)
+#define I2C_UNMASK_END		BIT(5)
+#define I2C_UNMASK_SEND		BIT(4)
+#define I2C_UNMASK_RECEIVE	BIT(3)
+#define I2C_UNMASK_ACK		BIT(2)
+#define I2C_UNMASK_ARBITRATE	BIT(1)
+#define I2C_UNMASK_OVER		BIT(0)
+#define I2C_UNMASK_ALL		(I2C_UNMASK_ACK | I2C_UNMASK_OVER)
+
+/* I2C_COM_REG */
+#define I2C_NO_ACK		BIT(4)
+#define I2C_START		BIT(3)
+#define I2C_READ		BIT(2)
+#define I2C_WRITE		BIT(1)
+#define I2C_STOP		BIT(0)
+
+/* I2C_ICR_REG */
+#define I2C_CLEAR_START		BIT(6)
+#define I2C_CLEAR_END		BIT(5)
+#define I2C_CLEAR_SEND		BIT(4)
+#define I2C_CLEAR_RECEIVE	BIT(3)
+#define I2C_CLEAR_ACK		BIT(2)
+#define I2C_CLEAR_ARBITRATE	BIT(1)
+#define I2C_CLEAR_OVER		BIT(0)
+#define I2C_CLEAR_ALL		(I2C_CLEAR_START | I2C_CLEAR_END | \
+				I2C_CLEAR_SEND | I2C_CLEAR_RECEIVE | \
+				I2C_CLEAR_ACK | I2C_CLEAR_ARBITRATE | \
+				I2C_CLEAR_OVER)
+
+/* I2C_SR_REG */
+#define I2C_BUSY		BIT(7)
+#define I2C_START_INTR		BIT(6)
+#define I2C_END_INTR		BIT(5)
+#define I2C_SEND_INTR		BIT(4)
+#define I2C_RECEIVE_INTR	BIT(3)
+#define I2C_ACK_INTR		BIT(2)
+#define I2C_ARBITRATE_INTR	BIT(1)
+#define I2C_OVER_INTR		BIT(0)
+
+#define HIX5I2C_MAX_FREQ	400000		/* 400k */
+#define HIX5I2C_READ_OPERATION	0x01
+
+enum hix5hd2_i2c_state {
+	HIX5I2C_STAT_RW_ERR = -1,
+	HIX5I2C_STAT_INIT,
+	HIX5I2C_STAT_RW,
+	HIX5I2C_STAT_SND_STOP,
+	HIX5I2C_STAT_RW_SUCCESS,
+};
+
+struct hix5hd2_i2c_priv {
+	struct i2c_adapter adap;
+	struct i2c_msg *msg;
+	struct completion msg_complete;
+	unsigned int msg_idx;
+	unsigned int msg_len;
+	int stop;
+	void __iomem *regs;
+	struct clk *clk;
+	struct device *dev;
+	spinlock_t lock;	/* IRQ synchronization */
+	int err;
+	unsigned int freq;
+	enum hix5hd2_i2c_state state;
+};
+
+static u32 hix5hd2_i2c_clr_pend_irq(struct hix5hd2_i2c_priv *priv)
+{
+	u32 val = readl_relaxed(priv->regs + HIX5I2C_SR);
+
+	writel_relaxed(val, priv->regs + HIX5I2C_ICR);
+
+	return val;
+}
+
+static void hix5hd2_i2c_clr_all_irq(struct hix5hd2_i2c_priv *priv)
+{
+	writel_relaxed(I2C_CLEAR_ALL, priv->regs + HIX5I2C_ICR);
+}
+
+static void hix5hd2_i2c_disable_irq(struct hix5hd2_i2c_priv *priv)
+{
+	writel_relaxed(0, priv->regs + HIX5I2C_CTRL);
+}
+
+static void hix5hd2_i2c_enable_irq(struct hix5hd2_i2c_priv *priv)
+{
+	writel_relaxed(I2C_ENABLE | I2C_UNMASK_TOTAL | I2C_UNMASK_ALL,
+		       priv->regs + HIX5I2C_CTRL);
+}
+
+static void hix5hd2_i2c_drv_setrate(struct hix5hd2_i2c_priv *priv)
+{
+	u32 rate, val;
+	u32 scl, sysclock;
+
+	/* close all i2c interrupt */
+	val = readl_relaxed(priv->regs + HIX5I2C_CTRL);
+	writel_relaxed(val & (~I2C_UNMASK_TOTAL), priv->regs + HIX5I2C_CTRL);
+
+	rate = priv->freq;
+	sysclock = clk_get_rate(priv->clk);
+	scl = (sysclock / (rate * 2)) / 2 - 1;
+	writel_relaxed(scl, priv->regs + HIX5I2C_SCL_H);
+	writel_relaxed(scl, priv->regs + HIX5I2C_SCL_L);
+
+	/* restore original interrupt*/
+	writel_relaxed(val, priv->regs + HIX5I2C_CTRL);
+
+	dev_dbg(priv->dev, "%s: sysclock=%d, rate=%d, scl=%d\n",
+		__func__, sysclock, rate, scl);
+}
+
+static void hix5hd2_i2c_init(struct hix5hd2_i2c_priv *priv)
+{
+	hix5hd2_i2c_disable_irq(priv);
+	hix5hd2_i2c_drv_setrate(priv);
+	hix5hd2_i2c_clr_all_irq(priv);
+	hix5hd2_i2c_enable_irq(priv);
+}
+
+static void hix5hd2_i2c_reset(struct hix5hd2_i2c_priv *priv)
+{
+	clk_disable_unprepare(priv->clk);
+	msleep(20);
+	clk_prepare_enable(priv->clk);
+	hix5hd2_i2c_init(priv);
+}
+
+static int hix5hd2_i2c_wait_bus_idle(struct hix5hd2_i2c_priv *priv)
+{
+	unsigned long stop_time;
+	u32 int_status;
+
+	/* wait for 100 milli seconds for the bus to be idle */
+	stop_time = jiffies + msecs_to_jiffies(100);
+	do {
+		int_status = hix5hd2_i2c_clr_pend_irq(priv);
+		if (!(int_status & I2C_BUSY))
+			return 0;
+
+		usleep_range(50, 200);
+	} while (time_before(jiffies, stop_time));
+
+	return -EBUSY;
+}
+
+static void hix5hd2_rw_over(struct hix5hd2_i2c_priv *priv)
+{
+	if (priv->state == HIX5I2C_STAT_SND_STOP)
+		dev_dbg(priv->dev, "%s: rw and send stop over\n", __func__);
+	else
+		dev_dbg(priv->dev, "%s: have not data to send\n", __func__);
+
+	priv->state = HIX5I2C_STAT_RW_SUCCESS;
+	priv->err = 0;
+}
+
+static void hix5hd2_rw_handle_stop(struct hix5hd2_i2c_priv *priv)
+{
+	if (priv->stop) {
+		priv->state = HIX5I2C_STAT_SND_STOP;
+		writel_relaxed(I2C_STOP, priv->regs + HIX5I2C_COM);
+	} else {
+		hix5hd2_rw_over(priv);
+	}
+}
+
+static void hix5hd2_read_handle(struct hix5hd2_i2c_priv *priv)
+{
+	if (priv->msg_len == 1) {
+		/* the last byte don't need send ACK */
+		writel_relaxed(I2C_READ | I2C_NO_ACK, priv->regs + HIX5I2C_COM);
+	} else if (priv->msg_len > 1) {
+		/* if i2c master receive data will send ACK */
+		writel_relaxed(I2C_READ, priv->regs + HIX5I2C_COM);
+	} else {
+		hix5hd2_rw_handle_stop(priv);
+	}
+}
+
+static void hix5hd2_write_handle(struct hix5hd2_i2c_priv *priv)
+{
+	u8 data;
+
+	if (priv->msg_len > 0) {
+		data = priv->msg->buf[priv->msg_idx++];
+		writel_relaxed(data, priv->regs + HIX5I2C_TXR);
+		writel_relaxed(I2C_WRITE, priv->regs + HIX5I2C_COM);
+	} else {
+		hix5hd2_rw_handle_stop(priv);
+	}
+}
+
+static int hix5hd2_rw_preprocess(struct hix5hd2_i2c_priv *priv)
+{
+	u8 data;
+
+	if (priv->state == HIX5I2C_STAT_INIT) {
+		priv->state = HIX5I2C_STAT_RW;
+	} else if (priv->state == HIX5I2C_STAT_RW) {
+		if (priv->msg->flags & I2C_M_RD) {
+			data = readl_relaxed(priv->regs + HIX5I2C_RXR);
+			priv->msg->buf[priv->msg_idx++] = data;
+		}
+		priv->msg_len--;
+	} else {
+		dev_dbg(priv->dev, "%s: error: priv->state = %d, msg_len = %d\n",
+			__func__, priv->state, priv->msg_len);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static irqreturn_t hix5hd2_i2c_irq(int irqno, void *dev_id)
+{
+	struct hix5hd2_i2c_priv *priv = dev_id;
+	u32 int_status;
+	int ret;
+
+	spin_lock(&priv->lock);
+
+	int_status = hix5hd2_i2c_clr_pend_irq(priv);
+
+	/* handle error */
+	if (int_status & I2C_ARBITRATE_INTR) {
+		/* bus error */
+		dev_dbg(priv->dev, "ARB bus loss\n");
+		priv->err = -EAGAIN;
+		priv->state = HIX5I2C_STAT_RW_ERR;
+		goto stop;
+	} else if (int_status & I2C_ACK_INTR) {
+		/* ack error */
+		dev_dbg(priv->dev, "No ACK from device\n");
+		priv->err = -ENXIO;
+		priv->state = HIX5I2C_STAT_RW_ERR;
+		goto stop;
+	}
+
+	if (int_status & I2C_OVER_INTR) {
+		if (priv->msg_len > 0) {
+			ret = hix5hd2_rw_preprocess(priv);
+			if (ret) {
+				priv->err = ret;
+				priv->state = HIX5I2C_STAT_RW_ERR;
+				goto stop;
+			}
+			if (priv->msg->flags & I2C_M_RD)
+				hix5hd2_read_handle(priv);
+			else
+				hix5hd2_write_handle(priv);
+		} else {
+			hix5hd2_rw_over(priv);
+		}
+	}
+
+stop:
+	if ((priv->state == HIX5I2C_STAT_RW_SUCCESS &&
+	     priv->msg->len == priv->msg_idx) ||
+	    (priv->state == HIX5I2C_STAT_RW_ERR)) {
+		hix5hd2_i2c_disable_irq(priv);
+		hix5hd2_i2c_clr_pend_irq(priv);
+		complete(&priv->msg_complete);
+	}
+
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	hix5hd2_i2c_clr_all_irq(priv);
+	hix5hd2_i2c_enable_irq(priv);
+
+	if (priv->msg->flags & I2C_M_RD)
+		writel_relaxed((priv->msg->addr << 1) | HIX5I2C_READ_OPERATION,
+			       priv->regs + HIX5I2C_TXR);
+	else
+		writel_relaxed(priv->msg->addr << 1,
+			       priv->regs + HIX5I2C_TXR);
+
+	writel_relaxed(I2C_WRITE | I2C_START, priv->regs + HIX5I2C_COM);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv,
+				struct i2c_msg *msgs, int stop)
+{
+	unsigned long timeout;
+	int ret;
+
+	priv->msg = msgs;
+	priv->msg_idx = 0;
+	priv->msg_len = priv->msg->len;
+	priv->stop = stop;
+	priv->err = 0;
+	priv->state = HIX5I2C_STAT_INIT;
+
+	reinit_completion(&priv->msg_complete);
+	hix5hd2_i2c_message_start(priv, stop);
+
+	timeout = wait_for_completion_timeout(&priv->msg_complete,
+					      priv->adap.timeout);
+	if (timeout == 0) {
+		priv->state = HIX5I2C_STAT_RW_ERR;
+		priv->err = -ETIMEDOUT;
+		dev_warn(priv->dev, "%s timeout=%d\n",
+			 msgs->flags & I2C_M_RD ? "rx" : "tx",
+			 priv->adap.timeout);
+	}
+	ret = priv->state;
+
+	/*
+	 * If this is the last message to be transfered (stop == 1)
+	 * Then check if the bus can be brought back to idle.
+	 */
+	if (priv->state == HIX5I2C_STAT_RW_SUCCESS && stop)
+		ret = hix5hd2_i2c_wait_bus_idle(priv);
+
+	if (ret < 0)
+		hix5hd2_i2c_reset(priv);
+
+	return priv->err;
+}
+
+static int hix5hd2_i2c_xfer(struct i2c_adapter *adap,
+			    struct i2c_msg *msgs, int num)
+{
+	struct hix5hd2_i2c_priv *priv = i2c_get_adapdata(adap);
+	int i, ret, stop;
+
+	pm_runtime_get_sync(priv->dev);
+
+	for (i = 0; i < num; i++, msgs++) {
+		stop = (i == num - 1);
+		ret = hix5hd2_i2c_xfer_msg(priv, msgs, stop);
+		if (ret < 0)
+			goto out;
+	}
+
+	if (i == num) {
+		ret = num;
+	} else {
+		/* Only one message, cannot access the device */
+		if (i == 1)
+			ret = -EREMOTEIO;
+		else
+			ret = i;
+
+		dev_warn(priv->dev, "xfer message failed\n");
+	}
+
+out:
+	pm_runtime_mark_last_busy(priv->dev);
+	pm_runtime_put_autosuspend(priv->dev);
+	return ret;
+}
+
+static u32 hix5hd2_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm hix5hd2_i2c_algorithm = {
+	.master_xfer		= hix5hd2_i2c_xfer,
+	.functionality		= hix5hd2_i2c_func,
+};
+
+static int hix5hd2_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct hix5hd2_i2c_priv *priv;
+	struct resource *mem;
+	unsigned int freq;
+	int irq, ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (of_property_read_u32(np, "clock-frequency", &freq)) {
+		/* use 100k as default value */
+		priv->freq = 100000;
+	} else {
+		if (freq > HIX5I2C_MAX_FREQ) {
+			priv->freq = HIX5I2C_MAX_FREQ;
+			dev_warn(priv->dev, "use max freq %d instead\n",
+				 HIX5I2C_MAX_FREQ);
+		} else {
+			priv->freq = freq;
+		}
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->regs = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(priv->regs))
+		return PTR_ERR(priv->regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0) {
+		dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
+		return irq;
+	}
+
+	priv->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		return PTR_ERR(priv->clk);
+	}
+	clk_prepare_enable(priv->clk);
+
+	strlcpy(priv->adap.name, "hix5hd2-i2c", sizeof(priv->adap.name));
+	priv->dev = &pdev->dev;
+	priv->adap.owner = THIS_MODULE;
+	priv->adap.algo = &hix5hd2_i2c_algorithm;
+	priv->adap.retries = 3;
+	priv->adap.dev.of_node = np;
+	priv->adap.algo_data = priv;
+	priv->adap.dev.parent = &pdev->dev;
+	i2c_set_adapdata(&priv->adap, priv);
+	platform_set_drvdata(pdev, priv);
+	spin_lock_init(&priv->lock);
+	init_completion(&priv->msg_complete);
+
+	hix5hd2_i2c_init(priv);
+
+	ret = devm_request_irq(&pdev->dev, irq, hix5hd2_i2c_irq,
+			       IRQF_NO_SUSPEND | IRQF_ONESHOT,
+			       dev_name(&pdev->dev), priv);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", irq);
+		goto err_clk;
+	}
+
+	ret = i2c_add_adapter(&priv->adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to add bus to i2c core\n");
+		goto err_clk;
+	}
+
+	pm_suspend_ignore_children(&pdev->dev, true);
+	pm_runtime_set_autosuspend_delay(priv->dev, MSEC_PER_SEC);
+	pm_runtime_use_autosuspend(priv->dev);
+	pm_runtime_set_active(priv->dev);
+	pm_runtime_enable(priv->dev);
+
+	return ret;
+
+err_clk:
+	clk_disable_unprepare(priv->clk);
+	return ret;
+}
+
+static int hix5hd2_i2c_remove(struct platform_device *pdev)
+{
+	struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&priv->adap);
+	pm_runtime_disable(priv->dev);
+	pm_runtime_set_suspended(priv->dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int hix5hd2_i2c_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+static int hix5hd2_i2c_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev);
+
+	clk_prepare_enable(priv->clk);
+	hix5hd2_i2c_init(priv);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops hix5hd2_i2c_pm_ops = {
+	SET_PM_RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend,
+			      hix5hd2_i2c_runtime_resume,
+			      NULL)
+};
+
+static const struct of_device_id hix5hd2_i2c_match[] = {
+	{ .compatible = "hisilicon,hix5hd2-i2c" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, hix5hd2_i2c_match);
+
+static struct platform_driver hix5hd2_i2c_driver = {
+	.probe		= hix5hd2_i2c_probe,
+	.remove		= hix5hd2_i2c_remove,
+	.driver		= {
+		.name	= "hix5hd2-i2c",
+		.pm	= &hix5hd2_i2c_pm_ops,
+		.of_match_table = hix5hd2_i2c_match,
+	},
+};
+
+module_platform_driver(hix5hd2_i2c_driver);
+
+MODULE_DESCRIPTION("Hix5hd2 I2C Bus driver");
+MODULE_AUTHOR("Wei Yan <sledge.yanwei@huawei.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-hix5hd2");
-- 
1.7.9.5

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

* [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
  2014-09-28  4:22 ` Zhangfei Gao
@ 2014-09-28  4:22     ` Zhangfei Gao
  -1 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: Wolfram Sang, Arnd Bergmann, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Zhangfei Gao

Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 arch/arm/boot/dts/hisi-x5hd2.dtsi |   60 +++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/arch/arm/boot/dts/hisi-x5hd2.dtsi b/arch/arm/boot/dts/hisi-x5hd2.dtsi
index d3d99fb..17d0637 100644
--- a/arch/arm/boot/dts/hisi-x5hd2.dtsi
+++ b/arch/arm/boot/dts/hisi-x5hd2.dtsi
@@ -476,5 +476,65 @@
                         interrupts = <0 70 4>;
                         clocks = <&clock HIX5HD2_SATA_CLK>;
 		};
+
+		i2c0: i2c@b10000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb10000 0x1000>;
+			interrupts = <0 38 4>;
+			clocks = <&clock HIX5HD2_I2C0_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c1: i2c@b11000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb11000 0x1000>;
+			interrupts = <0 39 4>;
+			clocks = <&clock HIX5HD2_I2C1_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c2: i2c@b12000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb12000 0x1000>;
+			interrupts = <0 40 4>;
+			clocks = <&clock HIX5HD2_I2C2_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c3: i2c@b13000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb13000 0x1000>;
+			interrupts = <0 41 4>;
+			clocks = <&clock HIX5HD2_I2C3_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c4: i2c@b16000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb16000 0x1000>;
+			interrupts = <0 43 4>;
+			clocks = <&clock HIX5HD2_I2C4_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c5: i2c@b17000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb17000 0x1000>;
+			interrupts = <0 44 4>;
+			clocks = <&clock HIX5HD2_I2C5_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 	};
 };
-- 
1.7.9.5

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

* [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
@ 2014-09-28  4:22     ` Zhangfei Gao
  0 siblings, 0 replies; 22+ messages in thread
From: Zhangfei Gao @ 2014-09-28  4:22 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
---
 arch/arm/boot/dts/hisi-x5hd2.dtsi |   60 +++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/arch/arm/boot/dts/hisi-x5hd2.dtsi b/arch/arm/boot/dts/hisi-x5hd2.dtsi
index d3d99fb..17d0637 100644
--- a/arch/arm/boot/dts/hisi-x5hd2.dtsi
+++ b/arch/arm/boot/dts/hisi-x5hd2.dtsi
@@ -476,5 +476,65 @@
                         interrupts = <0 70 4>;
                         clocks = <&clock HIX5HD2_SATA_CLK>;
 		};
+
+		i2c0: i2c at b10000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb10000 0x1000>;
+			interrupts = <0 38 4>;
+			clocks = <&clock HIX5HD2_I2C0_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c1: i2c at b11000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb11000 0x1000>;
+			interrupts = <0 39 4>;
+			clocks = <&clock HIX5HD2_I2C1_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c2: i2c at b12000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb12000 0x1000>;
+			interrupts = <0 40 4>;
+			clocks = <&clock HIX5HD2_I2C2_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c3: i2c at b13000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb13000 0x1000>;
+			interrupts = <0 41 4>;
+			clocks = <&clock HIX5HD2_I2C3_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c4: i2c at b16000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb16000 0x1000>;
+			interrupts = <0 43 4>;
+			clocks = <&clock HIX5HD2_I2C4_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c5: i2c at b17000 {
+			compatible = "hisilicon,hix5hd2-i2c";
+			reg = <0xb17000 0x1000>;
+			interrupts = <0 44 4>;
+			clocks = <&clock HIX5HD2_I2C5_RST>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
 	};
 };
-- 
1.7.9.5

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

* Re: [PATCH v2 2/3] i2c: hix5hd2: add i2c controller driver
  2014-09-28  4:22     ` Zhangfei Gao
@ 2014-09-29 12:49         ` zhangfei
  -1 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2014-09-29 12:49 UTC (permalink / raw)
  To: Zhangfei Gao, Wolfram Sang, Arnd Bergmann,
	haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Wei Yan



On 09/28/2014 12:22 PM, Zhangfei Gao wrote:
> From: Wei Yan <sledge.yanwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
>
> I2C drivers for hix5hd2 soc series, including following chipset
> Hi3716CV200, Hi3719CV100, Hi3718CV100, Hi3719MV100, Hi3718MV100.
>
> Signed-off-by: Wei Yan <sledge.yanwei-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>   drivers/i2c/busses/Kconfig       |   10 +
>   drivers/i2c/busses/Makefile      |    1 +
>   drivers/i2c/busses/i2c-hix5hd2.c |  554 ++++++++++++++++++++++++++++++++++++++
>   3 files changed, 565 insertions(+)
>   create mode 100644 drivers/i2c/busses/i2c-hix5hd2.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 2ac87fa..ba0f43c 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -77,6 +77,16 @@ config I2C_AMD8111
>   	  This driver can also be built as a module.  If so, the module
>   	  will be called i2c-amd8111.
>
> +config I2C_HIX5HD2
> +	tristate "Hix5hd2 high-speed I2C driver"
> +	depends on ARCH_HIX5HD2

Would like to remove the dependence in next version to enable compile-test.
The commit 4c255791ffd6410f ("asm-generic: io: implement relaxed 
accessor macros as conditional wrappers") adds wrappers to asm-generic 
of {read,write}{b,w,l,q}_relaxed.

Thanks

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

* [PATCH v2 2/3] i2c: hix5hd2: add i2c controller driver
@ 2014-09-29 12:49         ` zhangfei
  0 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2014-09-29 12:49 UTC (permalink / raw)
  To: linux-arm-kernel



On 09/28/2014 12:22 PM, Zhangfei Gao wrote:
> From: Wei Yan <sledge.yanwei@huawei.com>
>
> I2C drivers for hix5hd2 soc series, including following chipset
> Hi3716CV200, Hi3719CV100, Hi3718CV100, Hi3719MV100, Hi3718MV100.
>
> Signed-off-by: Wei Yan <sledge.yanwei@huawei.com>
> Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
> ---
>   drivers/i2c/busses/Kconfig       |   10 +
>   drivers/i2c/busses/Makefile      |    1 +
>   drivers/i2c/busses/i2c-hix5hd2.c |  554 ++++++++++++++++++++++++++++++++++++++
>   3 files changed, 565 insertions(+)
>   create mode 100644 drivers/i2c/busses/i2c-hix5hd2.c
>
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 2ac87fa..ba0f43c 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -77,6 +77,16 @@ config I2C_AMD8111
>   	  This driver can also be built as a module.  If so, the module
>   	  will be called i2c-amd8111.
>
> +config I2C_HIX5HD2
> +	tristate "Hix5hd2 high-speed I2C driver"
> +	depends on ARCH_HIX5HD2

Would like to remove the dependence in next version to enable compile-test.
The commit 4c255791ffd6410f ("asm-generic: io: implement relaxed 
accessor macros as conditional wrappers") adds wrappers to asm-generic 
of {read,write}{b,w,l,q}_relaxed.

Thanks

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

* Re: [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
  2014-09-28  4:22     ` Zhangfei Gao
@ 2014-09-30  9:01         ` Arnd Bergmann
  -1 siblings, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2014-09-30  9:01 UTC (permalink / raw)
  To: Zhangfei Gao
  Cc: Wolfram Sang, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Wei Yan

On Sunday 28 September 2014 12:22:07 Zhangfei Gao wrote:
> +
> +Required properties:
> +- compatible: Must be "hisilicon,hix5hd2-i2c"
> +  Specifically, the following versions of the chipset are supported:
> +         Hi3716CV200 (support six I2C module)
> +         Hi3719CV100 (support six I2C module)
> +         Hi3718CV100 (support six I2C module)
> +         Hi3719MV100 (support two I2C module)
> +         Hi3718MV100 (support two I2C module)
> 

How do you detect the specific model? Is there a hardware register that
lets you know the type?
If you have a device specific "compatible" string, you should list all
the known strings.

	Arnd

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

* [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
@ 2014-09-30  9:01         ` Arnd Bergmann
  0 siblings, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2014-09-30  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 28 September 2014 12:22:07 Zhangfei Gao wrote:
> +
> +Required properties:
> +- compatible: Must be "hisilicon,hix5hd2-i2c"
> +  Specifically, the following versions of the chipset are supported:
> +         Hi3716CV200 (support six I2C module)
> +         Hi3719CV100 (support six I2C module)
> +         Hi3718CV100 (support six I2C module)
> +         Hi3719MV100 (support two I2C module)
> +         Hi3718MV100 (support two I2C module)
> 

How do you detect the specific model? Is there a hardware register that
lets you know the type?
If you have a device specific "compatible" string, you should list all
the known strings.

	Arnd

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

* Re: [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
  2014-09-28  4:22     ` Zhangfei Gao
@ 2014-09-30  9:02         ` Arnd Bergmann
  -1 siblings, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2014-09-30  9:02 UTC (permalink / raw)
  To: Zhangfei Gao
  Cc: Wolfram Sang, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Sunday 28 September 2014 12:22:09 Zhangfei Gao wrote:
> +
> +               i2c0: i2c@b10000 {
> +                       compatible = "hisilicon,hix5hd2-i2c";
> +                       reg = <0xb10000 0x1000>;
> +                       interrupts = <0 38 4>;
> +                       clocks = <&clock HIX5HD2_I2C0_RST>;
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +                       status = "disabled";
> +               };
> 

HIX5HD2_I2C0_RST is not defined anywhere, so this will result in the
same build error that has required reverting a lot of patches for the
3.18 merge window.

How do you plan to deal with the dependency in the future?

	Arnd

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

* [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
@ 2014-09-30  9:02         ` Arnd Bergmann
  0 siblings, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2014-09-30  9:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday 28 September 2014 12:22:09 Zhangfei Gao wrote:
> +
> +               i2c0: i2c at b10000 {
> +                       compatible = "hisilicon,hix5hd2-i2c";
> +                       reg = <0xb10000 0x1000>;
> +                       interrupts = <0 38 4>;
> +                       clocks = <&clock HIX5HD2_I2C0_RST>;
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +                       status = "disabled";
> +               };
> 

HIX5HD2_I2C0_RST is not defined anywhere, so this will result in the
same build error that has required reverting a lot of patches for the
3.18 merge window.

How do you plan to deal with the dependency in the future?

	Arnd

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

* Re: [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
  2014-09-30  9:02         ` Arnd Bergmann
@ 2014-09-30  9:21           ` zhangfei
  -1 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2014-09-30  9:21 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Wolfram Sang, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA



On 09/30/2014 05:02 PM, Arnd Bergmann wrote:
> On Sunday 28 September 2014 12:22:09 Zhangfei Gao wrote:
>> +
>> +               i2c0: i2c@b10000 {
>> +                       compatible = "hisilicon,hix5hd2-i2c";
>> +                       reg = <0xb10000 0x1000>;
>> +                       interrupts = <0 38 4>;
>> +                       clocks = <&clock HIX5HD2_I2C0_RST>;
>> +                       #address-cells = <1>;
>> +                       #size-cells = <0>;
>> +                       status = "disabled";
>> +               };
>>
>
> HIX5HD2_I2C0_RST is not defined anywhere, so this will result in the
> same build error that has required reverting a lot of patches for the
> 3.18 merge window.
>
> How do you plan to deal with the dependency in the future?
>

HIX5HD2_I2C0_RST in clock patch and already been merged through clock 
tree in 09/29, should be in 3.18-rc1 (not sure).
When clock patch are combined in the same rc, will send the dts patch.
Sorry for the build issue.

Thanks

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

* [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
@ 2014-09-30  9:21           ` zhangfei
  0 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2014-09-30  9:21 UTC (permalink / raw)
  To: linux-arm-kernel



On 09/30/2014 05:02 PM, Arnd Bergmann wrote:
> On Sunday 28 September 2014 12:22:09 Zhangfei Gao wrote:
>> +
>> +               i2c0: i2c at b10000 {
>> +                       compatible = "hisilicon,hix5hd2-i2c";
>> +                       reg = <0xb10000 0x1000>;
>> +                       interrupts = <0 38 4>;
>> +                       clocks = <&clock HIX5HD2_I2C0_RST>;
>> +                       #address-cells = <1>;
>> +                       #size-cells = <0>;
>> +                       status = "disabled";
>> +               };
>>
>
> HIX5HD2_I2C0_RST is not defined anywhere, so this will result in the
> same build error that has required reverting a lot of patches for the
> 3.18 merge window.
>
> How do you plan to deal with the dependency in the future?
>

HIX5HD2_I2C0_RST in clock patch and already been merged through clock 
tree in 09/29, should be in 3.18-rc1 (not sure).
When clock patch are combined in the same rc, will send the dts patch.
Sorry for the build issue.

Thanks

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

* Re: [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
  2014-09-30  9:01         ` Arnd Bergmann
@ 2014-09-30  9:25           ` zhangfei
  -1 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2014-09-30  9:25 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Wolfram Sang, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA, Wei Yan



On 09/30/2014 05:01 PM, Arnd Bergmann wrote:
> On Sunday 28 September 2014 12:22:07 Zhangfei Gao wrote:
>> +
>> +Required properties:
>> +- compatible: Must be "hisilicon,hix5hd2-i2c"
>> +  Specifically, the following versions of the chipset are supported:
>> +         Hi3716CV200 (support six I2C module)
>> +         Hi3719CV100 (support six I2C module)
>> +         Hi3718CV100 (support six I2C module)
>> +         Hi3719MV100 (support two I2C module)
>> +         Hi3718MV100 (support two I2C module)
>>
>
> How do you detect the specific model? Is there a hardware register that
> lets you know the type?
> If you have a device specific "compatible" string, you should list all
> the known strings.
>
In fact, no need to distinguish these hardware, the only difference is 
i2c module number.
The same compatible is used.
These info can be removed to remove the confusion.

Thanks

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

* [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
@ 2014-09-30  9:25           ` zhangfei
  0 siblings, 0 replies; 22+ messages in thread
From: zhangfei @ 2014-09-30  9:25 UTC (permalink / raw)
  To: linux-arm-kernel



On 09/30/2014 05:01 PM, Arnd Bergmann wrote:
> On Sunday 28 September 2014 12:22:07 Zhangfei Gao wrote:
>> +
>> +Required properties:
>> +- compatible: Must be "hisilicon,hix5hd2-i2c"
>> +  Specifically, the following versions of the chipset are supported:
>> +         Hi3716CV200 (support six I2C module)
>> +         Hi3719CV100 (support six I2C module)
>> +         Hi3718CV100 (support six I2C module)
>> +         Hi3719MV100 (support two I2C module)
>> +         Hi3718MV100 (support two I2C module)
>>
>
> How do you detect the specific model? Is there a hardware register that
> lets you know the type?
> If you have a device specific "compatible" string, you should list all
> the known strings.
>
In fact, no need to distinguish these hardware, the only difference is 
i2c module number.
The same compatible is used.
These info can be removed to remove the confusion.

Thanks

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

* Re: [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
  2014-09-30  9:02         ` Arnd Bergmann
@ 2014-09-30  9:31           ` Wei Xu
  -1 siblings, 0 replies; 22+ messages in thread
From: Wei Xu @ 2014-09-30  9:31 UTC (permalink / raw)
  To: Arnd Bergmann, Zhangfei Gao
  Cc: Wolfram Sang, haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA



On 2014/9/30 17:02, Arnd Bergmann wrote:
> On Sunday 28 September 2014 12:22:09 Zhangfei Gao wrote:
>> +
>> +               i2c0: i2c@b10000 {
>> +                       compatible = "hisilicon,hix5hd2-i2c";
>> +                       reg = <0xb10000 0x1000>;
>> +                       interrupts = <0 38 4>;
>> +                       clocks = <&clock HIX5HD2_I2C0_RST>;
>> +                       #address-cells = <1>;
>> +                       #size-cells = <0>;
>> +                       status = "disabled";
>> +               };
>>

Hi Arnd,
 
> HIX5HD2_I2C0_RST is not defined anywhere, so this will result in the
> same build error that has required reverting a lot of patches for the
> 3.18 merge window.

Sorry again for bringing so much troubles to you, Olof and Stephen.
On 9/30, Mike Turquette has already accepted the clock pull request
which includes the HIX5HD2_I2C0_RST definition.

> How do you plan to deal with the dependency in the future? 

In the future, I will check the dependence firstly about the patches.
When creating pull request tag, I will test it and make sure it works.
And I will also make sure that the order of the pull request is sent correctly.

Best Regards,
Wei

> 	Arnd
> 
> .
> 

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

* [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node
@ 2014-09-30  9:31           ` Wei Xu
  0 siblings, 0 replies; 22+ messages in thread
From: Wei Xu @ 2014-09-30  9:31 UTC (permalink / raw)
  To: linux-arm-kernel



On 2014/9/30 17:02, Arnd Bergmann wrote:
> On Sunday 28 September 2014 12:22:09 Zhangfei Gao wrote:
>> +
>> +               i2c0: i2c at b10000 {
>> +                       compatible = "hisilicon,hix5hd2-i2c";
>> +                       reg = <0xb10000 0x1000>;
>> +                       interrupts = <0 38 4>;
>> +                       clocks = <&clock HIX5HD2_I2C0_RST>;
>> +                       #address-cells = <1>;
>> +                       #size-cells = <0>;
>> +                       status = "disabled";
>> +               };
>>

Hi Arnd,
 
> HIX5HD2_I2C0_RST is not defined anywhere, so this will result in the
> same build error that has required reverting a lot of patches for the
> 3.18 merge window.

Sorry again for bringing so much troubles to you, Olof and Stephen.
On 9/30, Mike Turquette has already accepted the clock pull request
which includes the HIX5HD2_I2C0_RST definition.

> How do you plan to deal with the dependency in the future? 

In the future, I will check the dependence firstly about the patches.
When creating pull request tag, I will test it and make sure it works.
And I will also make sure that the order of the pull request is sent correctly.

Best Regards,
Wei

> 	Arnd
> 
> .
> 

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

* Re: [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
  2014-09-30  9:25           ` zhangfei
@ 2014-09-30 10:24               ` Arnd Bergmann
  -1 siblings, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2014-09-30 10:24 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: zhangfei, devicetree-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang,
	haifeng.yan-QSEj5FYQhm4dnm+yROfE0A,
	xuwei5-C8/M+/jPZTeaMJb+Lgu22Q, Wei Yan,
	jchxue-Re5JQEeQqe8AvxtiuMwx3w, linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Tuesday 30 September 2014 17:25:25 zhangfei wrote:
> On 09/30/2014 05:01 PM, Arnd Bergmann wrote:
> > On Sunday 28 September 2014 12:22:07 Zhangfei Gao wrote:
> >> +
> >> +Required properties:
> >> +- compatible: Must be "hisilicon,hix5hd2-i2c"
> >> +  Specifically, the following versions of the chipset are supported:
> >> +         Hi3716CV200 (support six I2C module)
> >> +         Hi3719CV100 (support six I2C module)
> >> +         Hi3718CV100 (support six I2C module)
> >> +         Hi3719MV100 (support two I2C module)
> >> +         Hi3718MV100 (support two I2C module)
> >>
> >
> > How do you detect the specific model? Is there a hardware register that
> > lets you know the type?
> > If you have a device specific "compatible" string, you should list all
> > the known strings.
> >
> In fact, no need to distinguish these hardware, the only difference is 
> i2c module number.
> The same compatible is used.

Ah, so you have multiple nodes in those cases, not just one node with
a variable number of I2C hosts. I was a bit confused by the
description

> These info can be removed to remove the confusion.

Yes, I think that would be better, both because it avoids the confusion,
and because it means you can use the driver for future machines without
having to update the binding each time.

	Arnd

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

* [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation
@ 2014-09-30 10:24               ` Arnd Bergmann
  0 siblings, 0 replies; 22+ messages in thread
From: Arnd Bergmann @ 2014-09-30 10:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday 30 September 2014 17:25:25 zhangfei wrote:
> On 09/30/2014 05:01 PM, Arnd Bergmann wrote:
> > On Sunday 28 September 2014 12:22:07 Zhangfei Gao wrote:
> >> +
> >> +Required properties:
> >> +- compatible: Must be "hisilicon,hix5hd2-i2c"
> >> +  Specifically, the following versions of the chipset are supported:
> >> +         Hi3716CV200 (support six I2C module)
> >> +         Hi3719CV100 (support six I2C module)
> >> +         Hi3718CV100 (support six I2C module)
> >> +         Hi3719MV100 (support two I2C module)
> >> +         Hi3718MV100 (support two I2C module)
> >>
> >
> > How do you detect the specific model? Is there a hardware register that
> > lets you know the type?
> > If you have a device specific "compatible" string, you should list all
> > the known strings.
> >
> In fact, no need to distinguish these hardware, the only difference is 
> i2c module number.
> The same compatible is used.

Ah, so you have multiple nodes in those cases, not just one node with
a variable number of I2C hosts. I was a bit confused by the
description

> These info can be removed to remove the confusion.

Yes, I think that would be better, both because it avoids the confusion,
and because it means you can use the driver for future machines without
having to update the binding each time.

	Arnd

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

end of thread, other threads:[~2014-09-30 10:24 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-28  4:22 [PATCH v2 0/3] i2c: hix5hd2: add i2c controller driver Zhangfei Gao
2014-09-28  4:22 ` Zhangfei Gao
     [not found] ` <1411878129-19743-1-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-09-28  4:22   ` [PATCH v2 1/3] i2c: hix5hd2: add devicetree documentation Zhangfei Gao
2014-09-28  4:22     ` Zhangfei Gao
     [not found]     ` <1411878129-19743-2-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-09-30  9:01       ` Arnd Bergmann
2014-09-30  9:01         ` Arnd Bergmann
2014-09-30  9:25         ` zhangfei
2014-09-30  9:25           ` zhangfei
     [not found]           ` <542A7705.2030404-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-09-30 10:24             ` Arnd Bergmann
2014-09-30 10:24               ` Arnd Bergmann
2014-09-28  4:22   ` [PATCH v2 2/3] i2c: hix5hd2: add i2c controller driver Zhangfei Gao
2014-09-28  4:22     ` Zhangfei Gao
     [not found]     ` <1411878129-19743-3-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-09-29 12:49       ` zhangfei
2014-09-29 12:49         ` zhangfei
2014-09-28  4:22   ` [PATCH v2 3/3] ARM: dts: hix5hd2: add i2c node Zhangfei Gao
2014-09-28  4:22     ` Zhangfei Gao
     [not found]     ` <1411878129-19743-4-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2014-09-30  9:02       ` Arnd Bergmann
2014-09-30  9:02         ` Arnd Bergmann
2014-09-30  9:21         ` zhangfei
2014-09-30  9:21           ` zhangfei
2014-09-30  9:31         ` Wei Xu
2014-09-30  9:31           ` Wei Xu

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