From 9cbbf3dc994797f49cd30607a16182ca6c87863f Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Date: Fri, 13 Feb 2015 15:52:21 +0200
Subject: i2c: i801: Don't break user-visible strings

It makes more difficult to grep these error prints from sources if they are
split to multiple source lines.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-i801.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 8fafb254e42a..7d1f4a478c54 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1192,8 +1192,8 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	/* Determine the address of the SMBus area */
 	priv->smba = pci_resource_start(dev, SMBBAR);
 	if (!priv->smba) {
-		dev_err(&dev->dev, "SMBus base address uninitialized, "
-			"upgrade BIOS\n");
+		dev_err(&dev->dev,
+			"SMBus base address uninitialized, upgrade BIOS\n");
 		err = -ENODEV;
 		goto exit;
 	}
@@ -1206,8 +1206,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	err = pci_request_region(dev, SMBBAR, i801_driver.name);
 	if (err) {
-		dev_err(&dev->dev, "Failed to request SMBus region "
-			"0x%lx-0x%Lx\n", priv->smba,
+		dev_err(&dev->dev,
+			"Failed to request SMBus region 0x%lx-0x%Lx\n",
+			priv->smba,
 			(unsigned long long)pci_resource_end(dev, SMBBAR));
 		goto exit;
 	}
-- 
cgit v1.2.3


From 256493c58625530a958296724b92b344f3271b2f Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Date: Fri, 13 Feb 2015 15:52:22 +0200
Subject: i2c: i801: Remove i801_driver forward declaration

struct pci_driver i801_driver forward declaration is needed only for
accessing the name field. Remove it and use dev_driver_string() instead.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-i801.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 7d1f4a478c54..5f827dfc671a 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -223,8 +223,6 @@ struct i801_priv {
 #endif
 };
 
-static struct pci_driver i801_driver;
-
 #define FEATURE_SMBUS_PEC	(1 << 0)
 #define FEATURE_BLOCK_BUFFER	(1 << 1)
 #define FEATURE_BLOCK_PROC	(1 << 2)
@@ -1204,7 +1202,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		goto exit;
 	}
 
-	err = pci_request_region(dev, SMBBAR, i801_driver.name);
+	err = pci_request_region(dev, SMBBAR, dev_driver_string(&dev->dev));
 	if (err) {
 		dev_err(&dev->dev,
 			"Failed to request SMBus region 0x%lx-0x%Lx\n",
@@ -1256,7 +1254,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		init_waitqueue_head(&priv->waitq);
 
 		err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
-				  i801_driver.name, priv);
+				  dev_driver_string(&dev->dev), priv);
 		if (err) {
 			dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
 				dev->irq, err);
-- 
cgit v1.2.3


From 1621c59d94d13380015fb5131acc6c14ecd1c797 Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Date: Fri, 13 Feb 2015 15:52:23 +0200
Subject: i2c: i801: Use managed devm_* memory and irq allocation

This simplifies the error and remove paths.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-i801.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 5f827dfc671a..b1d725d758bb 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1138,7 +1138,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	int err, i;
 	struct i801_priv *priv;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
 
@@ -1253,8 +1253,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	if (priv->features & FEATURE_IRQ) {
 		init_waitqueue_head(&priv->waitq);
 
-		err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
-				  dev_driver_string(&dev->dev), priv);
+		err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
+				       IRQF_SHARED,
+				       dev_driver_string(&dev->dev), priv);
 		if (err) {
 			dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
 				dev->irq, err);
@@ -1275,7 +1276,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	err = i2c_add_adapter(&priv->adapter);
 	if (err) {
 		dev_err(&dev->dev, "Failed to add SMBus adapter\n");
-		goto exit_free_irq;
+		goto exit_release;
 	}
 
 	i801_probe_optional_slaves(priv);
@@ -1286,12 +1287,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	return 0;
 
-exit_free_irq:
-	if (priv->features & FEATURE_IRQ)
-		free_irq(dev->irq, priv);
+exit_release:
 	pci_release_region(dev, SMBBAR);
 exit:
-	kfree(priv);
 	return err;
 }
 
@@ -1303,11 +1301,8 @@ static void i801_remove(struct pci_dev *dev)
 	i2c_del_adapter(&priv->adapter);
 	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 
-	if (priv->features & FEATURE_IRQ)
-		free_irq(dev->irq, priv);
 	pci_release_region(dev, SMBBAR);
 
-	kfree(priv);
 	/*
 	 * do not call pci_disable_device(dev) since it can cause hard hangs on
 	 * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
-- 
cgit v1.2.3


From f85da3f5de6f354bc26eb84c013b41a8b8558c5e Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Date: Fri, 13 Feb 2015 15:52:24 +0200
Subject: i2c: i801: Remove pci_enable_device() call from i801_resume()

Since pci_disable_device() is not called from i801_suspend() and power
state is set already it means that subsequent pci_enable_device() calls do
practically nothing but monotonically increase struct pci_dev enable_cnt.

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-i801.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index b1d725d758bb..5fb35464f693 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1324,7 +1324,7 @@ static int i801_resume(struct pci_dev *dev)
 {
 	pci_set_power_state(dev, PCI_D0);
 	pci_restore_state(dev);
-	return pci_enable_device(dev);
+	return 0;
 }
 #else
 #define i801_suspend NULL
-- 
cgit v1.2.3


From fef220da43d8537ed7d11da4db17b958cd779887 Mon Sep 17 00:00:00 2001
From: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Date: Fri, 13 Feb 2015 15:52:25 +0200
Subject: i2c: i801: Use managed pcim_* PCI device initialization and
 reservation

Simplifies the code a bit and makes easier to disable PCI device on driver
detach by removing the pcim_pin_device() call in the future if needed.

Reason why i2c-i801.c doesn't ever call pci_disable_device() was because it
made some systems to hang during power-off. See commit d6fcb3b9cf77
("[PATCH] i2c-i801.c: don't pci_disable_device() after it was just enabled")
and
http://marc.info/?l=linux-kernel&m=115160053309535&w=2

Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Reviewed-by: Jean Delvare <jdelvare@suse.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-i801.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 5fb35464f693..5ecbb3fdc27e 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -1180,35 +1180,35 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	}
 	priv->features &= ~disable_features;
 
-	err = pci_enable_device(dev);
+	err = pcim_enable_device(dev);
 	if (err) {
 		dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
 			err);
-		goto exit;
+		return err;
 	}
+	pcim_pin_device(dev);
 
 	/* Determine the address of the SMBus area */
 	priv->smba = pci_resource_start(dev, SMBBAR);
 	if (!priv->smba) {
 		dev_err(&dev->dev,
 			"SMBus base address uninitialized, upgrade BIOS\n");
-		err = -ENODEV;
-		goto exit;
+		return -ENODEV;
 	}
 
 	err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
 	if (err) {
-		err = -ENODEV;
-		goto exit;
+		return -ENODEV;
 	}
 
-	err = pci_request_region(dev, SMBBAR, dev_driver_string(&dev->dev));
+	err = pcim_iomap_regions(dev, 1 << SMBBAR,
+				 dev_driver_string(&dev->dev));
 	if (err) {
 		dev_err(&dev->dev,
 			"Failed to request SMBus region 0x%lx-0x%Lx\n",
 			priv->smba,
 			(unsigned long long)pci_resource_end(dev, SMBBAR));
-		goto exit;
+		return err;
 	}
 
 	pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
@@ -1276,7 +1276,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	err = i2c_add_adapter(&priv->adapter);
 	if (err) {
 		dev_err(&dev->dev, "Failed to add SMBus adapter\n");
-		goto exit_release;
+		return err;
 	}
 
 	i801_probe_optional_slaves(priv);
@@ -1286,11 +1286,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	pci_set_drvdata(dev, priv);
 
 	return 0;
-
-exit_release:
-	pci_release_region(dev, SMBBAR);
-exit:
-	return err;
 }
 
 static void i801_remove(struct pci_dev *dev)
@@ -1301,8 +1296,6 @@ static void i801_remove(struct pci_dev *dev)
 	i2c_del_adapter(&priv->adapter);
 	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 
-	pci_release_region(dev, SMBBAR);
-
 	/*
 	 * do not call pci_disable_device(dev) since it can cause hard hangs on
 	 * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
-- 
cgit v1.2.3


From 58b59e0f2462780ae3978611519f6a5e477e31df Mon Sep 17 00:00:00 2001
From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Date: Tue, 17 Feb 2015 10:12:08 +0100
Subject: i2c: pca954x: improve usage of gpiod API
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions)
which appeared in v3.17-rc1, the gpiod_get* functions take an additional
parameter that allows to specify direction and initial value for
outputs.

Also there is an *_optional variant that serves well here.  The sematics
is slightly changed here by using it. Now if a reset gpio is specified
and getting hold on it fails, pca954x_probe fails, too.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/muxes/i2c-mux-pca954x.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 3d8f4fe2e47e..bea0d2de2993 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -204,9 +204,9 @@ static int pca954x_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, data);
 
 	/* Get the mux out of reset if a reset GPIO is specified. */
-	gpio = devm_gpiod_get(&client->dev, "reset");
-	if (!IS_ERR(gpio))
-		gpiod_direction_output(gpio, 0);
+	gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(gpio))
+		return PTR_ERR(gpio);
 
 	/* Write the mux register at addr to verify
 	 * that the mux is in fact present. This also
-- 
cgit v1.2.3


From b7f625840267b18ef1011cba0085bb7e237d76f7 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Mon, 5 Jan 2015 23:45:59 +0100
Subject: i2c: add quirk checks to core

Let the core do the checks if HW quirks prevent a transfer. Saves code
from drivers and adds consistency.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Tested-by: Ray Jui <rjui@broadcom.com>
Tested-by: Ivan T. Ivanov <iivanov@mm-sol.com>
Tested-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
Tested-By: Ludovic Desroches <ludovic.desroches@atmel.com>
---
 drivers/i2c/i2c-core.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 210cf4874cb7..57a86f4aab43 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1929,6 +1929,65 @@ module_exit(i2c_exit);
  * ----------------------------------------------------
  */
 
+/* Check if val is exceeding the quirk IFF quirk is non 0 */
+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))
+
+static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char *err_msg)
+{
+	dev_err_ratelimited(&adap->dev, "adapter quirk: %s (addr 0x%04x, size %u, %s)\n",
+			    err_msg, msg->addr, msg->len,
+			    msg->flags & I2C_M_RD ? "read" : "write");
+	return -EOPNOTSUPP;
+}
+
+static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	const struct i2c_adapter_quirks *q = adap->quirks;
+	int max_num = q->max_num_msgs, i;
+	bool do_len_check = true;
+
+	if (q->flags & I2C_AQ_COMB) {
+		max_num = 2;
+
+		/* special checks for combined messages */
+		if (num == 2) {
+			if (q->flags & I2C_AQ_COMB_WRITE_FIRST && msgs[0].flags & I2C_M_RD)
+				return i2c_quirk_error(adap, &msgs[0], "1st comb msg must be write");
+
+			if (q->flags & I2C_AQ_COMB_READ_SECOND && !(msgs[1].flags & I2C_M_RD))
+				return i2c_quirk_error(adap, &msgs[1], "2nd comb msg must be read");
+
+			if (q->flags & I2C_AQ_COMB_SAME_ADDR && msgs[0].addr != msgs[1].addr)
+				return i2c_quirk_error(adap, &msgs[0], "comb msg only to same addr");
+
+			if (i2c_quirk_exceeded(msgs[0].len, q->max_comb_1st_msg_len))
+				return i2c_quirk_error(adap, &msgs[0], "msg too long");
+
+			if (i2c_quirk_exceeded(msgs[1].len, q->max_comb_2nd_msg_len))
+				return i2c_quirk_error(adap, &msgs[1], "msg too long");
+
+			do_len_check = false;
+		}
+	}
+
+	if (i2c_quirk_exceeded(num, max_num))
+		return i2c_quirk_error(adap, &msgs[0], "too many messages");
+
+	for (i = 0; i < num; i++) {
+		u16 len = msgs[i].len;
+
+		if (msgs[i].flags & I2C_M_RD) {
+			if (do_len_check && i2c_quirk_exceeded(len, q->max_read_len))
+				return i2c_quirk_error(adap, &msgs[i], "msg too long");
+		} else {
+			if (do_len_check && i2c_quirk_exceeded(len, q->max_write_len))
+				return i2c_quirk_error(adap, &msgs[i], "msg too long");
+		}
+	}
+
+	return 0;
+}
+
 /**
  * __i2c_transfer - unlocked flavor of i2c_transfer
  * @adap: Handle to I2C bus
@@ -1946,6 +2005,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 	unsigned long orig_jiffies;
 	int ret, try;
 
+	if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
+		return -EOPNOTSUPP;
+
 	/* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
 	 * enabled.  This is an efficient way of keeping the for-loop from
 	 * being executed when not needed.
-- 
cgit v1.2.3


From a7405844da1c8064500f0741cc8876c7f887dd85 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: at91: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Tested-By: Ludovic Desroches <ludovic.desroches@atmel.com>
---
 drivers/i2c/busses/i2c-at91.c | 32 +++++++++++---------------------
 1 file changed, 11 insertions(+), 21 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 636fd2efad88..b3a70e8fc653 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -487,30 +487,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
 	if (ret < 0)
 		goto out;
 
-	/*
-	 * The hardware can handle at most two messages concatenated by a
-	 * repeated start via it's internal address feature.
-	 */
-	if (num > 2) {
-		dev_err(dev->dev,
-			"cannot handle more than two concatenated messages.\n");
-		ret = 0;
-		goto out;
-	} else if (num == 2) {
+	if (num == 2) {
 		int internal_address = 0;
 		int i;
 
-		if (msg->flags & I2C_M_RD) {
-			dev_err(dev->dev, "first transfer must be write.\n");
-			ret = -EINVAL;
-			goto out;
-		}
-		if (msg->len > 3) {
-			dev_err(dev->dev, "first message size must be <= 3.\n");
-			ret = -EINVAL;
-			goto out;
-		}
-
 		/* 1st msg is put into the internal address, start with 2nd */
 		m_start = &msg[1];
 		for (i = 0; i < msg->len; ++i) {
@@ -540,6 +520,15 @@ out:
 	return ret;
 }
 
+/*
+ * The hardware can handle at most two messages concatenated by a
+ * repeated start via it's internal address feature.
+ */
+static struct i2c_adapter_quirks at91_twi_quirks = {
+	.flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
+	.max_comb_1st_msg_len = 3,
+};
+
 static u32 at91_twi_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
@@ -777,6 +766,7 @@ static int at91_twi_probe(struct platform_device *pdev)
 	dev->adapter.owner = THIS_MODULE;
 	dev->adapter.class = I2C_CLASS_DEPRECATED;
 	dev->adapter.algo = &at91_twi_algorithm;
+	dev->adapter.quirks = &at91_twi_quirks;
 	dev->adapter.dev.parent = dev->dev;
 	dev->adapter.nr = pdev->id;
 	dev->adapter.timeout = AT91_I2C_TIMEOUT;
-- 
cgit v1.2.3


From a531afdf93489e9357c4207c7bdec9b921ddfe9e Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: opal: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Tested-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
---
 drivers/i2c/busses/i2c-opal.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
index 16f90b1a7508..b2788ecad5b3 100644
--- a/drivers/i2c/busses/i2c-opal.c
+++ b/drivers/i2c/busses/i2c-opal.c
@@ -104,17 +104,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 		req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
 		break;
 	case 2:
-		/* For two messages, we basically support only simple
-		 * smbus transactions of a write plus a read. We might
-		 * want to allow also two writes but we'd have to bounce
-		 * the data into a single buffer.
-		 */
-		if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD))
-			return -EOPNOTSUPP;
-		if (msgs[0].len > 4)
-			return -EOPNOTSUPP;
-		if (msgs[0].addr != msgs[1].addr)
-			return -EOPNOTSUPP;
 		req.type = OPAL_I2C_SM_READ;
 		req.addr = cpu_to_be16(msgs[0].addr);
 		req.subaddr_sz = msgs[0].len;
@@ -210,6 +199,16 @@ static const struct i2c_algorithm i2c_opal_algo = {
 	.functionality	= i2c_opal_func,
 };
 
+/* For two messages, we basically support only simple
+ * smbus transactions of a write plus a read. We might
+ * want to allow also two writes but we'd have to bounce
+ * the data into a single buffer.
+ */
+static struct i2c_adapter_quirks i2c_opal_quirks = {
+	.flags = I2C_AQ_COMB_WRITE_THEN_READ,
+	.max_comb_1st_msg_len = 4,
+};
+
 static int i2c_opal_probe(struct platform_device *pdev)
 {
 	struct i2c_adapter	*adapter;
@@ -232,6 +231,7 @@ static int i2c_opal_probe(struct platform_device *pdev)
 
 	adapter->algo = &i2c_opal_algo;
 	adapter->algo_data = (void *)(unsigned long)opal_id;
+	adapter->quirks = &i2c_opal_quirks;
 	adapter->dev.parent = &pdev->dev;
 	adapter->dev.of_node = of_node_get(pdev->dev.of_node);
 	pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL);
-- 
cgit v1.2.3


From 994647db6bb2284de7dfee10a51b4d9fec760ed3 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: qup: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Tested-by: Ivan T. Ivanov <iivanov@mm-sol.com>
---
 drivers/i2c/busses/i2c-qup.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 4dad23bdffbe..fdcbdab808e9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -412,17 +412,6 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
 	unsigned long left;
 	int ret;
 
-	/*
-	 * The QUP block will issue a NACK and STOP on the bus when reaching
-	 * the end of the read, the length of the read is specified as one byte
-	 * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
-	 */
-	if (msg->len > QUP_READ_LIMIT) {
-		dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
-			QUP_READ_LIMIT);
-		return -EINVAL;
-	}
-
 	qup->msg = msg;
 	qup->pos  = 0;
 
@@ -534,6 +523,15 @@ static const struct i2c_algorithm qup_i2c_algo = {
 	.functionality	= qup_i2c_func,
 };
 
+/*
+ * The QUP block will issue a NACK and STOP on the bus when reaching
+ * the end of the read, the length of the read is specified as one byte
+ * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+ */
+static struct i2c_adapter_quirks qup_i2c_quirks = {
+	.max_read_len = QUP_READ_LIMIT,
+};
+
 static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
 {
 	clk_prepare_enable(qup->clk);
@@ -670,6 +668,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
 
 	i2c_set_adapdata(&qup->adap, qup);
 	qup->adap.algo = &qup_i2c_algo;
+	qup->adap.quirks = &qup_i2c_quirks;
 	qup->adap.dev.parent = qup->dev;
 	qup->adap.dev.of_node = pdev->dev.of_node;
 	strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
-- 
cgit v1.2.3


From b94c820f37804a461376205b4919eef300ff3abe Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: cpm: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-cpm.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 2d466538b2e2..714bdc837769 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -308,22 +308,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 	struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
 	struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
 	struct i2c_msg *pmsg;
-	int ret, i;
+	int ret;
 	int tptr;
 	int rptr;
 	cbd_t __iomem *tbdf;
 	cbd_t __iomem *rbdf;
 
-	if (num > CPM_MAXBD)
-		return -EINVAL;
-
-	/* Check if we have any oversized READ requests */
-	for (i = 0; i < num; i++) {
-		pmsg = &msgs[i];
-		if (pmsg->len >= CPM_MAX_READ)
-			return -EINVAL;
-	}
-
 	/* Reset to use first buffer */
 	out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
 	out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
@@ -424,10 +414,18 @@ static const struct i2c_algorithm cpm_i2c_algo = {
 	.functionality = cpm_i2c_func,
 };
 
+/* CPM_MAX_READ is also limiting writes according to the code! */
+static struct i2c_adapter_quirks cpm_i2c_quirks = {
+	.max_num_msgs = CPM_MAXBD,
+	.max_read_len = CPM_MAX_READ,
+	.max_write_len = CPM_MAX_READ,
+};
+
 static const struct i2c_adapter cpm_ops = {
 	.owner		= THIS_MODULE,
 	.name		= "i2c-cpm",
 	.algo		= &cpm_i2c_algo,
+	.quirks		= &cpm_i2c_quirks,
 };
 
 static int cpm_i2c_setup(struct cpm_i2c *cpm)
-- 
cgit v1.2.3


From 280d230012dc0441e7fd8c722ac06dc370ce78d0 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: axxia: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-axxia.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 768a598d8d03..488c5d3bf9db 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -336,11 +336,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 	u32 addr_1, addr_2;
 	int ret;
 
-	if (msg->len > 255) {
-		dev_warn(idev->dev, "unsupported length %u\n", msg->len);
-		return -EINVAL;
-	}
-
 	idev->msg = msg;
 	idev->msg_xfrd = 0;
 	idev->msg_err = 0;
@@ -454,6 +449,11 @@ static const struct i2c_algorithm axxia_i2c_algo = {
 	.functionality = axxia_i2c_func,
 };
 
+static struct i2c_adapter_quirks axxia_i2c_quirks = {
+	.max_read_len = 255,
+	.max_write_len = 255,
+};
+
 static int axxia_i2c_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
@@ -511,6 +511,7 @@ static int axxia_i2c_probe(struct platform_device *pdev)
 	strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
 	idev->adapter.owner = THIS_MODULE;
 	idev->adapter.algo = &axxia_i2c_algo;
+	idev->adapter.quirks = &axxia_i2c_quirks;
 	idev->adapter.dev.parent = &pdev->dev;
 	idev->adapter.dev.of_node = pdev->dev.of_node;
 
-- 
cgit v1.2.3


From afe90203977bc7ecd7d1048a5ad453a8670c16f5 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: dln2: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-dln2.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
index b3fb86af4cbb..b6f9ba7eb175 100644
--- a/drivers/i2c/busses/i2c-dln2.c
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -144,7 +144,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
 {
 	struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
 	struct i2c_msg *pmsg;
-	struct device *dev = &dln2->adapter.dev;
 	int i;
 
 	for (i = 0; i < num; i++) {
@@ -152,11 +151,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
 
 		pmsg = &msgs[i];
 
-		if (pmsg->len > DLN2_I2C_MAX_XFER_SIZE) {
-			dev_warn(dev, "maximum transfer size exceeded\n");
-			return -EOPNOTSUPP;
-		}
-
 		if (pmsg->flags & I2C_M_RD) {
 			ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
 					    pmsg->len);
@@ -187,6 +181,11 @@ static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
 	.functionality = dln2_i2c_func,
 };
 
+static struct i2c_adapter_quirks dln2_i2c_quirks = {
+	.max_read_len = DLN2_I2C_MAX_XFER_SIZE,
+	.max_write_len = DLN2_I2C_MAX_XFER_SIZE,
+};
+
 static int dln2_i2c_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -209,6 +208,7 @@ static int dln2_i2c_probe(struct platform_device *pdev)
 	dln2->adapter.owner = THIS_MODULE;
 	dln2->adapter.class = I2C_CLASS_HWMON;
 	dln2->adapter.algo = &dln2_i2c_usb_algorithm;
+	dln2->adapter.quirks = &dln2_i2c_quirks;
 	dln2->adapter.dev.parent = dev;
 	i2c_set_adapdata(&dln2->adapter, dln2);
 	snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
-- 
cgit v1.2.3


From 7ee405ea068602d1fd42bf14ddc04d45733cfd7d Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: powermac: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-powermac.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 60a53c169ed2..6abcf696e359 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -153,12 +153,6 @@ static int i2c_powermac_master_xfer(	struct i2c_adapter *adap,
 	int			read;
 	int			addrdir;
 
-	if (num != 1) {
-		dev_err(&adap->dev,
-			"Multi-message I2C transactions not supported\n");
-		return -EOPNOTSUPP;
-	}
-
 	if (msgs->flags & I2C_M_TEN)
 		return -EINVAL;
 	read = (msgs->flags & I2C_M_RD) != 0;
@@ -205,6 +199,9 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
 	.functionality	= i2c_powermac_func,
 };
 
+static struct i2c_adapter_quirks i2c_powermac_quirks = {
+	.max_num_msgs = 1,
+};
 
 static int i2c_powermac_remove(struct platform_device *dev)
 {
@@ -434,6 +431,7 @@ static int i2c_powermac_probe(struct platform_device *dev)
 
 	platform_set_drvdata(dev, adapter);
 	adapter->algo = &i2c_powermac_algorithm;
+	adapter->quirks = &i2c_powermac_quirks;
 	i2c_set_adapdata(adapter, bus);
 	adapter->dev.parent = &dev->dev;
 
-- 
cgit v1.2.3


From f2325c54f362ffa1e2e3254bcb70d6d4da49a17a Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: viperboard: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-viperboard.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c
index 7533fa34d737..47e88adf2011 100644
--- a/drivers/i2c/busses/i2c-viperboard.c
+++ b/drivers/i2c/busses/i2c-viperboard.c
@@ -288,10 +288,6 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
 			i, pmsg->flags & I2C_M_RD ? "read" : "write",
 			pmsg->flags, pmsg->len, pmsg->addr);
 
-		/* msgs longer than 2048 bytes are not supported by adapter */
-		if (pmsg->len > 2048)
-			return -EINVAL;
-
 		mutex_lock(&vb->lock);
 		/* directly send the message */
 		if (pmsg->flags & I2C_M_RD) {
@@ -358,6 +354,11 @@ static const struct i2c_algorithm vprbrd_algorithm = {
 	.functionality	= vprbrd_i2c_func,
 };
 
+static struct i2c_adapter_quirks vprbrd_quirks = {
+	.max_read_len = 2048,
+	.max_write_len = 2048,
+};
+
 static int vprbrd_i2c_probe(struct platform_device *pdev)
 {
 	struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
@@ -373,6 +374,7 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)
 	vb_i2c->i2c.owner = THIS_MODULE;
 	vb_i2c->i2c.class = I2C_CLASS_HWMON;
 	vb_i2c->i2c.algo = &vprbrd_algorithm;
+	vb_i2c->i2c.quirks = &vprbrd_quirks;
 	vb_i2c->i2c.algo_data = vb;
 	/* save the param in usb capabable memory */
 	vb_i2c->bus_freq_param = i2c_bus_param;
-- 
cgit v1.2.3


From fb3de30cd9c7e90c3e58cfe51b02c768b291873b Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: pmcmsp: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-pmcmsp.c | 42 ++++++++++++++++-------------------------
 1 file changed, 16 insertions(+), 26 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index d37d9db6681e..2c40edbf6224 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -456,14 +456,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
 		return -EINVAL;
 	}
 
-	if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
-	    cmd->write_len > MSP_MAX_BYTES_PER_RW) {
-		dev_err(&pmcmsptwi_adapter.dev,
-			"%s: Cannot transfer more than %d bytes\n",
-			__func__, MSP_MAX_BYTES_PER_RW);
-		return -EINVAL;
-	}
-
 	mutex_lock(&data->lock);
 	dev_dbg(&pmcmsptwi_adapter.dev,
 		"Setting address to 0x%04x\n", cmd->addr);
@@ -520,25 +512,14 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
 	struct pmcmsptwi_cfg oldcfg, newcfg;
 	int ret;
 
-	if (num > 2) {
-		dev_dbg(&adap->dev, "%d messages unsupported\n", num);
-		return -EINVAL;
-	} else if (num == 2) {
-		/* Check for a dual write-then-read command */
+	if (num == 2) {
 		struct i2c_msg *nextmsg = msg + 1;
-		if (!(msg->flags & I2C_M_RD) &&
-		    (nextmsg->flags & I2C_M_RD) &&
-		    msg->addr == nextmsg->addr) {
-			cmd.type = MSP_TWI_CMD_WRITE_READ;
-			cmd.write_len = msg->len;
-			cmd.write_data = msg->buf;
-			cmd.read_len = nextmsg->len;
-			cmd.read_data = nextmsg->buf;
-		} else {
-			dev_dbg(&adap->dev,
-				"Non write-read dual messages unsupported\n");
-			return -EINVAL;
-		}
+
+		cmd.type = MSP_TWI_CMD_WRITE_READ;
+		cmd.write_len = msg->len;
+		cmd.write_data = msg->buf;
+		cmd.read_len = nextmsg->len;
+		cmd.read_data = nextmsg->buf;
 	} else if (msg->flags & I2C_M_RD) {
 		cmd.type = MSP_TWI_CMD_READ;
 		cmd.read_len = msg->len;
@@ -598,6 +579,14 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
 		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
 }
 
+static struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
+	.flags = I2C_AQ_COMB_WRITE_THEN_READ,
+	.max_write_len = MSP_MAX_BYTES_PER_RW,
+	.max_read_len = MSP_MAX_BYTES_PER_RW,
+	.max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW,
+	.max_comb_2nd_msg_len = MSP_MAX_BYTES_PER_RW,
+};
+
 /* -- Initialization -- */
 
 static struct i2c_algorithm pmcmsptwi_algo = {
@@ -609,6 +598,7 @@ static struct i2c_adapter pmcmsptwi_adapter = {
 	.owner		= THIS_MODULE,
 	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
 	.algo		= &pmcmsptwi_algo,
+	.quirks		= &pmcmsptwi_i2c_quirks,
 	.name		= DRV_NAME,
 };
 
-- 
cgit v1.2.3


From 338f1ab6c4ea60cbc8ee57b78707d4b8d0219519 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa@the-dreams.de>
Date: Wed, 7 Jan 2015 12:24:10 +0100
Subject: i2c: bcm-iproc: make use of the new infrastructure for quirks

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Tested-by: Ray Jui <rjui@broadcom.com>
---
 drivers/i2c/busses/i2c-bcm-iproc.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index d3c89157b337..f9f2c2082151 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -160,14 +160,6 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
 	u32 val;
 	unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
 
-	/* need to reserve one byte in the FIFO for the slave address */
-	if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
-		dev_err(iproc_i2c->device,
-			"only support data length up to %u bytes\n",
-			M_TX_RX_FIFO_SIZE - 1);
-		return -EOPNOTSUPP;
-	}
-
 	/* check if bus is busy */
 	if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
 	       BIT(M_CMD_START_BUSY_SHIFT))) {
@@ -287,6 +279,12 @@ static const struct i2c_algorithm bcm_iproc_algo = {
 	.functionality = bcm_iproc_i2c_functionality,
 };
 
+static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
+	/* need to reserve one byte in the FIFO for the slave address */
+	.max_read_len = M_TX_RX_FIFO_SIZE - 1,
+	.max_write_len = M_TX_RX_FIFO_SIZE - 1,
+};
+
 static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
 {
 	unsigned int bus_speed;
@@ -413,6 +411,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
 	i2c_set_adapdata(adap, iproc_i2c);
 	strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
 	adap->algo = &bcm_iproc_algo;
+	adap->quirks = &bcm_iproc_i2c_quirks;
 	adap->dev.parent = &pdev->dev;
 	adap->dev.of_node = pdev->dev.of_node;
 
-- 
cgit v1.2.3


From bf07038051ddd6c1e017cd50933e314040a69b11 Mon Sep 17 00:00:00 2001
From: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
Date: Fri, 13 Mar 2015 15:25:33 +0100
Subject: i2c: opal: Update quirk flags to do write-then-anything

Hardware can do write-then-anything. Activate that.

Signed-off-by: Neelesh Gupta <neelegup@linux.vnet.ibm.com>
[wsa: cosmetic updates]
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-opal.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
index b2788ecad5b3..75dd6d041241 100644
--- a/drivers/i2c/busses/i2c-opal.c
+++ b/drivers/i2c/busses/i2c-opal.c
@@ -104,7 +104,8 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 		req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
 		break;
 	case 2:
-		req.type = OPAL_I2C_SM_READ;
+		req.type = (msgs[1].flags & I2C_M_RD) ?
+			OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
 		req.addr = cpu_to_be16(msgs[0].addr);
 		req.subaddr_sz = msgs[0].len;
 		for (i = 0; i < msgs[0].len; i++)
@@ -199,13 +200,12 @@ static const struct i2c_algorithm i2c_opal_algo = {
 	.functionality	= i2c_opal_func,
 };
 
-/* For two messages, we basically support only simple
- * smbus transactions of a write plus a read. We might
- * want to allow also two writes but we'd have to bounce
- * the data into a single buffer.
+/*
+ * For two messages, we basically support simple smbus transactions of a
+ * write-then-anything.
  */
 static struct i2c_adapter_quirks i2c_opal_quirks = {
-	.flags = I2C_AQ_COMB_WRITE_THEN_READ,
+	.flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
 	.max_comb_1st_msg_len = 4,
 };
 
-- 
cgit v1.2.3


From 271a89cdd65f8c2b4a6be865859f8d2d1b504696 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Tue, 10 Mar 2015 14:08:13 -0400
Subject: i2c: mxs: match wait_for_completion_timeout return type

Return type of wait_for_completion_timeout is unsigned long not int.
An appropriately named unsigned long is added and the assignment fixed up.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-mxs.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index ff8b12c8d25f..56fceff6ba14 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -568,6 +568,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 	int ret;
 	int flags;
 	int use_pio = 0;
+	unsigned long time_left;
 
 	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
 
@@ -599,9 +600,9 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
 		if (ret)
 			return ret;
 
-		ret = wait_for_completion_timeout(&i2c->cmd_complete,
+		time_left = wait_for_completion_timeout(&i2c->cmd_complete,
 						msecs_to_jiffies(1000));
-		if (ret == 0)
+		if (!time_left)
 			goto timeout;
 
 		ret = i2c->cmd_err;
-- 
cgit v1.2.3


From 6973a39c9e35f46f2ea79ccbc25d3cab58737331 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 1 Mar 2015 09:17:41 -0500
Subject: i2c: tegra: match return type of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int. As ret
was only used for wait_for_completion_timeout here it is renamed to time_left
the type changed to unsigned long and references fixed up.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-tegra.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 29f14331dd9d..1bcd75ea0b4c 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -532,7 +532,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 {
 	u32 packet_header;
 	u32 int_mask;
-	int ret;
+	unsigned long time_left;
 
 	tegra_i2c_flush_fifos(i2c_dev);
 
@@ -585,18 +585,20 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 	dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
 		i2c_readl(i2c_dev, I2C_INT_MASK));
 
-	ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT);
+	time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+						TEGRA_I2C_TIMEOUT);
 	tegra_i2c_mask_irq(i2c_dev, int_mask);
 
-	if (ret == 0) {
+	if (time_left == 0) {
 		dev_err(i2c_dev->dev, "i2c transfer timed out\n");
 
 		tegra_i2c_init(i2c_dev);
 		return -ETIMEDOUT;
 	}
 
-	dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n",
-		ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err);
+	dev_dbg(i2c_dev->dev, "transfer complete: %lu %d %d\n",
+		time_left, completion_done(&i2c_dev->msg_complete),
+		i2c_dev->msg_err);
 
 	if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
 		return 0;
-- 
cgit v1.2.3


From bd9dd73c6a4e17c9345e81b46a52ca9d3157378f Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 1 Mar 2015 08:20:32 -0500
Subject: i2c: wmt: use msecs_to_jiffies for time conversions

This is only an API consolidation and should make things more readable
it replaces var * HZ / 1000 by msecs_to_jiffies(var).

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-wmt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 82ea34925489..26e49e6b4446 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -177,7 +177,7 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 
 	while (xfer_len < pmsg->len) {
 		wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-							  500 * HZ / 1000);
+							msecs_to_jiffies(500));
 
 		if (wait_result == 0)
 			return -ETIMEDOUT;
@@ -266,7 +266,7 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 
 	while (xfer_len < pmsg->len) {
 		wait_result = wait_for_completion_timeout(&i2c_dev->complete,
-							  500 * HZ / 1000);
+							msecs_to_jiffies(500));
 
 		if (!wait_result)
 			return -ETIMEDOUT;
-- 
cgit v1.2.3


From e2efb89768aebb93d3fa804bc6ee05888097797b Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Tue, 10 Feb 2015 11:55:10 -0500
Subject: i2c: cadence: fixup wait_for_completion_timeout return handling

return type of wait_for_completion_timeout is unsigned long not int. The
return variable is renamed to make the timeout condition clearly readable
and the type adjusted to unsigned long.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-cadence.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 7d7a14cdadfb..2ee78e099d30 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -475,7 +475,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap)
 static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
 		struct i2c_adapter *adap)
 {
-	int ret;
+	unsigned long time_left;
 	u32 reg;
 
 	id->p_msg = msg;
@@ -501,8 +501,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
 		cdns_i2c_msend(id);
 
 	/* Wait for the signal of completion */
-	ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
-	if (!ret) {
+	time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
+	if (time_left == 0) {
 		cdns_i2c_master_reset(adap);
 		dev_err(id->adap.dev.parent,
 				"timeout waiting on completion\n");
-- 
cgit v1.2.3


From 63d51e591931b878be7a16dacb37868a1e7ae8d1 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Tue, 10 Feb 2015 03:11:14 -0500
Subject: i2c: designware: fixup return handling of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int, rather
than introducing a new variable the wait_for_completion_timeout is moved
into the if condition as the return value is only used to detect timeout.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Reviewed-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-designware-core.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 6e25c010e690..6f19a33773fe 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -656,8 +656,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
 	i2c_dw_xfer_init(dev);
 
 	/* wait for tx to complete */
-	ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
-	if (ret == 0) {
+	if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
 		dev_err(dev->dev, "controller timed out\n");
 		/* i2c_dw_init implicitly disables the adapter */
 		i2c_dw_init(dev);
-- 
cgit v1.2.3


From c4dc12167db8c7c22b38ab5180afdd5c2acba783 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 06:04:18 -0500
Subject: i2c: i2c-bcm2835: match return type of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int. as
time_left is used for wait_for_completion_timeout exclusively here its
type is simply changed to unsigned long.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-bcm2835.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 5d6feb937b9d..c9336a3202d5 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -147,7 +147,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
 				struct i2c_msg *msg)
 {
 	u32 c;
-	int time_left;
+	unsigned long time_left;
 
 	i2c_dev->msg_buf = msg->buf;
 	i2c_dev->msg_buf_remaining = msg->len;
-- 
cgit v1.2.3


From 73958562f1ca5c91d802c845856c4a9edcf468cb Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 05:43:52 -0500
Subject: i2c: wmt: match return type of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int. as
wait_result is only used for wait_for_completion_timeout here the type
is simply changed to unsigned long.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-wmt.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 26e49e6b4446..e1e3a85596c5 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -128,7 +128,8 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 {
 	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 	u16 val, tcr_val;
-	int ret, wait_result;
+	int ret;
+	unsigned long wait_result;
 	int xfer_len = 0;
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
@@ -218,7 +219,8 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
 {
 	struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
 	u16 val, tcr_val;
-	int ret, wait_result;
+	int ret;
+	unsigned long wait_result;
 	u32 xfer_len = 0;
 
 	if (!(pmsg->flags & I2C_M_NOSTART)) {
-- 
cgit v1.2.3


From 1abdd5d957e1fc789a2981d27399f56b0682f53e Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 03:03:30 -0500
Subject: i2c: ismt: fix type of return var of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int. As
ret is in used for other calls a new appropriately typed variable timeout
is added to handle wait_for_completion_timeout

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-ismt.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index f2b0ff011631..f994712d0904 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -380,6 +380,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
 		       int size, union i2c_smbus_data *data)
 {
 	int ret;
+	unsigned long time_left;
 	dma_addr_t dma_addr = 0; /* address of the data buffer */
 	u8 dma_size = 0;
 	enum dma_data_direction dma_direction = 0;
@@ -578,13 +579,13 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
 	ismt_submit_desc(priv);
 
 	/* Now we wait for interrupt completion, 1s */
-	ret = wait_for_completion_timeout(&priv->cmp, HZ*1);
+	time_left = wait_for_completion_timeout(&priv->cmp, HZ*1);
 
 	/* unmap the data buffer */
 	if (dma_size != 0)
 		dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction);
 
-	if (unlikely(!ret)) {
+	if (unlikely(!time_left)) {
 		dev_err(dev, "completion wait timed out\n");
 		ret = -ETIMEDOUT;
 		goto out;
-- 
cgit v1.2.3


From 1ac63fef0564d0340eaa330804df29b348204cea Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 06:39:56 -0500
Subject: i2c: imx: match return type of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int.
An appropriate variable of type unsigned long is introduced and the
assignments fixed up.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-imx.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index d7b26fc6f432..a53a7dd66945 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -601,6 +601,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
 					struct i2c_msg *msgs)
 {
 	int result;
+	unsigned long time_left;
 	unsigned int temp = 0;
 	unsigned long orig_jiffies = jiffies;
 	struct imx_i2c_dma *dma = i2c_imx->dma;
@@ -624,10 +625,10 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
 	 */
 	imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
 	reinit_completion(&i2c_imx->dma->cmd_complete);
-	result = wait_for_completion_timeout(
+	time_left = wait_for_completion_timeout(
 				&i2c_imx->dma->cmd_complete,
 				msecs_to_jiffies(DMA_TIMEOUT));
-	if (result == 0) {
+	if (time_left == 0) {
 		dmaengine_terminate_all(dma->chan_using);
 		return -ETIMEDOUT;
 	}
@@ -663,6 +664,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
 			struct i2c_msg *msgs, bool is_lastmsg)
 {
 	int result;
+	unsigned long time_left;
 	unsigned int temp;
 	unsigned long orig_jiffies = jiffies;
 	struct imx_i2c_dma *dma = i2c_imx->dma;
@@ -682,10 +684,10 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
 		return result;
 
 	reinit_completion(&i2c_imx->dma->cmd_complete);
-	result = wait_for_completion_timeout(
+	time_left = wait_for_completion_timeout(
 				&i2c_imx->dma->cmd_complete,
 				msecs_to_jiffies(DMA_TIMEOUT));
-	if (result == 0) {
+	if (time_left == 0) {
 		dmaengine_terminate_all(dma->chan_using);
 		return -ETIMEDOUT;
 	}
-- 
cgit v1.2.3


From 9bb9fee9e9423082ff23f21257bfc68b5eacd504 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 07:34:33 -0500
Subject: i2c: nomadik: match return type of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int. as
timeout is used for wait_for_completion_timeout exclusively here its
type is simply changed to unsigned long.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-nomadik.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 97998946c4f6..6ca6ad6d901a 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -448,7 +448,7 @@ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
 {
 	u32 status = 0;
 	u32 mcr, irq_mask;
-	int timeout;
+	unsigned long timeout;
 
 	mcr = load_i2c_mcr_reg(dev, flags);
 	writel(mcr, dev->virtbase + I2C_MCR);
@@ -517,7 +517,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
 {
 	u32 status = 0;
 	u32 mcr, irq_mask;
-	int timeout;
+	unsigned long timeout;
 
 	mcr = load_i2c_mcr_reg(dev, flags);
 
-- 
cgit v1.2.3


From f87b53a0858ea69e65d7f19573907a60b2e32e66 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 07:34:43 -0500
Subject: i2c: nomadik: match status to return type of read_i2c

return type of read_i2c() is int not u32. As the assignments to status
are consistent with int here its type is changed to int.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-nomadik.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 6ca6ad6d901a..bcd17e8cbcb4 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -446,7 +446,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
  */
 static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
 {
-	u32 status = 0;
+	int status = 0;
 	u32 mcr, irq_mask;
 	unsigned long timeout;
 
-- 
cgit v1.2.3


From 2abaccb356a857dbf4c978a69f2209e19c1a0db3 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 10:36:48 -0500
Subject: i2c: axxia: fixup return type of wait_for_completion_timeout

return type of wait_for_completion_timeout is unsigned long not int. The
return variable is renamed to reflect its use and the type adjusted to
unsigned long.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-axxia.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 488c5d3bf9db..32d883490863 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -334,7 +334,7 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 	u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
 	u32 rx_xfer, tx_xfer;
 	u32 addr_1, addr_2;
-	int ret;
+	unsigned long time_left;
 
 	idev->msg = msg;
 	idev->msg_xfrd = 0;
@@ -383,15 +383,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 
 	i2c_int_enable(idev, int_mask);
 
-	ret = wait_for_completion_timeout(&idev->msg_complete,
-					  I2C_XFER_TIMEOUT);
+	time_left = wait_for_completion_timeout(&idev->msg_complete,
+					      I2C_XFER_TIMEOUT);
 
 	i2c_int_disable(idev, int_mask);
 
 	if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
 		dev_warn(idev->dev, "busy after xfer\n");
 
-	if (ret == 0)
+	if (time_left == 0)
 		idev->msg_err = -ETIMEDOUT;
 
 	if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
@@ -403,17 +403,17 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
 static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
 {
 	u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
-	int ret;
+	unsigned long time_left;
 
 	reinit_completion(&idev->msg_complete);
 
 	/* Issue stop */
 	writel(0xb, idev->base + MST_COMMAND);
 	i2c_int_enable(idev, int_mask);
-	ret = wait_for_completion_timeout(&idev->msg_complete,
-					  I2C_STOP_TIMEOUT);
+	time_left = wait_for_completion_timeout(&idev->msg_complete,
+					      I2C_STOP_TIMEOUT);
 	i2c_int_disable(idev, int_mask);
-	if (ret == 0)
+	if (time_left == 0)
 		return -ETIMEDOUT;
 
 	if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
-- 
cgit v1.2.3


From 1c42aca54fa0e738d9f0c0e5aa952d0e4357dcf0 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Sun, 8 Feb 2015 11:12:07 -0500
Subject: i2c: at91: fixup return type of wait_for_completion_timeout

Return type of wait_for_completion_timeout is unsigned long not int. This
patch adds a timeout variable of appropriate type and fixes up the assignment.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-at91.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index b3a70e8fc653..ff23d1bdd230 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -381,6 +381,7 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
 static int at91_do_twi_transfer(struct at91_twi_dev *dev)
 {
 	int ret;
+	unsigned long time_left;
 	bool has_unre_flag = dev->pdata->has_unre_flag;
 
 	dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
@@ -436,9 +437,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
 		}
 	}
 
-	ret = wait_for_completion_timeout(&dev->cmd_complete,
-					     dev->adapter.timeout);
-	if (ret == 0) {
+	time_left = wait_for_completion_timeout(&dev->cmd_complete,
+					      dev->adapter.timeout);
+	if (time_left == 0) {
 		dev_err(dev->dev, "controller timed out\n");
 		at91_init_twi_bus(dev);
 		ret = -ETIMEDOUT;
-- 
cgit v1.2.3


From 913b1d85cdde5f1fc081aa84f548270a15027abb Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Mon, 9 Feb 2015 10:15:21 -0500
Subject: i2c: img-scb: fixup of wait_for_completion_timeout return handling

Return type of wait_for_completion_timeout is unsigned long not int.
Appropriately typed/named variable are added and assignment fixed up.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: James Hogan <james.hogan@imgtec.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-img-scb.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index 0fcc1694c607..00ffd6613680 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -988,15 +988,16 @@ out:
 static int img_i2c_reset_bus(struct img_i2c *i2c)
 {
 	unsigned long flags;
-	int ret;
+	unsigned long time_left;
 
 	spin_lock_irqsave(&i2c->lock, flags);
 	reinit_completion(&i2c->msg_complete);
 	img_i2c_reset_start(i2c);
 	spin_unlock_irqrestore(&i2c->lock, flags);
 
-	ret = wait_for_completion_timeout(&i2c->msg_complete, IMG_I2C_TIMEOUT);
-	if (ret == 0)
+	time_left = wait_for_completion_timeout(&i2c->msg_complete,
+					      IMG_I2C_TIMEOUT);
+	if (time_left == 0)
 		return -ETIMEDOUT;
 	return 0;
 }
@@ -1007,6 +1008,7 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 	struct img_i2c *i2c = i2c_get_adapdata(adap);
 	bool atomic = false;
 	int i, ret;
+	unsigned long time_left;
 
 	if (i2c->mode == MODE_SUSPEND) {
 		WARN(1, "refusing to service transaction in suspended state\n");
@@ -1068,11 +1070,11 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
 			img_i2c_write(i2c);
 		spin_unlock_irqrestore(&i2c->lock, flags);
 
-		ret = wait_for_completion_timeout(&i2c->msg_complete,
-						  IMG_I2C_TIMEOUT);
+		time_left = wait_for_completion_timeout(&i2c->msg_complete,
+						      IMG_I2C_TIMEOUT);
 		del_timer_sync(&i2c->check_timer);
 
-		if (ret == 0) {
+		if (time_left == 0) {
 			dev_err(adap->dev.parent, "i2c transfer timed out\n");
 			i2c->msg_status = -ETIMEDOUT;
 			break;
-- 
cgit v1.2.3


From 8ce795cb0c6b8214779c4a220781a26f096e4442 Mon Sep 17 00:00:00 2001
From: Valentin Longchamp <valentin.longchamp@keymile.com>
Date: Tue, 10 Feb 2015 16:46:33 +0100
Subject: i2c: mpc: assign the correct prescaler from SVR

For the 85xx platforms, the source clock for the i2c-mpc can change from
one SoC to another. This is documented in the AN2919 "Determining the
I2C Frequency Divider Ratio for SCL" by Freescale. Not taking this into
account can lead to the output SCL frequency to by off by an offset. It
was observed on the P2041 from the QorIQ family.

This patch fixes this problem by setting the prescaler value to the
appropriate value when required. The SoCs that required a different
prescaler than 1 are identified by reading out the SVR as discussed in
http://thread.gmane.org/gmane.linux.drivers.devicetree/94247/focus=20556

Signed-off-by: Valentin Longchamp <valentin.longchamp@keymile.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-mpc.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index c74cc2be613b..dc03a9164772 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -29,6 +29,7 @@
 #include <linux/delay.h>
 
 #include <asm/mpc52xx.h>
+#include <asm/mpc85xx.h>
 #include <sysdev/fsl_soc.h>
 
 #define DRV_NAME "mpc-i2c"
@@ -346,6 +347,33 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
 	return val;
 }
 
+static u32 mpc_i2c_get_prescaler_8xxx(void)
+{
+	/* mpc83xx and mpc82xx all have prescaler 1 */
+	u32 prescaler = 1;
+
+	/* mpc85xx */
+	if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2)
+		|| pvr_version_is(PVR_VER_E500MC)
+		|| pvr_version_is(PVR_VER_E5500)
+		|| pvr_version_is(PVR_VER_E6500)) {
+		unsigned int svr = mfspr(SPRN_SVR);
+
+		if ((SVR_SOC_VER(svr) == SVR_8540)
+			|| (SVR_SOC_VER(svr) == SVR_8541)
+			|| (SVR_SOC_VER(svr) == SVR_8560)
+			|| (SVR_SOC_VER(svr) == SVR_8555)
+			|| (SVR_SOC_VER(svr) == SVR_8610))
+			/* the above 85xx SoCs have prescaler 1 */
+			prescaler = 1;
+		else
+			/* all the other 85xx have prescaler 2 */
+			prescaler = 2;
+	}
+
+	return prescaler;
+}
+
 static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
 					  u32 prescaler, u32 *real_clk)
 {
@@ -363,7 +391,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
 	if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
 		prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
 	if (!prescaler)
-		prescaler = 1;
+		prescaler = mpc_i2c_get_prescaler_8xxx();
 
 	divider = fsl_get_sys_freq() / clock / prescaler;
 
-- 
cgit v1.2.3


From b20d386485e25934aef8aa24cbc8c2f51a2cb9cf Mon Sep 17 00:00:00 2001
From: Alexey Brodkin <Alexey.Brodkin@synopsys.com>
Date: Mon, 9 Mar 2015 12:03:12 +0300
Subject: i2c: designware: Suppress error message if platform_get_irq() < 0

With -EPROBE_DEFER, this message is confusing and we hope for a
centralized printout in the future anyhow.

Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Christian Ruppert <christian.ruppert@alitech.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-designware-platdrv.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index c270f5f9a8f9..fa4e2b521f0d 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -143,10 +143,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
 	u32 clk_freq, ht = 0;
 
 	irq = platform_get_irq(pdev, 0);
-	if (irq < 0) {
-		dev_err(&pdev->dev, "no irq resource?\n");
-		return irq; /* -ENXIO */
-	}
+	if (irq < 0)
+		return irq;
 
 	dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
 	if (!dev)
-- 
cgit v1.2.3


From 03bde7c31a360f814ca42101d60563b1b803dca1 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa+renesas@sang-engineering.com>
Date: Thu, 12 Mar 2015 17:17:59 +0100
Subject: i2c: busses with dynamic ids should start after fixed ids for DT

Make sure dynamic ids do not interfere with fixed ones and let them
start after the highest fixed id. This patch might cause different
bus-numbers than before for dynamic ids, however it fixes a bug. Assume:

- fixed id0 defers probe
- fixed id1 succeeds and registers a muxed bus with dynamic id
- muxed bus gets id0
- fixed id0 wants to probe again, but its fixed id is gone now
- fixed id0 probe fails

With this patch, the fixed ids are always reserved in the DT case.
For legacy board init, we already have a mechanism like this in
i2c_register_board_info().

Reported-by: Bob Feretich <bob.feretich@rafresearch.com>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/i2c-core.c | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 57a86f4aab43..fe80f85896e2 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -1878,6 +1878,13 @@ static int __init i2c_init(void)
 {
 	int retval;
 
+	retval = of_alias_get_highest_id("i2c");
+
+	down_write(&__i2c_board_lock);
+	if (retval >= __i2c_first_dynamic_bus_num)
+		__i2c_first_dynamic_bus_num = retval + 1;
+	up_write(&__i2c_board_lock);
+
 	retval = bus_register(&i2c_bus_type);
 	if (retval)
 		return retval;
-- 
cgit v1.2.3


From 4a7a08226dd590a139e5f7835fe93f90b3beee90 Mon Sep 17 00:00:00 2001
From: Baruch Siach <baruch@tkos.co.il>
Date: Thu, 19 Mar 2015 13:16:46 +0200
Subject: i2c: add support for the Digicolor I2C controller

The CX92755 is an SoC in the Conexant Digicolor series. The devicetree binding
document describes the I2C controller on the CX92755 SoC, that is also shared
by some other SoCs in the Digicolor series. The driver adds support.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
[wsa: fixed spaces around operators]
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 .../devicetree/bindings/i2c/i2c-digicolor.txt      |  25 ++
 drivers/i2c/busses/Kconfig                         |   9 +
 drivers/i2c/busses/Makefile                        |   1 +
 drivers/i2c/busses/i2c-digicolor.c                 | 385 +++++++++++++++++++++
 4 files changed, 420 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-digicolor.txt
 create mode 100644 drivers/i2c/busses/i2c-digicolor.c

(limited to 'drivers/i2c')

diff --git a/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt
new file mode 100644
index 000000000000..457a098d4f7e
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-digicolor.txt
@@ -0,0 +1,25 @@
+Conexant Digicolor I2C controller
+
+Required properties:
+ - compatible: must be "cnxt,cx92755-i2c"
+ - reg: physical address and length of the device registers
+ - interrupts: a single interrupt specifier
+ - clocks: clock for the device
+ - #address-cells: should be <1>
+ - #size-cells: should be <0>
+
+Optional properties:
+- clock-frequency: the desired I2C bus clock frequency in Hz; in
+  absence of this property the default value is used (100 kHz).
+
+Example:
+
+	i2c: i2c@f0000120 {
+		compatible = "cnxt,cx92755-i2c";
+		reg = <0xf0000120 0x10>;
+		interrupts = <28>;
+		clocks = <&main_clk>;
+		clock-frequency = <100000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 22da9c2ffa22..db09881614b7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -485,6 +485,15 @@ config I2C_DESIGNWARE_BAYTRAIL
 	  the platform firmware controlling it. You should say Y if running on
 	  a BayTrail system using the AXP288.
 
+config I2C_DIGICOLOR
+	tristate "Conexant Digicolor I2C driver"
+	depends on ARCH_DIGICOLOR
+	help
+	  Support for Conexant Digicolor SoCs (CX92755) I2C controller driver.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-digicolor.
+
 config I2C_EFM32
 	tristate "EFM32 I2C controller"
 	depends on ARCH_EFM32 || COMPILE_TEST
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3638feb6677e..4413f09996cb 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -45,6 +45,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o
 i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
 obj-$(CONFIG_I2C_DESIGNWARE_PCI)	+= i2c-designware-pci.o
 i2c-designware-pci-objs := i2c-designware-pcidrv.o
+obj-$(CONFIG_I2C_DIGICOLOR)	+= i2c-digicolor.o
 obj-$(CONFIG_I2C_EFM32)		+= i2c-efm32.o
 obj-$(CONFIG_I2C_EG20T)		+= i2c-eg20t.o
 obj-$(CONFIG_I2C_EXYNOS5)	+= i2c-exynos5.o
diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c
new file mode 100644
index 000000000000..03f1e5549896
--- /dev/null
+++ b/drivers/i2c/busses/i2c-digicolor.c
@@ -0,0 +1,385 @@
+/*
+ * I2C bus driver for Conexant Digicolor SoCs
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2015 Paradox Innovation Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_FREQ		100000
+#define TIMEOUT_MS		100
+
+#define II_CONTROL		0x0
+#define II_CONTROL_LOCAL_RESET	BIT(0)
+
+#define II_CLOCKTIME		0x1
+
+#define II_COMMAND		0x2
+#define II_CMD_START		1
+#define II_CMD_RESTART		2
+#define II_CMD_SEND_ACK		3
+#define II_CMD_GET_ACK		6
+#define II_CMD_GET_NOACK	7
+#define II_CMD_STOP		10
+#define II_COMMAND_GO		BIT(7)
+#define II_COMMAND_COMPLETION_STATUS(r)	(((r) >> 5) & 3)
+#define II_CMD_STATUS_NORMAL	0
+#define II_CMD_STATUS_ACK_GOOD	1
+#define II_CMD_STATUS_ACK_BAD	2
+#define II_CMD_STATUS_ABORT	3
+
+#define II_DATA			0x3
+#define II_INTFLAG_CLEAR	0x8
+#define II_INTENABLE		0xa
+
+struct dc_i2c {
+	struct i2c_adapter	adap;
+	struct device		*dev;
+	void __iomem		*regs;
+	struct clk		*clk;
+	unsigned int		frequency;
+
+	struct i2c_msg		*msg;
+	unsigned int		msgbuf_ptr;
+	int			last;
+	spinlock_t		lock;
+	struct completion	done;
+	int			state;
+	int			error;
+};
+
+enum {
+	STATE_IDLE,
+	STATE_START,
+	STATE_ADDR,
+	STATE_WRITE,
+	STATE_READ,
+	STATE_STOP,
+};
+
+static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd)
+{
+	writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND);
+}
+
+static u8 dc_i2c_addr_cmd(struct i2c_msg *msg)
+{
+	u8 addr = (msg->addr & 0x7f) << 1;
+
+	if (msg->flags & I2C_M_RD)
+		addr |= 1;
+
+	return addr;
+}
+
+static void dc_i2c_data(struct dc_i2c *i2c, u8 data)
+{
+	writeb_relaxed(data, i2c->regs + II_DATA);
+}
+
+static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte)
+{
+	dc_i2c_data(i2c, byte);
+	dc_i2c_cmd(i2c, II_CMD_SEND_ACK);
+}
+
+static void dc_i2c_write_buf(struct dc_i2c *i2c)
+{
+	dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]);
+}
+
+static void dc_i2c_next_read(struct dc_i2c *i2c)
+{
+	bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len);
+
+	dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK);
+}
+
+static void dc_i2c_stop(struct dc_i2c *i2c)
+{
+	i2c->state = STATE_STOP;
+	if (i2c->last)
+		dc_i2c_cmd(i2c, II_CMD_STOP);
+	else
+		complete(&i2c->done);
+}
+
+static u8 dc_i2c_read_byte(struct dc_i2c *i2c)
+{
+	return readb_relaxed(i2c->regs + II_DATA);
+}
+
+static void dc_i2c_read_buf(struct dc_i2c *i2c)
+{
+	i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c);
+	dc_i2c_next_read(i2c);
+}
+
+static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable)
+{
+	if (enable)
+		writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
+	writeb_relaxed(!!enable, i2c->regs + II_INTENABLE);
+}
+
+static int dc_i2c_cmd_status(struct dc_i2c *i2c)
+{
+	u8 cmd = readb_relaxed(i2c->regs + II_COMMAND);
+
+	return II_COMMAND_COMPLETION_STATUS(cmd);
+}
+
+static void dc_i2c_start_msg(struct dc_i2c *i2c, int first)
+{
+	struct i2c_msg *msg = i2c->msg;
+
+	if (!(msg->flags & I2C_M_NOSTART)) {
+		i2c->state = STATE_START;
+		dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART);
+	} else if (msg->flags & I2C_M_RD) {
+		i2c->state = STATE_READ;
+		dc_i2c_next_read(i2c);
+	} else {
+		i2c->state = STATE_WRITE;
+		dc_i2c_write_buf(i2c);
+	}
+}
+
+static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
+{
+	struct dc_i2c *i2c = dev_id;
+	int cmd_status = dc_i2c_cmd_status(i2c);
+	unsigned long flags;
+	u8 addr_cmd;
+
+	writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	if (cmd_status == II_CMD_STATUS_ACK_BAD
+	    || cmd_status == II_CMD_STATUS_ABORT) {
+		i2c->error = -EIO;
+		complete(&i2c->done);
+		goto out;
+	}
+
+	switch (i2c->state) {
+	case STATE_START:
+		addr_cmd = dc_i2c_addr_cmd(i2c->msg);
+		dc_i2c_write_byte(i2c, addr_cmd);
+		i2c->state = STATE_ADDR;
+		break;
+	case STATE_ADDR:
+		if (i2c->msg->flags & I2C_M_RD) {
+			dc_i2c_next_read(i2c);
+			i2c->state = STATE_READ;
+			break;
+		}
+		i2c->state = STATE_WRITE;
+		/* fall through */
+	case STATE_WRITE:
+		if (i2c->msgbuf_ptr < i2c->msg->len)
+			dc_i2c_write_buf(i2c);
+		else
+			dc_i2c_stop(i2c);
+		break;
+	case STATE_READ:
+		if (i2c->msgbuf_ptr < i2c->msg->len)
+			dc_i2c_read_buf(i2c);
+		else
+			dc_i2c_stop(i2c);
+		break;
+	case STATE_STOP:
+		i2c->state = STATE_IDLE;
+		complete(&i2c->done);
+		break;
+	}
+
+out:
+	spin_unlock_irqrestore(&i2c->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,
+			   int last)
+{
+	unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS);
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+	i2c->msg = msg;
+	i2c->msgbuf_ptr = 0;
+	i2c->last = last;
+	i2c->error = 0;
+
+	reinit_completion(&i2c->done);
+	dc_i2c_set_irq(i2c, 1);
+	dc_i2c_start_msg(i2c, first);
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	timeout = wait_for_completion_timeout(&i2c->done, timeout);
+	dc_i2c_set_irq(i2c, 0);
+	if (timeout == 0) {
+		i2c->state = STATE_IDLE;
+		return -ETIMEDOUT;
+	}
+
+	if (i2c->error)
+		return i2c->error;
+
+	return 0;
+}
+
+static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct dc_i2c *i2c = adap->algo_data;
+	int i, ret;
+
+	for (i = 0; i < num; i++) {
+		ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1);
+		if (ret)
+			return ret;
+	}
+
+	return num;
+}
+
+static int dc_i2c_init_hw(struct dc_i2c *i2c)
+{
+	unsigned long clk_rate = clk_get_rate(i2c->clk);
+	unsigned int clocktime;
+
+	writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL);
+	udelay(100);
+	writeb_relaxed(0, i2c->regs + II_CONTROL);
+	udelay(100);
+
+	clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency);
+	if (clocktime < 1 || clocktime > 0xff) {
+		dev_err(i2c->dev, "can't set bus speed of %u Hz\n",
+			i2c->frequency);
+		return -EINVAL;
+	}
+	writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME);
+
+	return 0;
+}
+
+static u32 dc_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm dc_i2c_algorithm = {
+	.master_xfer	= dc_i2c_xfer,
+	.functionality	= dc_i2c_func,
+};
+
+static int dc_i2c_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct dc_i2c *i2c;
+	struct resource *r;
+	int ret = 0, irq;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+				 &i2c->frequency))
+		i2c->frequency = DEFAULT_FREQ;
+
+	i2c->dev = &pdev->dev;
+	platform_set_drvdata(pdev, i2c);
+
+	spin_lock_init(&i2c->lock);
+	init_completion(&i2c->done);
+
+	i2c->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2c->clk))
+		return PTR_ERR(i2c->clk);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	i2c->regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(i2c->regs))
+		return PTR_ERR(i2c->regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0,
+			       dev_name(&pdev->dev), i2c);
+	if (ret < 0)
+		return ret;
+
+	strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter",
+		sizeof(i2c->adap.name));
+	i2c->adap.owner = THIS_MODULE;
+	i2c->adap.algo = &dc_i2c_algorithm;
+	i2c->adap.dev.parent = &pdev->dev;
+	i2c->adap.dev.of_node = np;
+	i2c->adap.algo_data = i2c;
+
+	ret = dc_i2c_init_hw(i2c);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(i2c->clk);
+	if (ret < 0)
+		return ret;
+
+	ret = i2c_add_adapter(&i2c->adap);
+	if (ret < 0) {
+		clk_unprepare(i2c->clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dc_i2c_remove(struct platform_device *pdev)
+{
+	struct dc_i2c *i2c = platform_get_drvdata(pdev);
+
+	i2c_del_adapter(&i2c->adap);
+	clk_disable_unprepare(i2c->clk);
+
+	return 0;
+}
+
+static const struct of_device_id dc_i2c_match[] = {
+	{ .compatible = "cnxt,cx92755-i2c" },
+	{ },
+};
+
+static struct platform_driver dc_i2c_driver = {
+	.probe   = dc_i2c_probe,
+	.remove  = dc_i2c_remove,
+	.driver  = {
+		.name  = "digicolor-i2c",
+		.of_match_table = dc_i2c_match,
+	},
+};
+module_platform_driver(dc_i2c_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Conexant Digicolor I2C master driver");
+MODULE_LICENSE("GPL v2");
-- 
cgit v1.2.3


From 5b77d162a3d7359a8a8d83776720da065bf4e77b Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa+renesas@sang-engineering.com>
Date: Mon, 23 Mar 2015 09:26:36 +0100
Subject: i2c: slave: rework the slave API
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

After more discussion, brave users, and additional datasheet evaluation,
some API updates for the new I2C slave framework became imminent. The
slave events now get some easier to understand naming. Also, the event
handling has been simplified to only need a single call to the slave
callback when an action by the backend is required.

Reported-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Acked-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-rcar.c  | 10 ++++------
 drivers/i2c/i2c-slave-eeprom.c | 12 ++++++------
 include/linux/i2c.h            |  8 ++++----
 3 files changed, 14 insertions(+), 16 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 71a6e07eb7ab..5a84bea5b845 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -382,11 +382,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
 	if (ssr_filtered & SAR) {
 		/* read or write request */
 		if (ssr_raw & STM) {
-			i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
+			i2c_slave_event(priv->slave, I2C_SLAVE_READ_REQUESTED, &value);
 			rcar_i2c_write(priv, ICRXTX, value);
 			rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
 		} else {
-			i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
+			i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
 			rcar_i2c_read(priv, ICRXTX);	/* dummy read */
 			rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
 		}
@@ -406,17 +406,15 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
 		int ret;
 
 		value = rcar_i2c_read(priv, ICRXTX);
-		ret = i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_END, &value);
+		ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
 		/* Send NACK in case of error */
 		rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
-		i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
 		rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
 	}
 
 	/* master wants to read from us */
 	if (ssr_filtered & SDE) {
-		i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_END, &value);
-		i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
+		i2c_slave_event(priv->slave, I2C_SLAVE_READ_PROCESSED, &value);
 		rcar_i2c_write(priv, ICRXTX, value);
 		rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);
 	}
diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c
index cf9b09db092f..3fb45d894d80 100644
--- a/drivers/i2c/i2c-slave-eeprom.c
+++ b/drivers/i2c/i2c-slave-eeprom.c
@@ -36,7 +36,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
 	struct eeprom_data *eeprom = i2c_get_clientdata(client);
 
 	switch (event) {
-	case I2C_SLAVE_REQ_WRITE_END:
+	case I2C_SLAVE_WRITE_RECEIVED:
 		if (eeprom->first_write) {
 			eeprom->buffer_idx = *val;
 			eeprom->first_write = false;
@@ -47,17 +47,17 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
 		}
 		break;
 
-	case I2C_SLAVE_REQ_READ_START:
+	case I2C_SLAVE_READ_PROCESSED:
+		eeprom->buffer_idx++;
+		/* fallthrough */
+	case I2C_SLAVE_READ_REQUESTED:
 		spin_lock(&eeprom->buffer_lock);
 		*val = eeprom->buffer[eeprom->buffer_idx];
 		spin_unlock(&eeprom->buffer_lock);
 		break;
 
-	case I2C_SLAVE_REQ_READ_END:
-		eeprom->buffer_idx++;
-		break;
-
 	case I2C_SLAVE_STOP:
+	case I2C_SLAVE_WRITE_REQUESTED:
 		eeprom->first_write = true;
 		break;
 
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 243d1a1d78b2..c5e4bb2c5759 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -253,10 +253,10 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
 
 #if IS_ENABLED(CONFIG_I2C_SLAVE)
 enum i2c_slave_event {
-	I2C_SLAVE_REQ_READ_START,
-	I2C_SLAVE_REQ_READ_END,
-	I2C_SLAVE_REQ_WRITE_START,
-	I2C_SLAVE_REQ_WRITE_END,
+	I2C_SLAVE_READ_REQUESTED,
+	I2C_SLAVE_WRITE_REQUESTED,
+	I2C_SLAVE_READ_PROCESSED,
+	I2C_SLAVE_WRITE_RECEIVED,
 	I2C_SLAVE_STOP,
 };
 
-- 
cgit v1.2.3


From 98e982b3a29829b676b723e42c1184c87e5242d0 Mon Sep 17 00:00:00 2001
From: Wolfram Sang <wsa+renesas@sang-engineering.com>
Date: Mon, 23 Mar 2015 09:26:39 +0100
Subject: i2c: slave-eeprom: add more info when to increase the pointer
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

It is a bit subtle when to correctly increase the buffer index when
reading. Make this clearer by adding some more comments and pointers to
the docs.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/i2c-slave-eeprom.c | 6 ++++++
 1 file changed, 6 insertions(+)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c
index 3fb45d894d80..822374654609 100644
--- a/drivers/i2c/i2c-slave-eeprom.c
+++ b/drivers/i2c/i2c-slave-eeprom.c
@@ -48,12 +48,18 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client,
 		break;
 
 	case I2C_SLAVE_READ_PROCESSED:
+		/* The previous byte made it to the bus, get next one */
 		eeprom->buffer_idx++;
 		/* fallthrough */
 	case I2C_SLAVE_READ_REQUESTED:
 		spin_lock(&eeprom->buffer_lock);
 		*val = eeprom->buffer[eeprom->buffer_idx];
 		spin_unlock(&eeprom->buffer_lock);
+		/*
+		 * Do not increment buffer_idx here, because we don't know if
+		 * this byte will be actually used. Read Linux I2C slave docs
+		 * for details.
+		 */
 		break;
 
 	case I2C_SLAVE_STOP:
-- 
cgit v1.2.3


From 9c836d0c44798227a75c410cf33a76992cf93437 Mon Sep 17 00:00:00 2001
From: Amit Tomar <Amit.Tomar@freescale.com>
Date: Fri, 27 Mar 2015 18:19:00 +0530
Subject: i2c: mpc: Fix ISR return value

ISR should not return IRQ_HANDLED for not handling anything.
This patch fixes the return value of ISR for the same case.

Signed-off-by: Amit Singh Tomar <amit.tomar@freescale.com>
Acked-by: Danielle Costantino <danielle.costantino@gmail.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-mpc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index dc03a9164772..48ecffecc0ed 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -96,8 +96,9 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
 		i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
 		writeb(0, i2c->base + MPC_I2C_SR);
 		wake_up(&i2c->queue);
+		return IRQ_HANDLED;
 	}
-	return IRQ_HANDLED;
+	return IRQ_NONE;
 }
 
 /* Sometimes 9th clock pulse isn't generated, and slave doesn't release
-- 
cgit v1.2.3


From d9e1f4417a43cd0871253b2158eae07a48d656b5 Mon Sep 17 00:00:00 2001
From: Nicholas Mc Guire <hofrat@osadl.org>
Date: Tue, 17 Mar 2015 03:51:13 -0400
Subject: i2c: davinci: fixup wait_for_completion_timeout handling

wait_for_completion_timeout return 0 (timeout) or >=1 (completion) so the check
for >= 0 is always true and can be dropped implying that r==-EREMOTEIO and thus
the return of -EREMOTEIO can be done in the   if (dev->buf_len)  branch.
As wait_for_completion_timeout returns unsigned long not int, and   int r   is
exclusively used for wait_for_completion_timeout it is renamed and the type
changed to unsigned long.

Signed-off-by: Nicholas Mc Guire <hofrat@osadl.org>
Acked-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-davinci.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 6dc7ff5d3d9a..120a4ef36ef5 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -304,7 +304,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
 	struct davinci_i2c_platform_data *pdata = dev->pdata;
 	u32 flag;
 	u16 w;
-	int r;
+	unsigned long time_left;
 
 	/* Introduce a delay, required for some boards (e.g Davinci EVM) */
 	if (pdata->bus_delay)
@@ -368,8 +368,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
 		flag |= DAVINCI_I2C_MDR_STP;
 	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
 
-	r = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout);
-	if (r == 0) {
+	time_left = wait_for_completion_timeout(&dev->cmd_complete,
+						dev->adapter.timeout);
+	if (!time_left) {
 		dev_err(dev->dev, "controller timed out\n");
 		davinci_i2c_recover_bus(dev);
 		i2c_davinci_init(dev);
@@ -380,17 +381,13 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
 		/* This should be 0 if all bytes were transferred
 		 * or dev->cmd_err denotes an error.
 		 */
-		if (r >= 0) {
-			dev_err(dev->dev, "abnormal termination buf_len=%i\n",
-				dev->buf_len);
-			r = -EREMOTEIO;
-		}
+		dev_err(dev->dev, "abnormal termination buf_len=%i\n",
+			dev->buf_len);
 		dev->terminate = 1;
 		wmb();
 		dev->buf_len = 0;
+		return -EREMOTEIO;
 	}
-	if (r < 0)
-		return r;
 
 	/* no error */
 	if (likely(!dev->cmd_err))
-- 
cgit v1.2.3


From 3b10db23c0411524357c5834731df2e24897b53b Mon Sep 17 00:00:00 2001
From: Octavian Purdila <octavian.purdila@intel.com>
Date: Fri, 27 Mar 2015 17:37:10 +0200
Subject: i2c: dln2: set the device tree node of the adapter

This patch makes sure the platform device tree node is inherited by
the adapter device. This allows the DLN2 bus to work with i2c devices
defined in the device tree.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-dln2.c | 1 +
 1 file changed, 1 insertion(+)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
index b6f9ba7eb175..1600edd57ce9 100644
--- a/drivers/i2c/busses/i2c-dln2.c
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -210,6 +210,7 @@ static int dln2_i2c_probe(struct platform_device *pdev)
 	dln2->adapter.algo = &dln2_i2c_usb_algorithm;
 	dln2->adapter.quirks = &dln2_i2c_quirks;
 	dln2->adapter.dev.parent = dev;
+	dln2->adapter.dev.of_node = dev->of_node;
 	i2c_set_adapdata(&dln2->adapter, dln2);
 	snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
 		 "dln2-i2c", dev_name(pdev->dev.parent), dln2->port);
-- 
cgit v1.2.3


From ba92222ed63a12d09120df9b92f56cc990abac19 Mon Sep 17 00:00:00 2001
From: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
Date: Tue, 31 Mar 2015 14:03:55 +0100
Subject: i2c: jz4780: Add i2c bus controller driver for Ingenic JZ4780

Adds the i2c bus controller driver for the Ingenic JZ4780 SoC.

Signed-off-by: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 .../devicetree/bindings/i2c/i2c-jz4780.txt         |  35 +
 drivers/i2c/busses/Kconfig                         |   9 +
 drivers/i2c/busses/Makefile                        |   1 +
 drivers/i2c/busses/i2c-jz4780.c                    | 832 +++++++++++++++++++++
 4 files changed, 877 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-jz4780.txt
 create mode 100644 drivers/i2c/busses/i2c-jz4780.c

(limited to 'drivers/i2c')

diff --git a/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt b/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt
new file mode 100644
index 000000000000..231e4cc4008c
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-jz4780.txt
@@ -0,0 +1,35 @@
+* Ingenic JZ4780 I2C Bus controller
+
+Required properties:
+- compatible: should be "ingenic,jz4780-i2c"
+- reg: Should contain the address & size of the I2C controller registers.
+- interrupts: Should specify the interrupt provided by parent.
+- clocks: Should contain a single clock specifier for the JZ4780 I2C clock.
+- clock-frequency: desired I2C bus clock frequency in Hz.
+
+Recommended properties:
+- pinctrl-names: should be "default";
+- pinctrl-0: phandle to pinctrl function
+
+Optional properties:
+- interrupt-parent: Should be the phandle of the interrupt controller that
+  delivers interrupts to the I2C block.
+
+Example
+
+/ {
+	i2c4: i2c4@0x10054000 {
+		compatible = "ingenic,jz4780-i2c";
+		reg = <0x10054000 0x1000>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <56>;
+
+		clocks = <&cgu JZ4780_CLK_SMB4>;
+		clock-frequency = <100000>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pins_i2c4_data>;
+
+	};
+};
+
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index db09881614b7..0b0ca7dd5d1f 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -583,6 +583,15 @@ config I2C_IOP3XX
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-iop3xx.
 
+config I2C_JZ4780
+	tristate "JZ4780 I2C controller interface support"
+	depends on MACH_JZ4780 || COMPILE_TEST
+	help
+	 If you say yes to this option, support will be included for the
+	 Ingenic JZ4780 I2C controller.
+
+	 If you don't know what to do here, say N.
+
 config I2C_KEMPLD
 	tristate "Kontron COM I2C Controller"
 	depends on MFD_KEMPLD
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 4413f09996cb..ab6a0a67aca1 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IMG)		+= i2c-img-scb.o
 obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
+obj-$(CONFIG_I2C_JZ4780)	+= i2c-jz4780.o
 obj-$(CONFIG_I2C_KEMPLD)	+= i2c-kempld.o
 obj-$(CONFIG_I2C_MESON)		+= i2c-meson.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c
new file mode 100644
index 000000000000..ce1d69324169
--- /dev/null
+++ b/drivers/i2c/busses/i2c-jz4780.c
@@ -0,0 +1,832 @@
+/*
+ * Ingenic JZ4780 I2C bus driver
+ *
+ * Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
+ * Copyright (C) 2015 Imagination Technologies
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#define JZ4780_I2C_CTRL		0x00
+#define JZ4780_I2C_TAR		0x04
+#define JZ4780_I2C_SAR		0x08
+#define JZ4780_I2C_DC		0x10
+#define JZ4780_I2C_SHCNT	0x14
+#define JZ4780_I2C_SLCNT	0x18
+#define JZ4780_I2C_FHCNT	0x1C
+#define JZ4780_I2C_FLCNT	0x20
+#define JZ4780_I2C_INTST	0x2C
+#define JZ4780_I2C_INTM		0x30
+#define JZ4780_I2C_RXTL		0x38
+#define JZ4780_I2C_TXTL		0x3C
+#define JZ4780_I2C_CINTR	0x40
+#define JZ4780_I2C_CRXUF	0x44
+#define JZ4780_I2C_CRXOF	0x48
+#define JZ4780_I2C_CTXOF	0x4C
+#define JZ4780_I2C_CRXREQ	0x50
+#define JZ4780_I2C_CTXABRT	0x54
+#define JZ4780_I2C_CRXDONE	0x58
+#define JZ4780_I2C_CACT		0x5C
+#define JZ4780_I2C_CSTP		0x60
+#define JZ4780_I2C_CSTT		0x64
+#define JZ4780_I2C_CGC		0x68
+#define JZ4780_I2C_ENB		0x6C
+#define JZ4780_I2C_STA		0x70
+#define JZ4780_I2C_TXABRT	0x80
+#define JZ4780_I2C_DMACR	0x88
+#define JZ4780_I2C_DMATDLR	0x8C
+#define JZ4780_I2C_DMARDLR	0x90
+#define JZ4780_I2C_SDASU	0x94
+#define JZ4780_I2C_ACKGC	0x98
+#define JZ4780_I2C_ENSTA	0x9C
+#define JZ4780_I2C_SDAHD	0xD0
+
+#define JZ4780_I2C_CTRL_STPHLD		BIT(7)
+#define JZ4780_I2C_CTRL_SLVDIS		BIT(6)
+#define JZ4780_I2C_CTRL_REST		BIT(5)
+#define JZ4780_I2C_CTRL_MATP		BIT(4)
+#define JZ4780_I2C_CTRL_SATP		BIT(3)
+#define JZ4780_I2C_CTRL_SPDF		BIT(2)
+#define JZ4780_I2C_CTRL_SPDS		BIT(1)
+#define JZ4780_I2C_CTRL_MD		BIT(0)
+
+#define JZ4780_I2C_STA_SLVACT		BIT(6)
+#define JZ4780_I2C_STA_MSTACT		BIT(5)
+#define JZ4780_I2C_STA_RFF		BIT(4)
+#define JZ4780_I2C_STA_RFNE		BIT(3)
+#define JZ4780_I2C_STA_TFE		BIT(2)
+#define JZ4780_I2C_STA_TFNF		BIT(1)
+#define JZ4780_I2C_STA_ACT		BIT(0)
+
+static const char * const jz4780_i2c_abrt_src[] = {
+	"ABRT_7B_ADDR_NOACK",
+	"ABRT_10ADDR1_NOACK",
+	"ABRT_10ADDR2_NOACK",
+	"ABRT_XDATA_NOACK",
+	"ABRT_GCALL_NOACK",
+	"ABRT_GCALL_READ",
+	"ABRT_HS_ACKD",
+	"SBYTE_ACKDET",
+	"ABRT_HS_NORSTRT",
+	"SBYTE_NORSTRT",
+	"ABRT_10B_RD_NORSTRT",
+	"ABRT_MASTER_DIS",
+	"ARB_LOST",
+	"SLVFLUSH_TXFIFO",
+	"SLV_ARBLOST",
+	"SLVRD_INTX",
+};
+
+#define JZ4780_I2C_INTST_IGC		BIT(11)
+#define JZ4780_I2C_INTST_ISTT		BIT(10)
+#define JZ4780_I2C_INTST_ISTP		BIT(9)
+#define JZ4780_I2C_INTST_IACT		BIT(8)
+#define JZ4780_I2C_INTST_RXDN		BIT(7)
+#define JZ4780_I2C_INTST_TXABT		BIT(6)
+#define JZ4780_I2C_INTST_RDREQ		BIT(5)
+#define JZ4780_I2C_INTST_TXEMP		BIT(4)
+#define JZ4780_I2C_INTST_TXOF		BIT(3)
+#define JZ4780_I2C_INTST_RXFL		BIT(2)
+#define JZ4780_I2C_INTST_RXOF		BIT(1)
+#define JZ4780_I2C_INTST_RXUF		BIT(0)
+
+#define JZ4780_I2C_INTM_MIGC		BIT(11)
+#define JZ4780_I2C_INTM_MISTT		BIT(10)
+#define JZ4780_I2C_INTM_MISTP		BIT(9)
+#define JZ4780_I2C_INTM_MIACT		BIT(8)
+#define JZ4780_I2C_INTM_MRXDN		BIT(7)
+#define JZ4780_I2C_INTM_MTXABT		BIT(6)
+#define JZ4780_I2C_INTM_MRDREQ		BIT(5)
+#define JZ4780_I2C_INTM_MTXEMP		BIT(4)
+#define JZ4780_I2C_INTM_MTXOF		BIT(3)
+#define JZ4780_I2C_INTM_MRXFL		BIT(2)
+#define JZ4780_I2C_INTM_MRXOF		BIT(1)
+#define JZ4780_I2C_INTM_MRXUF		BIT(0)
+
+#define JZ4780_I2C_DC_READ		BIT(8)
+
+#define JZ4780_I2C_SDAHD_HDENB		BIT(8)
+
+#define JZ4780_I2C_ENB_I2C		BIT(0)
+
+#define JZ4780_I2CSHCNT_ADJUST(n)	(((n) - 8) < 6 ? 6 : ((n) - 8))
+#define JZ4780_I2CSLCNT_ADJUST(n)	(((n) - 1) < 8 ? 8 : ((n) - 1))
+#define JZ4780_I2CFHCNT_ADJUST(n)	(((n) - 8) < 6 ? 6 : ((n) - 8))
+#define JZ4780_I2CFLCNT_ADJUST(n)	(((n) - 1) < 8 ? 8 : ((n) - 1))
+
+#define JZ4780_I2C_FIFO_LEN	16
+#define TX_LEVEL		3
+#define RX_LEVEL		(JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1)
+
+#define JZ4780_I2C_TIMEOUT	300
+
+#define BUFSIZE 200
+
+struct jz4780_i2c {
+	void __iomem		*iomem;
+	int			 irq;
+	struct clk		*clk;
+	struct i2c_adapter	 adap;
+
+	/* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
+	spinlock_t		lock;
+
+	/* beginning of lock scope */
+	unsigned char		*rbuf;
+	int			rd_total_len;
+	int			rd_data_xfered;
+	int			rd_cmd_xfered;
+
+	unsigned char		*wbuf;
+	int			wt_len;
+
+	int			is_write;
+	int			stop_hold;
+	int			speed;
+
+	int			data_buf[BUFSIZE];
+	int			cmd_buf[BUFSIZE];
+	int			cmd;
+
+	/* end of lock scope */
+	struct completion	trans_waitq;
+};
+
+static inline unsigned short jz4780_i2c_readw(struct jz4780_i2c *i2c,
+					      unsigned long offset)
+{
+	return readw(i2c->iomem + offset);
+}
+
+static inline void jz4780_i2c_writew(struct jz4780_i2c *i2c,
+				     unsigned long offset, unsigned short val)
+{
+	writew(val, i2c->iomem + offset);
+}
+
+static int jz4780_i2c_disable(struct jz4780_i2c *i2c)
+{
+	unsigned short regval;
+	unsigned long loops = 5;
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 0);
+
+	do {
+		regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
+		if (!(regval & JZ4780_I2C_ENB_I2C))
+			return 0;
+
+		usleep_range(5000, 15000);
+	} while (--loops);
+
+	dev_err(&i2c->adap.dev, "disable failed: ENSTA=0x%04x\n", regval);
+	return -ETIMEDOUT;
+}
+
+static int jz4780_i2c_enable(struct jz4780_i2c *i2c)
+{
+	unsigned short regval;
+	unsigned long loops = 5;
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 1);
+
+	do {
+		regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
+		if (regval & JZ4780_I2C_ENB_I2C)
+			return 0;
+
+		usleep_range(5000, 15000);
+	} while (--loops);
+
+	dev_err(&i2c->adap.dev, "enable failed: ENSTA=0x%04x\n", regval);
+	return -ETIMEDOUT;
+}
+
+static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address)
+{
+	unsigned short regval;
+	unsigned long loops = 5;
+
+	do {
+		regval = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+		if ((regval & JZ4780_I2C_STA_TFE) &&
+		    !(regval & JZ4780_I2C_STA_MSTACT))
+			break;
+
+		usleep_range(5000, 15000);
+	} while (--loops);
+
+	if (loops) {
+		jz4780_i2c_writew(i2c, JZ4780_I2C_TAR, address);
+		return 0;
+	}
+
+	dev_err(&i2c->adap.dev,
+		"set device to address 0x%02x failed, STA=0x%04x\n",
+		address, regval);
+
+	return -ENXIO;
+}
+
+static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
+{
+	int dev_clk_khz = clk_get_rate(i2c->clk) / 1000;
+	int cnt_high = 0;	/* HIGH period count of the SCL clock */
+	int cnt_low = 0;	/* LOW period count of the SCL clock */
+	int cnt_period = 0;	/* period count of the SCL clock */
+	int setup_time = 0;
+	int hold_time = 0;
+	unsigned short tmp = 0;
+	int i2c_clk = i2c->speed;
+
+	if (jz4780_i2c_disable(i2c))
+		dev_dbg(&i2c->adap.dev, "i2c not disabled\n");
+
+	/*
+	 * 1 JZ4780_I2C cycle equals to cnt_period PCLK(i2c_clk)
+	 * standard mode, min LOW and HIGH period are 4700 ns and 4000 ns
+	 * fast mode, min LOW and HIGH period are 1300 ns and 600 ns
+	 */
+	cnt_period = dev_clk_khz / i2c_clk;
+
+	if (i2c_clk <= 100)
+		cnt_high = (cnt_period * 4000) / (4700 + 4000);
+	else
+		cnt_high = (cnt_period * 600) / (1300 + 600);
+
+	cnt_low = cnt_period - cnt_high;
+
+	/*
+	 * NOTE: JZ4780_I2C_CTRL_REST can't set when i2c enabled, because
+	 * normal read are 2 messages, we cannot disable i2c controller
+	 * between these two messages, this means that we must always set
+	 * JZ4780_I2C_CTRL_REST when init JZ4780_I2C_CTRL
+	 *
+	 */
+	if (i2c_clk <= 100) {
+		tmp = JZ4780_I2C_CTRL_SPDS | JZ4780_I2C_CTRL_REST
+		      | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
+		jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+		jz4780_i2c_writew(i2c, JZ4780_I2C_SHCNT,
+				  JZ4780_I2CSHCNT_ADJUST(cnt_high));
+		jz4780_i2c_writew(i2c, JZ4780_I2C_SLCNT,
+				  JZ4780_I2CSLCNT_ADJUST(cnt_low));
+	} else {
+		tmp = JZ4780_I2C_CTRL_SPDF | JZ4780_I2C_CTRL_REST
+		      | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
+		jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+		jz4780_i2c_writew(i2c, JZ4780_I2C_FHCNT,
+				  JZ4780_I2CFHCNT_ADJUST(cnt_high));
+		jz4780_i2c_writew(i2c, JZ4780_I2C_FLCNT,
+				  JZ4780_I2CFLCNT_ADJUST(cnt_low));
+	}
+
+	/*
+	 * a i2c device must internally provide a hold time at least 300ns
+	 * tHD:DAT
+	 *	Standard Mode: min=300ns, max=3450ns
+	 *	Fast Mode: min=0ns, max=900ns
+	 * tSU:DAT
+	 *	Standard Mode: min=250ns, max=infinite
+	 *	Fast Mode: min=100(250ns is recommended), max=infinite
+	 *
+	 * 1i2c_clk = 10^6 / dev_clk_khz
+	 * on FPGA, dev_clk_khz = 12000, so 1i2c_clk = 1000/12 = 83ns
+	 * on Pisces(1008M), dev_clk_khz=126000, so 1i2c_clk = 1000 / 126 = 8ns
+	 *
+	 * The actual hold time is (SDAHD + 1) * (i2c_clk period).
+	 *
+	 * Length of setup time calculated using (SDASU - 1) * (ic_clk_period)
+	 *
+	 */
+	if (i2c_clk <= 100) { /* standard mode */
+		setup_time = 300;
+		hold_time = 400;
+	} else {
+		setup_time = 450;
+		hold_time = 450;
+	}
+
+	hold_time = ((hold_time * dev_clk_khz) / 1000000) - 1;
+	setup_time = ((setup_time * dev_clk_khz) / 1000000)  + 1;
+
+	if (setup_time > 255)
+		setup_time = 255;
+
+	if (setup_time <= 0)
+		setup_time = 1;
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_SDASU, setup_time);
+
+	if (hold_time > 255)
+		hold_time = 255;
+
+	if (hold_time >= 0) {
+		/*i2c hold time enable */
+		hold_time |= JZ4780_I2C_SDAHD_HDENB;
+		jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
+	} else {
+		/* disable hold time */
+		jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
+	}
+
+	return 0;
+}
+
+static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c)
+{
+	int ret;
+	unsigned long flags;
+	unsigned short tmp;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	/* can send stop now if need */
+	tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+	tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+	jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+	/* disable all interrupts first */
+	jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
+
+	/* then clear all interrupts */
+	jz4780_i2c_readw(i2c, JZ4780_I2C_CTXABRT);
+	jz4780_i2c_readw(i2c, JZ4780_I2C_CINTR);
+
+	/* then disable the controller */
+	tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+	tmp &= ~JZ4780_I2C_ENB_I2C;
+	jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+	udelay(10);
+	tmp |= JZ4780_I2C_ENB_I2C;
+	jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	ret = jz4780_i2c_disable(i2c);
+	if (ret)
+		dev_err(&i2c->adap.dev,
+			"unable to disable device during cleanup!\n");
+
+	if (unlikely(jz4780_i2c_readw(i2c, JZ4780_I2C_INTM)
+		     & jz4780_i2c_readw(i2c, JZ4780_I2C_INTST)))
+		dev_err(&i2c->adap.dev,
+			"device has interrupts after a complete cleanup!\n");
+
+	return ret;
+}
+
+static int jz4780_i2c_prepare(struct jz4780_i2c *i2c)
+{
+	jz4780_i2c_set_speed(i2c);
+	return jz4780_i2c_enable(i2c);
+}
+
+static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count)
+{
+	int i;
+
+	for (i = 0; i < cmd_count; i++)
+		jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
+}
+
+static void jz4780_i2c_trans_done(struct jz4780_i2c *i2c)
+{
+	jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
+	complete(&i2c->trans_waitq);
+}
+
+static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
+{
+	unsigned short tmp;
+	unsigned short intst;
+	unsigned short intmsk;
+	struct jz4780_i2c *i2c = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+	intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
+	intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST);
+
+	intst &= intmsk;
+
+	if (intst & JZ4780_I2C_INTST_TXABT) {
+		jz4780_i2c_trans_done(i2c);
+		goto done;
+	}
+
+	if (intst & JZ4780_I2C_INTST_RXOF) {
+		dev_dbg(&i2c->adap.dev, "received fifo overflow!\n");
+		jz4780_i2c_trans_done(i2c);
+		goto done;
+	}
+
+	/*
+	 * When reading, always drain RX FIFO before we send more Read
+	 * Commands to avoid fifo overrun
+	 */
+	if (i2c->is_write == 0) {
+		int rd_left;
+
+		while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA)
+				  & JZ4780_I2C_STA_RFNE)) {
+			*(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC)
+					 & 0xff;
+			i2c->rd_data_xfered++;
+			if (i2c->rd_data_xfered == i2c->rd_total_len) {
+				jz4780_i2c_trans_done(i2c);
+				goto done;
+			}
+		}
+
+		rd_left = i2c->rd_total_len - i2c->rd_data_xfered;
+
+		if (rd_left <= JZ4780_I2C_FIFO_LEN)
+			jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
+	}
+
+	if (intst & JZ4780_I2C_INTST_TXEMP) {
+		if (i2c->is_write == 0) {
+			int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
+			int max_send = (JZ4780_I2C_FIFO_LEN - 1)
+					 - (i2c->rd_cmd_xfered
+					 - i2c->rd_data_xfered);
+			int cmd_to_send = min(cmd_left, max_send);
+
+			if (i2c->rd_cmd_xfered != 0)
+				cmd_to_send = min(cmd_to_send,
+						  JZ4780_I2C_FIFO_LEN
+						  - TX_LEVEL - 1);
+
+			if (cmd_to_send) {
+				jz4780_i2c_send_rcmd(i2c, cmd_to_send);
+				i2c->rd_cmd_xfered += cmd_to_send;
+			}
+
+			cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
+			if (cmd_left == 0) {
+				intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
+				intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
+				jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
+
+				tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+				tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+				jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+			}
+		} else {
+			unsigned short data;
+			unsigned short i2c_sta;
+
+			i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+
+			while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
+			       (i2c->wt_len > 0)) {
+				i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+				data = *i2c->wbuf;
+				data &= ~JZ4780_I2C_DC_READ;
+				jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
+						  data);
+				i2c->wbuf++;
+				i2c->wt_len--;
+			}
+
+			if (i2c->wt_len == 0) {
+				if (!i2c->stop_hold) {
+					tmp = jz4780_i2c_readw(i2c,
+							       JZ4780_I2C_CTRL);
+					tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+					jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL,
+							  tmp);
+				}
+
+				jz4780_i2c_trans_done(i2c);
+				goto done;
+			}
+		}
+	}
+
+done:
+	spin_unlock_irqrestore(&i2c->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src)
+{
+	int i;
+
+	dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src);
+	dev_err(&i2c->adap.dev, "device addr=%x\n",
+		jz4780_i2c_readw(i2c, JZ4780_I2C_TAR));
+	dev_err(&i2c->adap.dev, "send cmd count:%d  %d\n",
+		i2c->cmd, i2c->cmd_buf[i2c->cmd]);
+	dev_err(&i2c->adap.dev, "receive data count:%d  %d\n",
+		i2c->cmd, i2c->data_buf[i2c->cmd]);
+
+	for (i = 0; i < 16; i++) {
+		if (src & BIT(i))
+			dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n",
+				i, jz4780_i2c_abrt_src[i]);
+	}
+}
+
+static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
+				       unsigned char *buf, int len, int cnt,
+				       int idx)
+{
+	int ret = 0;
+	long timeout;
+	int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
+	unsigned short tmp;
+	unsigned long flags;
+
+	memset(buf, 0, len);
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	i2c->stop_hold = 0;
+	i2c->is_write = 0;
+	i2c->rbuf = buf;
+	i2c->rd_total_len = len;
+	i2c->rd_data_xfered = 0;
+	i2c->rd_cmd_xfered = 0;
+
+	if (len <= JZ4780_I2C_FIFO_LEN)
+		jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1);
+	else
+		jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL);
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_INTM,
+			  JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
+			  | JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
+
+	tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+	tmp |= JZ4780_I2C_CTRL_STPHLD;
+	jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	timeout = wait_for_completion_timeout(&i2c->trans_waitq,
+					      msecs_to_jiffies(wait_time));
+
+	if (!timeout) {
+		dev_err(&i2c->adap.dev, "irq read timeout\n");
+		dev_dbg(&i2c->adap.dev, "send cmd count:%d  %d\n",
+			i2c->cmd, i2c->cmd_buf[i2c->cmd]);
+		dev_dbg(&i2c->adap.dev, "receive data count:%d  %d\n",
+			i2c->cmd, i2c->data_buf[i2c->cmd]);
+		ret = -EIO;
+	}
+
+	tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
+	if (tmp) {
+		jz4780_i2c_txabrt(i2c, tmp);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
+					unsigned char *buf, int len,
+					int cnt, int idx)
+{
+	int ret = 0;
+	int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
+	long timeout;
+	unsigned short tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i2c->lock, flags);
+
+	if (idx < (cnt - 1))
+		i2c->stop_hold = 1;
+	else
+		i2c->stop_hold = 0;
+
+	i2c->is_write = 1;
+	i2c->wbuf = buf;
+	i2c->wt_len = len;
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP
+					| JZ4780_I2C_INTM_MTXABT);
+
+	tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+	tmp |= JZ4780_I2C_CTRL_STPHLD;
+	jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	timeout = wait_for_completion_timeout(&i2c->trans_waitq,
+					      msecs_to_jiffies(wait_time));
+	if (timeout && !i2c->stop_hold) {
+		unsigned short i2c_sta;
+		int write_in_process;
+
+		timeout = JZ4780_I2C_TIMEOUT * 100;
+		for (; timeout > 0; timeout--) {
+			i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+
+			write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) ||
+				!(i2c_sta & JZ4780_I2C_STA_TFE);
+			if (!write_in_process)
+				break;
+			udelay(10);
+		}
+	}
+
+	if (!timeout) {
+		dev_err(&i2c->adap.dev, "write wait timeout\n");
+		ret = -EIO;
+	}
+
+	tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
+	if (tmp) {
+		jz4780_i2c_txabrt(i2c, tmp);
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int jz4780_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+			   int count)
+{
+	int i = -EIO;
+	int ret = 0;
+	struct jz4780_i2c *i2c = adap->algo_data;
+
+	ret = jz4780_i2c_prepare(i2c);
+	if (ret) {
+		dev_err(&i2c->adap.dev, "I2C prepare failed\n");
+		goto out;
+	}
+
+	if (msg->addr != jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)) {
+		ret = jz4780_i2c_set_target(i2c, msg->addr);
+		if (ret)
+			goto out;
+	}
+	for (i = 0; i < count; i++, msg++) {
+		if (msg->flags & I2C_M_RD)
+			ret = jz4780_i2c_xfer_read(i2c, msg->buf, msg->len,
+						   count, i);
+		else
+			ret = jz4780_i2c_xfer_write(i2c, msg->buf, msg->len,
+						    count, i);
+
+		if (ret)
+			goto out;
+	}
+
+	ret = i;
+
+out:
+	jz4780_i2c_cleanup(i2c);
+	return ret;
+}
+
+static u32 jz4780_i2c_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm jz4780_i2c_algorithm = {
+	.master_xfer	= jz4780_i2c_xfer,
+	.functionality	= jz4780_i2c_functionality,
+};
+
+static const struct of_device_id jz4780_i2c_of_matches[] = {
+	{ .compatible = "ingenic,jz4780-i2c", },
+	{ /* sentinel */ }
+};
+
+static int jz4780_i2c_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	unsigned int clk_freq = 0;
+	unsigned short tmp;
+	struct resource *r;
+	struct jz4780_i2c *i2c;
+
+	i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	i2c->adap.owner		= THIS_MODULE;
+	i2c->adap.algo		= &jz4780_i2c_algorithm;
+	i2c->adap.algo_data	= i2c;
+	i2c->adap.retries	= 5;
+	i2c->adap.dev.parent	= &pdev->dev;
+	i2c->adap.dev.of_node	= pdev->dev.of_node;
+	sprintf(i2c->adap.name, "%s", pdev->name);
+
+	init_completion(&i2c->trans_waitq);
+	spin_lock_init(&i2c->lock);
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	i2c->iomem = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(i2c->iomem))
+		return PTR_ERR(i2c->iomem);
+
+	platform_set_drvdata(pdev, i2c);
+
+	i2c->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2c->clk))
+		return PTR_ERR(i2c->clk);
+
+	clk_prepare_enable(i2c->clk);
+
+	if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+				 &clk_freq)) {
+		dev_err(&pdev->dev, "clock-frequency not specified in DT");
+		return clk_freq;
+	}
+
+	i2c->speed = clk_freq / 1000;
+	jz4780_i2c_set_speed(i2c);
+
+	dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed);
+
+	tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+	tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+	jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+	jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
+
+	i2c->cmd = 0;
+	memset(i2c->cmd_buf, 0, BUFSIZE);
+	memset(i2c->data_buf, 0, BUFSIZE);
+
+	i2c->irq = platform_get_irq(pdev, 0);
+	ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
+			       dev_name(&pdev->dev), i2c);
+	if (ret) {
+		ret = -ENODEV;
+		goto err;
+	}
+
+	ret = i2c_add_adapter(&i2c->adap);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to add bus\n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	clk_disable_unprepare(i2c->clk);
+	return ret;
+}
+
+static int jz4780_i2c_remove(struct platform_device *pdev)
+{
+	struct jz4780_i2c *i2c = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(i2c->clk);
+	i2c_del_adapter(&i2c->adap);
+	return 0;
+}
+
+static struct platform_driver jz4780_i2c_driver = {
+	.probe		= jz4780_i2c_probe,
+	.remove		= jz4780_i2c_remove,
+	.driver		= {
+		.name	= "jz4780-i2c",
+		.of_match_table = of_match_ptr(jz4780_i2c_of_matches),
+	},
+};
+
+module_platform_driver(jz4780_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ztyan<ztyan@ingenic.cn>");
+MODULE_DESCRIPTION("i2c driver for JZ4780 SoCs");
-- 
cgit v1.2.3


From 623e4ecb869ea5c643715a08f376987887664de1 Mon Sep 17 00:00:00 2001
From: Ioan Nicu <ioan.nicu.ext@nokia.com>
Date: Mon, 30 Mar 2015 15:03:38 +0200
Subject: i2c: i2c-mux-gpio: remove error messages for probe deferrals

Probe deferral is not an error case. It happens only when
the necessary dependencies are not there yet.

The driver core is already printing a message when a driver
requests probe deferral, so this can be traced in the logs
without these error prints.

This patch removes the error messages for these deferral cases.

Signed-off-by: Ionut Nicu <ioan.nicu.ext@nokia.com>
Acked-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Acked-by: Peter Korsgaard <peter.korsgaard@barco.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/muxes/i2c-mux-gpio.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c
index f5798eb4076b..70db99264339 100644
--- a/drivers/i2c/muxes/i2c-mux-gpio.c
+++ b/drivers/i2c/muxes/i2c-mux-gpio.c
@@ -76,10 +76,9 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux,
 		return -ENODEV;
 	}
 	adapter = of_find_i2c_adapter_by_node(adapter_np);
-	if (!adapter) {
-		dev_err(&pdev->dev, "Cannot find parent bus\n");
+	if (!adapter)
 		return -EPROBE_DEFER;
-	}
+
 	mux->data.parent = i2c_adapter_id(adapter);
 	put_device(&adapter->dev);
 
@@ -177,11 +176,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
 	}
 
 	parent = i2c_get_adapter(mux->data.parent);
-	if (!parent) {
-		dev_err(&pdev->dev, "Parent adapter (%d) not found\n",
-			mux->data.parent);
+	if (!parent)
 		return -EPROBE_DEFER;
-	}
 
 	mux->parent = parent;
 	mux->gpio_base = gpio_base;
-- 
cgit v1.2.3


From 2b2190a375d796a5ad9ec557cb51269f36b264d4 Mon Sep 17 00:00:00 2001
From: Grygorii Strashko <grygorii.strashko@ti.com>
Date: Mon, 6 Apr 2015 15:38:39 +0300
Subject: i2c: change input parameter to i2c_adapter for
 prepare/unprepare_recovery
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch changes type of input parameter for
prepare/unprepare_recovery() callbacks from struct i2c_bus_recovery_info
* to struct i2c_adapter *. This allows to simplify implementation of
these callbacks and avoid type conversations from i2c_bus_recovery_info
to i2c_adapter. The i2c_bus_recovery_info can be simply retrieved from
struct i2c_adapter which contains pointer on it. There are no users
currently, so this is safe to do.

Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/i2c-core.c | 4 ++--
 include/linux/i2c.h    | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index fe80f85896e2..617a19acf76a 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -561,7 +561,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
 	int i = 0, val = 1, ret = 0;
 
 	if (bri->prepare_recovery)
-		bri->prepare_recovery(bri);
+		bri->prepare_recovery(adap);
 
 	/*
 	 * By this time SCL is high, as we need to give 9 falling-rising edges
@@ -586,7 +586,7 @@ static int i2c_generic_recovery(struct i2c_adapter *adap)
 	}
 
 	if (bri->unprepare_recovery)
-		bri->unprepare_recovery(bri);
+		bri->unprepare_recovery(adap);
 
 	return ret;
 }
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index c5e4bb2c5759..898033f41d76 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -435,8 +435,8 @@ struct i2c_bus_recovery_info {
 	void (*set_scl)(struct i2c_adapter *, int val);
 	int (*get_sda)(struct i2c_adapter *);
 
-	void (*prepare_recovery)(struct i2c_bus_recovery_info *bri);
-	void (*unprepare_recovery)(struct i2c_bus_recovery_info *bri);
+	void (*prepare_recovery)(struct i2c_adapter *);
+	void (*unprepare_recovery)(struct i2c_adapter *);
 
 	/* gpio recovery */
 	int scl_gpio;
-- 
cgit v1.2.3


From 2e65676f710e8feb9f76a7beee649b0e5ff95ca3 Mon Sep 17 00:00:00 2001
From: Grygorii Strashko <grygorii.strashko@ti.com>
Date: Mon, 6 Apr 2015 15:38:40 +0300
Subject: i2c: davinci: use bus recovery infrastructure
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch converts Davinci I2C driver to use I2C bus recovery
infrastructure, introduced by commit 5f9296ba21b3 ("i2c: Add
bus recovery infrastructure").

The i2c_bus_recovery_info is configured for Davinci I2C adapter
only in case scl_pin is provided in platform data.

As the controller must be held in reset while doing so, the
recovery routine must re-init the controller. Since this was already
being done after each call to i2c_recover_bus, move those calls into
the recovery_prepare/unprepare routines and as well.

Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 drivers/i2c/busses/i2c-davinci.c | 77 +++++++++++++++++++---------------------
 1 file changed, 36 insertions(+), 41 deletions(-)

(limited to 'drivers/i2c')

diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 120a4ef36ef5..54819fb4f82e 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -129,43 +129,6 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
 	return readw_relaxed(i2c_dev->base + reg);
 }
 
-/* Generate a pulse on the i2c clock pin. */
-static void davinci_i2c_clock_pulse(unsigned int scl_pin)
-{
-	u16 i;
-
-	if (scl_pin) {
-		/* Send high and low on the SCL line */
-		for (i = 0; i < 9; i++) {
-			gpio_set_value(scl_pin, 0);
-			udelay(20);
-			gpio_set_value(scl_pin, 1);
-			udelay(20);
-		}
-	}
-}
-
-/* This routine does i2c bus recovery as specified in the
- * i2c protocol Rev. 03 section 3.16 titled "Bus clear"
- */
-static void davinci_i2c_recover_bus(struct davinci_i2c_dev *dev)
-{
-	u32 flag = 0;
-	struct davinci_i2c_platform_data *pdata = dev->pdata;
-
-	dev_err(dev->dev, "initiating i2c bus recovery\n");
-	/* Send NACK to the slave */
-	flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
-	flag |=  DAVINCI_I2C_MDR_NACK;
-	/* write the data into mode register */
-	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
-	davinci_i2c_clock_pulse(pdata->scl_pin);
-	/* Send STOP */
-	flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
-	flag |= DAVINCI_I2C_MDR_STP;
-	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
-}
-
 static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
 								int val)
 {
@@ -262,6 +225,34 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
 	return 0;
 }
 
+/*
+ * This routine does i2c bus recovery by using i2c_generic_gpio_recovery
+ * which is provided by I2C Bus recovery infrastructure.
+ */
+static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+	/* Disable interrupts */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, 0);
+
+	/* put I2C into reset */
+	davinci_i2c_reset_ctrl(dev, 0);
+}
+
+static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+	i2c_davinci_init(dev);
+}
+
+static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = {
+	.recover_bus = i2c_generic_gpio_recovery,
+	.prepare_recovery = davinci_i2c_prepare_recovery,
+	.unprepare_recovery = davinci_i2c_unprepare_recovery,
+};
+
 /*
  * Waiting for bus not busy
  */
@@ -282,8 +273,7 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
 				return -ETIMEDOUT;
 			} else {
 				to_cnt = 0;
-				davinci_i2c_recover_bus(dev);
-				i2c_davinci_init(dev);
+				i2c_recover_bus(&dev->adapter);
 			}
 		}
 		if (allow_sleep)
@@ -372,8 +362,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
 						dev->adapter.timeout);
 	if (!time_left) {
 		dev_err(dev->dev, "controller timed out\n");
-		davinci_i2c_recover_bus(dev);
-		i2c_davinci_init(dev);
+		i2c_recover_bus(adap);
 		dev->buf_len = 0;
 		return -ETIMEDOUT;
 	}
@@ -712,6 +701,12 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 	adap->timeout = DAVINCI_I2C_TIMEOUT;
 	adap->dev.of_node = pdev->dev.of_node;
 
+	if (dev->pdata->scl_pin) {
+		adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info;
+		adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin;
+		adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin;
+	}
+
 	adap->nr = pdev->id;
 	r = i2c_add_numbered_adapter(adap);
 	if (r) {
-- 
cgit v1.2.3


From 7ef97e9a312c359a2b32a7b5d918c60f238b69b2 Mon Sep 17 00:00:00 2001
From: Grygorii Strashko <grygorii.strashko@ti.com>
Date: Mon, 6 Apr 2015 15:38:41 +0300
Subject: i2c: davinci: use ICPFUNC to toggle I2C as gpio for bus recovery
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Having a board where the I2C bus locks up occasionally made it clear
that the bus recovery in the i2c-davinci driver will only work on
some boards, because on regular boards, this will only toggle GPIO
lines that aren't muxed to the actual pins.

The I2C controller on SoCs like da850 (and da830), Keystone 2 has the
built-in capability to bit-bang its lines by using the ICPFUNC registers
of the i2c controller.
Implement the suggested procedure by toggling SCL and checking SDA using
the ICPFUNC registers of the I2C controller when present. Allow platforms
to indicate the presence of the ICPFUNC registers with a has_pfunc platform
data flag and add optional DT property "ti,has-pfunc" to indicate
the same in DT.

Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
Tested-by: Michael Lawnick <michael.lawnick@nokia.com>
Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Signed-off-by: Mike Looijmans <milo-software@users.sourceforge.net>
[grygorii.strashko@ti.com: combined patches from Ben Gardiner and
Mike Looijmans and reimplemented ICPFUNC bus recovery using I2C
bus recovery infrastructure]
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 .../devicetree/bindings/i2c/i2c-davinci.txt        |   3 +
 drivers/i2c/busses/i2c-davinci.c                   | 102 ++++++++++++++++++++-
 include/linux/platform_data/i2c-davinci.h          |   1 +
 3 files changed, 105 insertions(+), 1 deletion(-)

(limited to 'drivers/i2c')

diff --git a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
index 2dc935b4113d..a4e1cbc810c1 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
@@ -10,6 +10,9 @@ Required properties:
 Recommended properties :
 - interrupts : standard interrupt property.
 - clock-frequency : desired I2C bus clock frequency in Hz.
+- ti,has-pfunc: boolean; if defined, it indicates that SoC supports PFUNC
+	registers. PFUNC registers allow to switch I2C pins to function as
+	GPIOs, so they can by toggled manually.
 
 Example (enbw_cmc board):
 	i2c@1c22000 {
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 54819fb4f82e..4788a32afb86 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -60,6 +60,12 @@
 #define DAVINCI_I2C_IVR_REG	0x28
 #define DAVINCI_I2C_EMDR_REG	0x2c
 #define DAVINCI_I2C_PSC_REG	0x30
+#define DAVINCI_I2C_FUNC_REG	0x48
+#define DAVINCI_I2C_DIR_REG	0x4c
+#define DAVINCI_I2C_DIN_REG	0x50
+#define DAVINCI_I2C_DOUT_REG	0x54
+#define DAVINCI_I2C_DSET_REG	0x58
+#define DAVINCI_I2C_DCLR_REG	0x5c
 
 #define DAVINCI_I2C_IVR_AAS	0x07
 #define DAVINCI_I2C_IVR_SCD	0x06
@@ -93,6 +99,29 @@
 #define DAVINCI_I2C_IMR_NACK	BIT(1)
 #define DAVINCI_I2C_IMR_AL	BIT(0)
 
+/* set SDA and SCL as GPIO */
+#define DAVINCI_I2C_FUNC_PFUNC0	BIT(0)
+
+/* set SCL as output when used as GPIO*/
+#define DAVINCI_I2C_DIR_PDIR0	BIT(0)
+/* set SDA as output when used as GPIO*/
+#define DAVINCI_I2C_DIR_PDIR1	BIT(1)
+
+/* read SCL GPIO level */
+#define DAVINCI_I2C_DIN_PDIN0 BIT(0)
+/* read SDA GPIO level */
+#define DAVINCI_I2C_DIN_PDIN1 BIT(1)
+
+/*set the SCL GPIO high */
+#define DAVINCI_I2C_DSET_PDSET0	BIT(0)
+/*set the SDA GPIO high */
+#define DAVINCI_I2C_DSET_PDSET1	BIT(1)
+
+/* set the SCL GPIO low */
+#define DAVINCI_I2C_DCLR_PDCLR0	BIT(0)
+/* set the SDA GPIO low */
+#define DAVINCI_I2C_DCLR_PDCLR1	BIT(1)
+
 struct davinci_i2c_dev {
 	struct device           *dev;
 	void __iomem		*base;
@@ -253,6 +282,71 @@ static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = {
 	.unprepare_recovery = davinci_i2c_unprepare_recovery,
 };
 
+static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+	if (val)
+		davinci_i2c_write_reg(dev, DAVINCI_I2C_DSET_REG,
+				      DAVINCI_I2C_DSET_PDSET0);
+	else
+		davinci_i2c_write_reg(dev, DAVINCI_I2C_DCLR_REG,
+				      DAVINCI_I2C_DCLR_PDCLR0);
+}
+
+static int davinci_i2c_get_scl(struct i2c_adapter *adap)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+	int val;
+
+	/* read the state of SCL */
+	val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
+	return val & DAVINCI_I2C_DIN_PDIN0;
+}
+
+static int davinci_i2c_get_sda(struct i2c_adapter *adap)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+	int val;
+
+	/* read the state of SDA */
+	val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
+	return val & DAVINCI_I2C_DIN_PDIN1;
+}
+
+static void davinci_i2c_scl_prepare_recovery(struct i2c_adapter *adap)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+	davinci_i2c_prepare_recovery(adap);
+
+	/* SCL output, SDA input */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_DIR_REG, DAVINCI_I2C_DIR_PDIR0);
+
+	/* change to GPIO mode */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG,
+			      DAVINCI_I2C_FUNC_PFUNC0);
+}
+
+static void davinci_i2c_scl_unprepare_recovery(struct i2c_adapter *adap)
+{
+	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+	/* change back to I2C mode */
+	davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, 0);
+
+	davinci_i2c_unprepare_recovery(adap);
+}
+
+static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = {
+	.recover_bus = i2c_generic_scl_recovery,
+	.set_scl = davinci_i2c_set_scl,
+	.get_scl = davinci_i2c_get_scl,
+	.get_sda = davinci_i2c_get_sda,
+	.prepare_recovery = davinci_i2c_scl_prepare_recovery,
+	.unprepare_recovery = davinci_i2c_scl_unprepare_recovery,
+};
+
 /*
  * Waiting for bus not busy
  */
@@ -660,6 +754,10 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 		if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
 			&prop))
 			dev->pdata->bus_freq = prop / 1000;
+
+		dev->pdata->has_pfunc =
+			of_property_read_bool(pdev->dev.of_node,
+					      "ti,has-pfunc");
 	} else if (!dev->pdata) {
 		dev->pdata = &davinci_i2c_platform_data_default;
 	}
@@ -701,7 +799,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 	adap->timeout = DAVINCI_I2C_TIMEOUT;
 	adap->dev.of_node = pdev->dev.of_node;
 
-	if (dev->pdata->scl_pin) {
+	if (dev->pdata->has_pfunc)
+		adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;
+	else if (dev->pdata->scl_pin) {
 		adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info;
 		adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin;
 		adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin;
diff --git a/include/linux/platform_data/i2c-davinci.h b/include/linux/platform_data/i2c-davinci.h
index 2312d197dfb7..89fd34727a24 100644
--- a/include/linux/platform_data/i2c-davinci.h
+++ b/include/linux/platform_data/i2c-davinci.h
@@ -18,6 +18,7 @@ struct davinci_i2c_platform_data {
 	unsigned int	bus_delay;	/* post-transaction delay (usec) */
 	unsigned int    sda_pin;        /* GPIO pin ID to use for SDA */
 	unsigned int    scl_pin;        /* GPIO pin ID to use for SCL */
+	bool		has_pfunc;	/*chip has a ICPFUNC register */
 };
 
 /* for board setup code */
-- 
cgit v1.2.3


From 2bbd681ba2bfa0f3805fb541b0840b96893c5727 Mon Sep 17 00:00:00 2001
From: Subhendu Sekhar Behera <sbehera@broadcom.com>
Date: Wed, 18 Mar 2015 17:20:29 +0530
Subject: i2c: xlp9xx: Driver for Netlogic XLP9XX/5XX I2C controller

Add an I2C bus driver i2c-xlp9xx.c to support the I2C block in the
XLP9xx/XLP5xx MIPS SoC. Update Kconfig and Makefile to add the
CONFIG_I2C_XLP9XX option.

Signed-off-by: Subhendu Sekhar Behera <sbehera@broadcom.com>
Signed-off-by: Jayachandran C <jchandra@broadcom.com>
Reviewed-by: Ray Jui <rjui@broadcom.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
---
 .../devicetree/bindings/i2c/i2c-xlp9xx.txt         |  22 +
 drivers/i2c/busses/Kconfig                         |  10 +
 drivers/i2c/busses/Makefile                        |   1 +
 drivers/i2c/busses/i2c-xlp9xx.c                    | 445 +++++++++++++++++++++
 4 files changed, 478 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt
 create mode 100644 drivers/i2c/busses/i2c-xlp9xx.c

(limited to 'drivers/i2c')

diff --git a/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt
new file mode 100644
index 000000000000..f818ef507ab7
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-xlp9xx.txt
@@ -0,0 +1,22 @@
+Device tree configuration for the I2C controller on the XLP9xx/5xx SoC
+
+Required properties:
+- compatible      : should be "netlogic,xlp980-i2c"
+- reg             : bus address start and address range size of device
+- interrupts      : interrupt number
+
+Optional properties:
+- clock-frequency : frequency of bus clock in Hz
+                    Defaults to 100 KHz when the property is not specified
+
+Example:
+
+i2c0: i2c@113100 {
+	compatible = "netlogic,xlp980-i2c";
+	#address-cells = <1>;
+	#size-cells = <0>;
+	reg = <0 0x113100 0x100>;
+	clock-frequency = <400000>;
+	interrupts = <30>;
+	interrupt-parent = <&pic>;
+};
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 0b0ca7dd5d1f..2255af23b9c7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -916,6 +916,16 @@ config I2C_XLR
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-xlr.
 
+config I2C_XLP9XX
+	tristate "XLP9XX I2C support"
+	depends on CPU_XLP || COMPILE_TEST
+	help
+	  This driver enables support for the on-chip I2C interface of
+	  the Broadcom XLP9xx/XLP5xx MIPS processors.
+
+	  This driver can also be built as a module.  If so, the module will
+	  be called i2c-xlp9xx.
+
 config I2C_RCAR
 	tristate "Renesas R-Car I2C Controller"
 	depends on ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ab6a0a67aca1..cdf941da91c6 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_I2C_WMT)		+= i2c-wmt.o
 obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o
 obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o
 obj-$(CONFIG_I2C_XLR)		+= i2c-xlr.o
+obj-$(CONFIG_I2C_XLP9XX)	+= i2c-xlp9xx.o
 obj-$(CONFIG_I2C_RCAR)		+= i2c-rcar.o
 
 # External I2C/SMBus adapter drivers
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
new file mode 100644
index 000000000000..c941418f06f5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2003-2015 Broadcom Corporation
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define XLP9XX_I2C_DIV			0x0
+#define XLP9XX_I2C_CTRL			0x1
+#define XLP9XX_I2C_CMD			0x2
+#define XLP9XX_I2C_STATUS		0x3
+#define XLP9XX_I2C_MTXFIFO		0x4
+#define XLP9XX_I2C_MRXFIFO		0x5
+#define XLP9XX_I2C_MFIFOCTRL		0x6
+#define XLP9XX_I2C_STXFIFO		0x7
+#define XLP9XX_I2C_SRXFIFO		0x8
+#define XLP9XX_I2C_SFIFOCTRL		0x9
+#define XLP9XX_I2C_SLAVEADDR		0xA
+#define XLP9XX_I2C_OWNADDR		0xB
+#define XLP9XX_I2C_FIFOWCNT		0xC
+#define XLP9XX_I2C_INTEN		0xD
+#define XLP9XX_I2C_INTST		0xE
+#define XLP9XX_I2C_WAITCNT		0xF
+#define XLP9XX_I2C_TIMEOUT		0X10
+#define XLP9XX_I2C_GENCALLADDR		0x11
+
+#define XLP9XX_I2C_CMD_START		BIT(7)
+#define XLP9XX_I2C_CMD_STOP		BIT(6)
+#define XLP9XX_I2C_CMD_READ		BIT(5)
+#define XLP9XX_I2C_CMD_WRITE		BIT(4)
+#define XLP9XX_I2C_CMD_ACK		BIT(3)
+
+#define XLP9XX_I2C_CTRL_MCTLEN_SHIFT	16
+#define XLP9XX_I2C_CTRL_MCTLEN_MASK	0xffff0000
+#define XLP9XX_I2C_CTRL_RST		BIT(8)
+#define XLP9XX_I2C_CTRL_EN		BIT(6)
+#define XLP9XX_I2C_CTRL_MASTER		BIT(4)
+#define XLP9XX_I2C_CTRL_FIFORD		BIT(1)
+#define XLP9XX_I2C_CTRL_ADDMODE		BIT(0)
+
+#define XLP9XX_I2C_INTEN_NACKADDR	BIT(25)
+#define XLP9XX_I2C_INTEN_SADDR		BIT(13)
+#define XLP9XX_I2C_INTEN_DATADONE	BIT(12)
+#define XLP9XX_I2C_INTEN_ARLOST		BIT(11)
+#define XLP9XX_I2C_INTEN_MFIFOFULL	BIT(4)
+#define XLP9XX_I2C_INTEN_MFIFOEMTY	BIT(3)
+#define XLP9XX_I2C_INTEN_MFIFOHI	BIT(2)
+#define XLP9XX_I2C_INTEN_BUSERR		BIT(0)
+
+#define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT		8
+#define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT		0
+#define XLP9XX_I2C_MFIFOCTRL_RST		BIT(16)
+
+#define XLP9XX_I2C_SLAVEADDR_RW			BIT(0)
+#define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT		1
+
+#define XLP9XX_I2C_IP_CLK_FREQ		133000000UL
+#define XLP9XX_I2C_DEFAULT_FREQ		100000
+#define XLP9XX_I2C_HIGH_FREQ		400000
+#define XLP9XX_I2C_FIFO_SIZE		0x80U
+#define XLP9XX_I2C_TIMEOUT_MS		1000
+
+#define XLP9XX_I2C_FIFO_WCNT_MASK	0xff
+#define XLP9XX_I2C_STATUS_ERRMASK	(XLP9XX_I2C_INTEN_ARLOST | \
+			XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR)
+
+struct xlp9xx_i2c_dev {
+	struct device *dev;
+	struct i2c_adapter adapter;
+	struct completion msg_complete;
+	int irq;
+	bool msg_read;
+	u32 __iomem *base;
+	u32 msg_buf_remaining;
+	u32 msg_len;
+	u32 clk_hz;
+	u32 msg_err;
+	u8 *msg_buf;
+};
+
+static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv,
+					unsigned long reg, u32 val)
+{
+	writel(val, priv->base + reg);
+}
+
+static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv,
+				      unsigned long reg)
+{
+	return readl(priv->base + reg);
+}
+
+static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
+{
+	u32 inten;
+
+	inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask;
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
+}
+
+static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
+{
+	u32 inten;
+
+	inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask;
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
+}
+
+static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv)
+{
+	u32 thres;
+
+	thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
+			     thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT);
+}
+
+static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
+{
+	u32 len, i;
+	u8 *buf = priv->msg_buf;
+
+	len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
+	for (i = 0; i < len; i++)
+		xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]);
+	priv->msg_buf_remaining -= len;
+	priv->msg_buf += len;
+}
+
+static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
+{
+	u32 len, i;
+	u8 *buf = priv->msg_buf;
+
+	len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
+				  XLP9XX_I2C_FIFO_WCNT_MASK;
+	len = min(priv->msg_buf_remaining, len);
+	for (i = 0; i < len; i++, buf++)
+		*buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
+
+	priv->msg_buf_remaining -= len;
+	priv->msg_buf = buf;
+
+	if (priv->msg_buf_remaining)
+		xlp9xx_i2c_update_rx_fifo_thres(priv);
+}
+
+static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id)
+{
+	struct xlp9xx_i2c_dev *priv = dev_id;
+	u32 status;
+
+	status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST);
+	if (status == 0)
+		return IRQ_NONE;
+
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status);
+	if (status & XLP9XX_I2C_STATUS_ERRMASK) {
+		priv->msg_err = status;
+		goto xfer_done;
+	}
+
+	/* SADDR ACK for SMBUS_QUICK */
+	if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0))
+		goto xfer_done;
+
+	if (!priv->msg_read) {
+		if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) {
+			/* TX FIFO got empty, fill it up again */
+			if (priv->msg_buf_remaining)
+				xlp9xx_i2c_fill_tx_fifo(priv);
+			else
+				xlp9xx_i2c_mask_irq(priv,
+						    XLP9XX_I2C_INTEN_MFIFOEMTY);
+		}
+	} else {
+		if (status & (XLP9XX_I2C_INTEN_DATADONE |
+			      XLP9XX_I2C_INTEN_MFIFOHI)) {
+			/* data is in FIFO, read it */
+			if (priv->msg_buf_remaining)
+				xlp9xx_i2c_drain_rx_fifo(priv);
+		}
+	}
+
+	/* Transfer complete */
+	if (status & XLP9XX_I2C_INTEN_DATADONE)
+		goto xfer_done;
+
+	return IRQ_HANDLED;
+
+xfer_done:
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+	complete(&priv->msg_complete);
+	return IRQ_HANDLED;
+}
+
+static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv)
+{
+	u32 prescale;
+
+	/*
+	 * The controller uses 5 * SCL clock internally.
+	 * So prescale value should be divided by 5.
+	 */
+	prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz);
+	prescale = ((prescale - 8) / 5) - 1;
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST);
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN |
+			     XLP9XX_I2C_CTRL_MASTER);
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale);
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+
+	return 0;
+}
+
+static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
+			       int last_msg)
+{
+	unsigned long timeleft;
+	u32 intr_mask, cmd, val;
+
+	priv->msg_buf = msg->buf;
+	priv->msg_buf_remaining = priv->msg_len = msg->len;
+	priv->msg_err = 0;
+	priv->msg_read = (msg->flags & I2C_M_RD);
+	reinit_completion(&priv->msg_complete);
+
+	/* Reset FIFO */
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
+			     XLP9XX_I2C_MFIFOCTRL_RST);
+
+	/* set FIFO threshold if reading */
+	if (priv->msg_read)
+		xlp9xx_i2c_update_rx_fifo_thres(priv);
+
+	/* set slave addr */
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR,
+			     (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) |
+			     (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0));
+
+	/* Build control word for transfer */
+	val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
+	if (!priv->msg_read)
+		val &= ~XLP9XX_I2C_CTRL_FIFORD;
+	else
+		val |= XLP9XX_I2C_CTRL_FIFORD;	/* read */
+
+	if (msg->flags & I2C_M_TEN)
+		val |= XLP9XX_I2C_CTRL_ADDMODE;	/* 10-bit address mode*/
+	else
+		val &= ~XLP9XX_I2C_CTRL_ADDMODE;
+
+	/* set data length to be transferred */
+	val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
+	      (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
+
+	/* fill fifo during tx */
+	if (!priv->msg_read)
+		xlp9xx_i2c_fill_tx_fifo(priv);
+
+	/* set interrupt mask */
+	intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR |
+		     XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE);
+
+	if (priv->msg_read) {
+		intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI;
+		if (msg->len == 0)
+			intr_mask |= XLP9XX_I2C_INTEN_SADDR;
+	} else {
+		if (msg->len == 0)
+			intr_mask |= XLP9XX_I2C_INTEN_SADDR;
+		else
+			intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY;
+	}
+	xlp9xx_i2c_unmask_irq(priv, intr_mask);
+
+	/* set cmd reg */
+	cmd = XLP9XX_I2C_CMD_START;
+	cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE);
+	if (last_msg)
+		cmd |= XLP9XX_I2C_CMD_STOP;
+
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd);
+
+	timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS);
+	timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft);
+
+	if (priv->msg_err) {
+		dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err);
+		if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR)
+			xlp9xx_i2c_init(priv);
+		return -EIO;
+	}
+
+	if (timeleft == 0) {
+		dev_dbg(priv->dev, "i2c transfer timed out!\n");
+		xlp9xx_i2c_init(priv);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+			   int num)
+{
+	int i, ret;
+	struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap);
+
+	for (i = 0; i < num; i++) {
+		ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1);
+		if (ret != 0)
+			return ret;
+	}
+
+	return num;
+}
+
+static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C |
+		I2C_FUNC_10BIT_ADDR;
+}
+
+static struct i2c_algorithm xlp9xx_i2c_algo = {
+	.master_xfer = xlp9xx_i2c_xfer,
+	.functionality = xlp9xx_i2c_functionality,
+};
+
+static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
+				    struct xlp9xx_i2c_dev *priv)
+{
+	struct device_node *np = pdev->dev.of_node;
+	u32 freq;
+	int err;
+
+	err = of_property_read_u32(np, "clock-frequency", &freq);
+	if (err) {
+		freq = XLP9XX_I2C_DEFAULT_FREQ;
+		dev_dbg(&pdev->dev, "using default frequency %u\n", freq);
+	} else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) {
+		dev_warn(&pdev->dev, "invalid frequency %u, using default\n",
+			 freq);
+		freq = XLP9XX_I2C_DEFAULT_FREQ;
+	}
+	priv->clk_hz = freq;
+
+	return 0;
+}
+
+static int xlp9xx_i2c_probe(struct platform_device *pdev)
+{
+	struct xlp9xx_i2c_dev *priv;
+	struct resource *res;
+	int err = 0;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->irq = platform_get_irq(pdev, 0);
+	if (priv->irq <= 0) {
+		dev_err(&pdev->dev, "invalid irq!\n");
+		return priv->irq;
+	}
+
+	xlp9xx_i2c_get_frequency(pdev, priv);
+	xlp9xx_i2c_init(priv);
+
+	err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0,
+			       pdev->name, priv);
+	if (err) {
+		dev_err(&pdev->dev, "IRQ request failed!\n");
+		return err;
+	}
+
+	init_completion(&priv->msg_complete);
+	priv->adapter.dev.parent = &pdev->dev;
+	priv->adapter.algo = &xlp9xx_i2c_algo;
+	priv->adapter.dev.of_node = pdev->dev.of_node;
+	priv->dev = &pdev->dev;
+
+	snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c");
+	i2c_set_adapdata(&priv->adapter, priv);
+
+	err = i2c_add_adapter(&priv->adapter);
+	if (err) {
+		dev_err(&pdev->dev, "failed to add I2C adapter!\n");
+		return err;
+	}
+
+	platform_set_drvdata(pdev, priv);
+	dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr);
+
+	return 0;
+}
+
+static int xlp9xx_i2c_remove(struct platform_device *pdev)
+{
+	struct xlp9xx_i2c_dev *priv;
+
+	priv = platform_get_drvdata(pdev);
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+	synchronize_irq(priv->irq);
+	i2c_del_adapter(&priv->adapter);
+	xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0);
+
+	return 0;
+}
+
+static const struct of_device_id xlp9xx_i2c_of_match[] = {
+	{ .compatible = "netlogic,xlp980-i2c", },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver xlp9xx_i2c_driver = {
+	.probe = xlp9xx_i2c_probe,
+	.remove = xlp9xx_i2c_remove,
+	.driver = {
+		.name = "xlp9xx-i2c",
+		.of_match_table = xlp9xx_i2c_of_match,
+	},
+};
+
+module_platform_driver(xlp9xx_i2c_driver);
+
+MODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>");
+MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver");
+MODULE_LICENSE("GPL v2");
-- 
cgit v1.2.3