mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4 v2] i2c: add algo-bit support with gpio and versatile support
@ 2012-11-02  9:27 Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02 10:27 ` [PATCH 0/4 v2] i2c: add algo-bit support with gpio and " Sascha Hauer
  0 siblings, 2 replies; 6+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-02  9:27 UTC (permalink / raw)
  To: barebox

HI,

	v2: keep return -EBUSY if the adapter is already present

	the foloing patch series add the i2c algo bit support with 2 drivers
	that use it

	 - gpio
	 - versatile

	 thie also create a device for i2c bus itself

	 all the pedending branch are rebased on it

The following changes since commit 2d1ceaff2f905f4a2bd7e6c539e7dd3d8d8e9bef:

  uimage: Fix deleting of temporary file (2012-10-30 18:39:38 +0100)

are available in the git repository at:

  git://git.jcrosoft.org/barebox.git delivery/i2c

for you to fetch changes up to 5c90416b6ffb8d4ca7c4bc6aff92578b555cb965:

  i2c: add versatile support (2012-11-02 02:17:04 +0800)

----------------------------------------------------------------
Jean-Christophe PLAGNIOL-VILLARD (4):
      i2c: adapter: register it's own device
      i2c: add i2c algo bit support
      i2c: add i2c-gpio support
      i2c: add versatile support

 drivers/i2c/Kconfig                |    1 +
 drivers/i2c/Makefile               |    2 +-
 drivers/i2c/algos/Kconfig          |    6 +++
 drivers/i2c/algos/Makefile         |    5 ++
 drivers/i2c/algos/i2c-algo-bit.c   |  585 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/busses/Kconfig         |   16 +++++++
 drivers/i2c/busses/Makefile        |    2 +
 drivers/i2c/busses/i2c-gpio.c      |  177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/busses/i2c-imx.c       |   20 ++++----
 drivers/i2c/busses/i2c-omap.c      |   30 ++++++------
 drivers/i2c/busses/i2c-versatile.c |  112 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/i2c.c                  |   17 ++++++-
 include/i2c/i2c-algo-bit.h         |   55 ++++++++++++++++++++++
 include/i2c/i2c-gpio.h             |   38 +++++++++++++++
 include/i2c/i2c.h                  |    4 +-
 15 files changed, 1042 insertions(+), 28 deletions(-)
 create mode 100644 drivers/i2c/algos/Kconfig
 create mode 100644 drivers/i2c/algos/Makefile
 create mode 100644 drivers/i2c/algos/i2c-algo-bit.c
 create mode 100644 drivers/i2c/busses/i2c-gpio.c
 create mode 100644 drivers/i2c/busses/i2c-versatile.c
 create mode 100644 include/i2c/i2c-algo-bit.h
 create mode 100644 include/i2c/i2c-gpio.h

Best Regards,
J.

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 1/4] i2c: adapter: register it's own device
  2012-11-02  9:27 [PATCH 0/4 v2] i2c: add algo-bit support with gpio and versatile support Jean-Christophe PLAGNIOL-VILLARD
@ 2012-11-02  9:36 ` Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36   ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD
                     ` (2 more replies)
  2012-11-02 10:27 ` [PATCH 0/4 v2] i2c: add algo-bit support with gpio and " Sascha Hauer
  1 sibling, 3 replies; 6+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-02  9:36 UTC (permalink / raw)
  To: barebox

so we can show the this of i2c busses
set the bus device as parent of all devices.

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 drivers/i2c/busses/i2c-imx.c  |   20 ++++++++++----------
 drivers/i2c/busses/i2c-omap.c |   30 +++++++++++++++---------------
 drivers/i2c/i2c.c             |   17 ++++++++++++++++-
 include/i2c/i2c.h             |    2 +-
 4 files changed, 42 insertions(+), 27 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index a1012a7..7f9a2dc 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -154,7 +154,7 @@ static int i2c_fsl_bus_busy(struct i2c_adapter *adapter, int for_busy)
 		if (!for_busy && !(temp & I2SR_IBB))
 			break;
 		if (is_timeout(start, 500 * MSECOND)) {
-			dev_err(adapter->dev,
+			dev_err(&adapter->dev,
 				 "<%s> timeout waiting for I2C bus %s\n",
 				 __func__,for_busy ? "busy" : "not busy");
 			return -EIO;
@@ -177,7 +177,7 @@ static int i2c_fsl_trx_complete(struct i2c_adapter *adapter)
 			break;
 
 		if (is_timeout(start, 100 * MSECOND)) {
-			dev_err(adapter->dev, "<%s> TXR timeout\n", __func__);
+			dev_err(&adapter->dev, "<%s> TXR timeout\n", __func__);
 			return -EIO;
 		}
 	}
@@ -199,7 +199,7 @@ static int i2c_fsl_acked(struct i2c_adapter *adapter)
 			break;
 
 		if (is_timeout(start, MSECOND)) {
-			dev_dbg(adapter->dev, "<%s> No ACK\n", __func__);
+			dev_dbg(&adapter->dev, "<%s> No ACK\n", __func__);
 			return -EIO;
 		}
 	}
@@ -368,9 +368,9 @@ static void i2c_fsl_set_clk(struct fsl_i2c_struct *i2c_fsl,
 		(500000U * i2c_clk_div[i][0] + (i2c_clk_rate / 2) - 1) /
 		(i2c_clk_rate / 2);
 
-	dev_dbg(i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
+	dev_dbg(&i2c_fsl->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",
 		__func__, i2c_clk_rate, div);
-	dev_dbg(i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
+	dev_dbg(&i2c_fsl->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",
 		__func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);
 }
 #endif
@@ -382,7 +382,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
 	int i, result;
 
 	if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
-		dev_dbg(adapter->dev,
+		dev_dbg(&adapter->dev,
 			"<%s> write slave address: addr=0x%02x\n",
 			__func__, msgs->addr << 1);
 
@@ -399,7 +399,7 @@ static int i2c_fsl_write(struct i2c_adapter *adapter, struct i2c_msg *msgs)
 
 	/* write data */
 	for (i = 0; i < msgs->len; i++) {
-		dev_dbg(adapter->dev,
+		dev_dbg(&adapter->dev,
 			"<%s> write byte: B%d=0x%02X\n",
 			__func__, i, msgs->buf[i]);
 		writeb(msgs->buf[i], base + FSL_I2C_I2DR);
@@ -425,7 +425,7 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
 	writeb(0x0, base + FSL_I2C_I2SR);
 
 	if ( !(msgs->flags & I2C_M_DATA_ONLY) ) {
-		dev_dbg(adapter->dev,
+		dev_dbg(&adapter->dev,
 			"<%s> write slave address: addr=0x%02x\n",
 			__func__, (msgs->addr << 1) | 0x01);
 
@@ -478,7 +478,7 @@ static int i2c_fsl_read(struct i2c_adapter *adapter, struct i2c_msg *msgs)
 		}
 		msgs->buf[i] = readb(base + FSL_I2C_I2DR);
 
-		dev_dbg(adapter->dev, "<%s> read byte: B%d=0x%02X\n",
+		dev_dbg(&adapter->dev, "<%s> read byte: B%d=0x%02X\n",
 			__func__, i, msgs->buf[i]);
 	}
 	return 0;
@@ -544,7 +544,7 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
 	/* Setup i2c_fsl driver structure */
 	i2c_fsl->adapter.master_xfer = i2c_fsl_xfer;
 	i2c_fsl->adapter.nr = pdev->id;
-	i2c_fsl->adapter.dev = pdev;
+	i2c_fsl->adapter.dev.parent = pdev;
 	i2c_fsl->base = dev_request_mem_region(pdev, 0);
 	i2c_fsl->dfsrr = -1;
 
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 24961eb..f371875 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -318,7 +318,7 @@ static int omap_i2c_init(struct omap_i2c_struct *i2c_omap)
 		while (!(omap_i2c_read_reg(i2c_omap, OMAP_I2C_SYSS_REG) &
 			 SYSS_RESETDONE_MASK)) {
 			if (is_timeout(start, MSECOND)) {
-				dev_warn(i2c_omap->adapter.dev, "timeout waiting "
+				dev_warn(&i2c_omap->adapter.dev, "timeout waiting "
 						"for controller reset\n");
 				return -ETIMEDOUT;
 			}
@@ -453,7 +453,7 @@ static int omap_i2c_wait_for_bb(struct i2c_adapter *adapter)
 	start = get_time_ns();
 	while (omap_i2c_read_reg(i2c_omap, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
 		if (is_timeout(start, MSECOND)) {
-			dev_warn(adapter->dev, "timeout waiting for bus ready\n");
+			dev_warn(&adapter->dev, "timeout waiting for bus ready\n");
 			return -ETIMEDOUT;
 		}
 	}
@@ -476,9 +476,9 @@ omap_i2c_isr(struct omap_i2c_struct *dev)
 
 	bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
 	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
-		dev_dbg(dev->adapter.dev, "IRQ (ISR = 0x%04x)\n", stat);
+		dev_dbg(&dev->adapter.dev, "IRQ (ISR = 0x%04x)\n", stat);
 		if (count++ == 100) {
-			dev_warn(dev->adapter.dev, "Too much work in one IRQ\n");
+			dev_warn(&dev->adapter.dev, "Too much work in one IRQ\n");
 			break;
 		}
 
@@ -499,7 +499,7 @@ complete:
 					   OMAP_I2C_CON_STP);
 		}
 		if (stat & OMAP_I2C_STAT_AL) {
-			dev_err(dev->adapter.dev, "Arbitration lost\n");
+			dev_err(&dev->adapter.dev, "Arbitration lost\n");
 			err |= OMAP_I2C_STAT_AL;
 		}
 		if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
@@ -536,11 +536,11 @@ complete:
 					}
 				} else {
 					if (stat & OMAP_I2C_STAT_RRDY)
-						dev_err(dev->adapter.dev,
+						dev_err(&dev->adapter.dev,
 							"RRDY IRQ while no data"
 								" requested\n");
 					if (stat & OMAP_I2C_STAT_RDR)
-						dev_err(dev->adapter.dev,
+						dev_err(&dev->adapter.dev,
 							"RDR IRQ while no data"
 								" requested\n");
 					break;
@@ -577,11 +577,11 @@ complete:
 					}
 				} else {
 					if (stat & OMAP_I2C_STAT_XRDY)
-						dev_err(dev->adapter.dev,
+						dev_err(&dev->adapter.dev,
 							"XRDY IRQ while no "
 							"data to send\n");
 					if (stat & OMAP_I2C_STAT_XDR)
-						dev_err(dev->adapter.dev,
+						dev_err(&dev->adapter.dev,
 							"XDR IRQ while no "
 							"data to send\n");
 					break;
@@ -613,11 +613,11 @@ complete:
 			continue;
 		}
 		if (stat & OMAP_I2C_STAT_ROVR) {
-			dev_err(dev->adapter.dev, "Receive overrun\n");
+			dev_err(&dev->adapter.dev, "Receive overrun\n");
 			dev->cmd_err |= OMAP_I2C_STAT_ROVR;
 		}
 		if (stat & OMAP_I2C_STAT_XUDF) {
-			dev_err(dev->adapter.dev, "Transmit underflow\n");
+			dev_err(&dev->adapter.dev, "Transmit underflow\n");
 			dev->cmd_err |= OMAP_I2C_STAT_XUDF;
 		}
 	}
@@ -639,7 +639,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adapter,
 	int ret = 0;
 
 
-	dev_dbg(adapter->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+	dev_dbg(&adapter->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
 		msg->addr, msg->len, msg->flags, stop);
 
 	if (msg->len == 0)
@@ -687,7 +687,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adapter,
 
 			/* Let the user know if i2c is in a bad state */
 			if (is_timeout(start, MSECOND)) {
-				dev_err(adapter->dev, "controller timed out "
+				dev_err(&adapter->dev, "controller timed out "
 				"waiting for start condition to finish\n");
 				return -ETIMEDOUT;
 			}
@@ -707,7 +707,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adapter,
 	while (ret){
 		ret = omap_i2c_isr(i2c_omap);
 		if (is_timeout(start, MSECOND)) {
-				dev_err(adapter->dev,
+				dev_err(&adapter->dev,
 				"timed out on polling for "
 				"open i2c message handling\n");
 				return -ETIMEDOUT;
@@ -835,7 +835,7 @@ i2c_omap_probe(struct device_d *pdev)
 
 	i2c_omap->adapter.master_xfer	= omap_i2c_xfer,
 	i2c_omap->adapter.nr = pdev->id;
-	i2c_omap->adapter.dev = pdev;
+	i2c_omap->adapter.dev.parent = pdev;
 
 	/* i2c device drivers may be active on return from add_adapter() */
 	r = i2c_add_numbered_adapter(&i2c_omap->adapter);
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index 27fd256..3af5c32 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -80,7 +80,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 	 */
 
 	for (ret = 0; ret < num; ret++) {
-		dev_dbg(adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+		dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
 			"len=%d\n", ret, (msgs[ret].flags & I2C_M_RD)
 			? 'R' : 'W', msgs[ret].addr, msgs[ret].len);
 	}
@@ -256,6 +256,9 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
 	client->adapter = adapter;
 	client->addr = chip->addr;
 
+	client->dev.parent = &adapter->dev;
+	dev_add_child(client->dev.parent, &client->dev);
+
 	status = register_device(&client->dev);
 
 #if 0
@@ -363,9 +366,21 @@ struct i2c_adapter *i2c_get_adapter(int busnum)
  */
 int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
 {
+	int ret;
+
 	if (i2c_get_adapter(adapter->nr))
 		return -EBUSY;
 
+	adapter->dev.id = adapter->nr;
+	strcpy(adapter->dev.name, "i2c");
+
+	if (adapter->dev.parent)
+		dev_add_child(adapter->dev.parent, &adapter->dev);
+
+	ret = register_device(&adapter->dev);
+	if (ret)
+		return ret;
+
 	list_add_tail(&adapter->list, &adapter_list);
 
 	/* populate children from any i2c device tables */
diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
index de2a7ea..5021dd4 100644
--- a/include/i2c/i2c.h
+++ b/include/i2c/i2c.h
@@ -66,7 +66,7 @@ struct i2c_msg {
  *
  */
 struct i2c_adapter {
-	struct device_d		*dev;	/* ptr to device */
+	struct device_d		dev;	/* ptr to device */
 	int			nr;	/* bus number */
 	int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
 	struct list_head	list;
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 2/4] i2c: add i2c algo bit support
  2012-11-02  9:36 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD
@ 2012-11-02  9:36   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36   ` [PATCH 3/4] i2c: add i2c-gpio support Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36   ` [PATCH 4/4] i2c: add versatile support Jean-Christophe PLAGNIOL-VILLARD
  2 siblings, 0 replies; 6+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-02  9:36 UTC (permalink / raw)
  To: barebox

This is needed for i2c-gpio support

Based on linux 3.7-rc2

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 drivers/i2c/Kconfig              |    1 +
 drivers/i2c/Makefile             |    2 +-
 drivers/i2c/algos/Kconfig        |    6 +
 drivers/i2c/algos/Makefile       |    5 +
 drivers/i2c/algos/i2c-algo-bit.c |  585 ++++++++++++++++++++++++++++++++++++++
 include/i2c/i2c-algo-bit.h       |   55 ++++
 include/i2c/i2c.h                |    2 +
 7 files changed, 655 insertions(+), 1 deletion(-)
 create mode 100644 drivers/i2c/algos/Kconfig
 create mode 100644 drivers/i2c/algos/Makefile
 create mode 100644 drivers/i2c/algos/i2c-algo-bit.c
 create mode 100644 include/i2c/i2c-algo-bit.h

diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index c2af818..038e2ee 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -3,6 +3,7 @@ menuconfig I2C
 
 if I2C
 
+source drivers/i2c/algos/Kconfig
 source drivers/i2c/busses/Kconfig
 
 endif
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 42e22c0..5ce0324 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_I2C) += i2c.o busses/
+obj-$(CONFIG_I2C) += i2c.o busses/ algos/
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
new file mode 100644
index 0000000..c74b148
--- /dev/null
+++ b/drivers/i2c/algos/Kconfig
@@ -0,0 +1,6 @@
+#
+# I2C algorithm drivers configuration
+#
+
+config I2C_ALGOBIT
+	bool
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
new file mode 100644
index 0000000..e0a0399
--- /dev/null
+++ b/drivers/i2c/algos/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the i2c algorithms
+#
+
+obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
new file mode 100644
index 0000000..37af27c
--- /dev/null
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -0,0 +1,585 @@
+/* -------------------------------------------------------------------------
+ * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
+ * -------------------------------------------------------------------------
+ *   Copyright (C) 1995-2000 Simon G. Vogl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.
+ * ------------------------------------------------------------------------- */
+
+/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
+   <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
+
+#include <common.h>
+#include <init.h>
+#include <errno.h>
+#include <clock.h>
+#include <i2c/i2c.h>
+#include <i2c/i2c-algo-bit.h>
+
+/* ----- global defines ----------------------------------------------- */
+
+#ifdef DEBUG
+#define bit_dbg(level, dev, format, args...) \
+	do { \
+		if (i2c_debug >= level) \
+			dev_dbg(dev, format, ##args); \
+	} while (0)
+#else
+#define bit_dbg(level, dev, format, args...) \
+	do {} while (0)
+#endif /* DEBUG */
+
+/* ----- global variables ---------------------------------------------	*/
+
+static int bit_test;	/* see if the line-setting functions work	*/
+
+#ifdef DEBUG
+static int i2c_debug = 1;
+#endif
+
+/* --- setting states on the bus with the right timing: ---------------	*/
+
+#define setsda(adap, val)	adap->setsda(adap->data, val)
+#define setscl(adap, val)	adap->setscl(adap->data, val)
+#define getsda(adap)		adap->getsda(adap->data)
+#define getscl(adap)		adap->getscl(adap->data)
+
+static inline void sdalo(struct i2c_algo_bit_data *adap)
+{
+	setsda(adap, 0);
+	udelay((adap->udelay + 1) / 2);
+}
+
+static inline void sdahi(struct i2c_algo_bit_data *adap)
+{
+	setsda(adap, 1);
+	udelay((adap->udelay + 1) / 2);
+}
+
+static inline void scllo(struct i2c_algo_bit_data *adap)
+{
+	setscl(adap, 0);
+	udelay(adap->udelay / 2);
+}
+
+/*
+ * Raise scl line, and do checking for delays. This is necessary for slower
+ * devices.
+ */
+static int sclhi(struct i2c_algo_bit_data *adap)
+{
+	uint64_t start;
+
+	setscl(adap, 1);
+
+	/* Not all adapters have scl sense line... */
+	if (!adap->getscl)
+		goto done;
+
+	start = get_time_ns();
+	while (!getscl(adap)) {
+		/* This hw knows how to read the clock line, so we wait
+		 * until it actually gets high.  This is safer as some
+		 * chips may hold it low ("clock stretching") while they
+		 * are processing data internally.
+		 */
+		if (is_timeout(start, adap->timeout_ms * MSECOND)) {
+			/* Test one last time, as we may have been preempted
+			 * between last check and timeout test.
+			 */
+			if (getscl(adap))
+				break;
+			return -ETIMEDOUT;
+		}
+	}
+#ifdef DEBUG
+	if (jiffies != start && i2c_debug >= 3)
+		pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
+			 "high\n", jiffies - start);
+#endif
+
+done:
+	udelay(adap->udelay);
+	return 0;
+}
+
+
+/* --- other auxiliary functions --------------------------------------	*/
+static void i2c_start(struct i2c_algo_bit_data *adap)
+{
+	/* assert: scl, sda are high */
+	setsda(adap, 0);
+	udelay(adap->udelay);
+	scllo(adap);
+}
+
+static void i2c_repstart(struct i2c_algo_bit_data *adap)
+{
+	/* assert: scl is low */
+	sdahi(adap);
+	sclhi(adap);
+	setsda(adap, 0);
+	udelay(adap->udelay);
+	scllo(adap);
+}
+
+
+static void i2c_stop(struct i2c_algo_bit_data *adap)
+{
+	/* assert: scl is low */
+	sdalo(adap);
+	sclhi(adap);
+	setsda(adap, 1);
+	udelay(adap->udelay);
+}
+
+
+
+/* send a byte without start cond., look for arbitration,
+   check ackn. from slave */
+/* returns:
+ * 1 if the device acknowledged
+ * 0 if the device did not ack
+ * -ETIMEDOUT if an error occurred (while raising the scl line)
+ */
+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
+{
+	int i;
+	int sb;
+	int ack;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	/* assert: scl is low */
+	for (i = 7; i >= 0; i--) {
+		sb = (c >> i) & 1;
+		setsda(adap, sb);
+		udelay((adap->udelay + 1) / 2);
+		if (sclhi(adap) < 0) { /* timed out */
+			bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+				"timeout at bit #%d\n", (int)c, i);
+			return -ETIMEDOUT;
+		}
+		/* FIXME do arbitration here:
+		 * if (sb && !getsda(adap)) -> ouch! Get out of here.
+		 *
+		 * Report a unique code, so higher level code can retry
+		 * the whole (combined) message and *NOT* issue STOP.
+		 */
+		scllo(adap);
+	}
+	sdahi(adap);
+	if (sclhi(adap) < 0) { /* timeout */
+		bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+			"timeout at ack\n", (int)c);
+		return -ETIMEDOUT;
+	}
+
+	/* read ack: SDA should be pulled down by slave, or it may
+	 * NAK (usually to report problems with the data we wrote).
+	 */
+	ack = !getsda(adap);    /* ack: sda is pulled low -> success */
+	bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+		ack ? "A" : "NA");
+
+	scllo(adap);
+	return ack;
+	/* assert: scl is low (sda undef) */
+}
+
+
+static int i2c_inb(struct i2c_adapter *i2c_adap)
+{
+	/* read byte via i2c port, without start/stop sequence	*/
+	/* acknowledge is sent in i2c_read.			*/
+	int i;
+	unsigned char indata = 0;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	/* assert: scl is low */
+	sdahi(adap);
+	for (i = 0; i < 8; i++) {
+		if (sclhi(adap) < 0) { /* timeout */
+			bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+				"#%d\n", 7 - i);
+			return -ETIMEDOUT;
+		}
+		indata *= 2;
+		if (getsda(adap))
+			indata |= 0x01;
+		setscl(adap, 0);
+		udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
+	}
+	/* assert: scl is low */
+	return indata;
+}
+
+/*
+ * Sanity check for the adapter hardware - check the reaction of
+ * the bus lines only if it seems to be idle.
+ */
+static int test_bus(struct i2c_adapter *i2c_adap)
+{
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+	struct device_d *dev = &i2c_adap->dev;
+	int scl, sda, ret;
+
+	if (adap->pre_xfer) {
+		ret = adap->pre_xfer(i2c_adap);
+		if (ret < 0)
+			return -ENODEV;
+	}
+
+	if (adap->getscl == NULL)
+		dev_info(dev, "Testing SDA only, SCL is not readable\n");
+
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl || !sda) {
+		dev_warn(dev, "bus seems to be busy (scl=%d, sda=%d)\n", scl, sda);
+		goto bailout;
+	}
+
+	sdalo(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (sda) {
+		dev_warn(dev, "SDA stuck high!\n");
+		goto bailout;
+	}
+	if (!scl) {
+		dev_warn(dev, "SCL unexpected low while pulling SDA low!\n");
+		goto bailout;
+	}
+
+	sdahi(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!sda) {
+		dev_warn(dev, "SDA stuck low!\n");
+		goto bailout;
+	}
+	if (!scl) {
+		dev_warn(dev, "SCL unexpected low while pulling SDA high!\n");
+		goto bailout;
+	}
+
+	scllo(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 0 : getscl(adap);
+	if (scl) {
+		dev_warn(dev, "SCL stuck high!\n");
+		goto bailout;
+	}
+	if (!sda) {
+		dev_warn(dev, "SDA unexpected low while pulling SCL low!\n");
+		goto bailout;
+	}
+
+	sclhi(adap);
+	sda = getsda(adap);
+	scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+	if (!scl) {
+		dev_warn(dev, "SCL stuck low!\n");
+		goto bailout;
+	}
+	if (!sda) {
+		dev_warn(dev, "SDA unexpected low while pulling SCL high!\n");
+		goto bailout;
+	}
+
+	if (adap->post_xfer)
+		adap->post_xfer(i2c_adap);
+
+	dev_info(dev, "Test OK\n");
+	return 0;
+bailout:
+	sdahi(adap);
+	sclhi(adap);
+
+	if (adap->post_xfer)
+		adap->post_xfer(i2c_adap);
+
+	return -ENODEV;
+}
+
+/* ----- Utility functions
+ */
+
+/* try_address tries to contact a chip for a number of
+ * times before it gives up.
+ * return values:
+ * 1 chip answered
+ * 0 chip did not answer
+ * -x transmission error
+ */
+static int try_address(struct i2c_adapter *i2c_adap,
+		       unsigned char addr, int retries)
+{
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+	int i, ret = 0;
+
+	for (i = 0; i <= retries; i++) {
+		ret = i2c_outb(i2c_adap, addr);
+		if (ret == 1 || i == retries)
+			break;
+		bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+		i2c_stop(adap);
+		udelay(adap->udelay);
+		bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+		i2c_start(adap);
+	}
+	if (i && ret)
+		bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
+			"0x%02x: %s\n", i + 1,
+			addr & 1 ? "read from" : "write to", addr >> 1,
+			ret == 1 ? "success" : "failed, timeout?");
+	return ret;
+}
+
+static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+	const unsigned char *temp = msg->buf;
+	int count = msg->len;
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+	int retval;
+	int wrcount = 0;
+
+	while (count > 0) {
+		retval = i2c_outb(i2c_adap, *temp);
+
+		/* OK/ACK; or ignored NAK */
+		if ((retval > 0) || (nak_ok && (retval == 0))) {
+			count--;
+			temp++;
+			wrcount++;
+
+		/* A slave NAKing the master means the slave didn't like
+		 * something about the data it saw.  For example, maybe
+		 * the SMBus PEC was wrong.
+		 */
+		} else if (retval == 0) {
+			dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n");
+			return -EIO;
+
+		/* Timeout; or (someday) lost arbitration
+		 *
+		 * FIXME Lost ARB implies retrying the transaction from
+		 * the first message, after the "winning" master issues
+		 * its STOP.  As a rule, upper layer code has no reason
+		 * to know or care about this ... it is *NOT* an error.
+		 */
+		} else {
+			dev_err(&i2c_adap->dev, "sendbytes: error %d\n",
+					retval);
+			return retval;
+		}
+	}
+	return wrcount;
+}
+
+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+	int inval;
+	int rdcount = 0;	/* counts bytes read */
+	unsigned char *temp = msg->buf;
+	int count = msg->len;
+
+	while (count > 0) {
+		inval = i2c_inb(i2c_adap);
+		if (inval >= 0) {
+			*temp = inval;
+			rdcount++;
+		} else {   /* read timed out */
+			break;
+		}
+
+		temp++;
+		count--;
+
+		bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
+			inval,
+			(flags & I2C_M_NO_RD_ACK)
+				? "(no ack/nak)"
+				: (count ? "A" : "NA"));
+	}
+	return rdcount;
+}
+
+/* doAddress initiates the transfer by generating the start condition (in
+ * try_address) and transmits the address in the necessary format to handle
+ * reads, writes as well as 10bit-addresses.
+ * returns:
+ *  0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set
+ * -x an error occurred (like: -ENXIO if the device did not answer, or
+ *	-ETIMEDOUT, for example if the lines are stuck...)
+ */
+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+{
+	unsigned short flags = msg->flags;
+	unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	unsigned char addr;
+	int ret, retries;
+
+	retries = nak_ok ? 0 : i2c_adap->retries;
+
+	if (flags & I2C_M_TEN) {
+		/* a ten bit address */
+		addr = 0xf0 | ((msg->addr >> 7) & 0x06);
+		bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
+		/* try extended address code...*/
+		ret = try_address(i2c_adap, addr, retries);
+		if ((ret != 1) && !nak_ok)  {
+			dev_err(&i2c_adap->dev,
+				"died at extended address code\n");
+			return -ENXIO;
+		}
+		/* the remaining 8 bit address */
+		ret = i2c_outb(i2c_adap, msg->addr & 0xff);
+		if ((ret != 1) && !nak_ok) {
+			/* the chip did not ack / xmission error occurred */
+			dev_err(&i2c_adap->dev, "died at 2nd address code\n");
+			return -ENXIO;
+		}
+		if (flags & I2C_M_RD) {
+			bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+				"start condition\n");
+			i2c_repstart(adap);
+			/* okay, now switch into reading mode */
+			addr |= 0x01;
+			ret = try_address(i2c_adap, addr, retries);
+			if ((ret != 1) && !nak_ok) {
+				dev_err(&i2c_adap->dev,
+					"died at repeated address code\n");
+				return -EIO;
+			}
+		}
+	} else {		/* normal 7bit address	*/
+		addr = msg->addr << 1;
+		if (flags & I2C_M_RD)
+			addr |= 1;
+		ret = try_address(i2c_adap, addr, retries);
+		if ((ret != 1) && !nak_ok)
+			return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int bit_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg msgs[], int num)
+{
+	struct i2c_msg *pmsg;
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+	int i, ret;
+	unsigned short nak_ok;
+
+	if (adap->pre_xfer) {
+		ret = adap->pre_xfer(i2c_adap);
+		if (ret < 0)
+			return ret;
+	}
+
+	bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+	i2c_start(adap);
+	for (i = 0; i < num; i++) {
+		pmsg = &msgs[i];
+		nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
+		if (i) {
+			bit_dbg(3, &i2c_adap->dev, "emitting "
+				"repeated start condition\n");
+			i2c_repstart(adap);
+		}
+		ret = bit_doAddress(i2c_adap, pmsg);
+		if ((ret != 0) && !nak_ok) {
+			bit_dbg(1, &i2c_adap->dev, "NAK from "
+				"device addr 0x%02x msg #%d\n",
+				msgs[i].addr, i);
+			goto bailout;
+		}
+		if (pmsg->flags & I2C_M_RD) {
+			/* read bytes into buffer*/
+			ret = readbytes(i2c_adap, pmsg);
+			if (ret >= 1)
+				bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
+					ret, ret == 1 ? "" : "s");
+			if (ret < pmsg->len) {
+				if (ret >= 0)
+					ret = -EIO;
+				goto bailout;
+			}
+		} else {
+			/* write bytes from buffer */
+			ret = sendbytes(i2c_adap, pmsg);
+			if (ret >= 1)
+				bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
+					ret, ret == 1 ? "" : "s");
+			if (ret < pmsg->len) {
+				if (ret >= 0)
+					ret = -EIO;
+				goto bailout;
+			}
+		}
+	}
+	ret = i;
+
+bailout:
+	bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+	i2c_stop(adap);
+
+	if (adap->post_xfer)
+		adap->post_xfer(i2c_adap);
+	return ret;
+}
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+static int __i2c_bit_add_bus(struct i2c_adapter *adap,
+			     int (*add_adapter)(struct i2c_adapter *))
+{
+	struct i2c_algo_bit_data *bit_adap = adap->algo_data;
+	int ret;
+
+	if (bit_test) {
+		ret = test_bus(adap);
+		if (bit_test >= 2 && ret < 0)
+			return -ENODEV;
+	}
+
+	/* register new adapter to i2c module... */
+	//adap->algo = &i2c_bit_algo;
+	adap->retries = 3;
+	adap->master_xfer = bit_xfer;
+
+	ret = add_adapter(adap);
+	if (ret < 0)
+		return ret;
+
+	/* Complain if SCL can't be read */
+	if (bit_adap->getscl == NULL) {
+		dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+		dev_warn(&adap->dev, "Bus may be unreliable\n");
+	}
+	return 0;
+}
+
+int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
+{
+	return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
+}
+EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
diff --git a/include/i2c/i2c-algo-bit.h b/include/i2c/i2c-algo-bit.h
new file mode 100644
index 0000000..1b72219
--- /dev/null
+++ b/include/i2c/i2c-algo-bit.h
@@ -0,0 +1,55 @@
+/* ------------------------------------------------------------------------- */
+/* i2c-algo-bit.h i2c driver algorithms for bit-shift adapters               */
+/* ------------------------------------------------------------------------- */
+/*   Copyright (C) 1995-99 Simon G. Vogl
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+    MA 02110-1301 USA.							     */
+/* ------------------------------------------------------------------------- */
+
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+   Frodo Looijaard <frodol@dds.nl> */
+
+#ifndef _LINUX_I2C_ALGO_BIT_H
+#define _LINUX_I2C_ALGO_BIT_H
+
+/* --- Defines for bit-adapters ---------------------------------------	*/
+/*
+ * This struct contains the hw-dependent functions of bit-style adapters to
+ * manipulate the line states, and to init any hw-specific features. This is
+ * only used if you have more than one hw-type of adapter running.
+ */
+struct i2c_algo_bit_data {
+	void *data;		/* private data for lowlevel routines */
+	void (*setsda) (void *data, int state);
+	void (*setscl) (void *data, int state);
+	int  (*getsda) (void *data);
+	int  (*getscl) (void *data);
+	int  (*pre_xfer)  (struct i2c_adapter *);
+	void (*post_xfer) (struct i2c_adapter *);
+
+	/* local settings */
+	int udelay;		/* half clock cycle time in us,
+				   minimum 2 us for fast-mode I2C,
+				   minimum 5 us for standard-mode I2C and SMBus,
+				   maximum 50 us for SMBus */
+	int timeout_ms;		/* in ms */
+};
+
+int i2c_bit_add_bus(struct i2c_adapter *);
+int i2c_bit_add_numbered_bus(struct i2c_adapter *);
+extern const struct i2c_algorithm i2c_bit_algo;
+
+#endif /* _LINUX_I2C_ALGO_BIT_H */
diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
index 5021dd4..b059119 100644
--- a/include/i2c/i2c.h
+++ b/include/i2c/i2c.h
@@ -70,6 +70,8 @@ struct i2c_adapter {
 	int			nr;	/* bus number */
 	int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
 	struct list_head	list;
+	int			retries;
+	void 			*algo_data;
 };
 
 
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 3/4] i2c: add i2c-gpio support
  2012-11-02  9:36 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36   ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD
@ 2012-11-02  9:36   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36   ` [PATCH 4/4] i2c: add versatile support Jean-Christophe PLAGNIOL-VILLARD
  2 siblings, 0 replies; 6+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-02  9:36 UTC (permalink / raw)
  To: barebox

Based on linux 3.7-rc2

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 drivers/i2c/busses/Kconfig    |    8 ++
 drivers/i2c/busses/Makefile   |    1 +
 drivers/i2c/busses/i2c-gpio.c |  177 +++++++++++++++++++++++++++++++++++++++++
 include/i2c/i2c-gpio.h        |   38 +++++++++
 4 files changed, 224 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-gpio.c
 create mode 100644 include/i2c/i2c-gpio.h

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 3f998ea..17e33cb 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -4,6 +4,14 @@
 
 menu "I2C Hardware Bus support"
 
+config I2C_GPIO
+	tristate "GPIO-based bitbanging I2C"
+	depends on GENERIC_GPIO
+	select I2C_ALGOBIT
+	help
+	  This is a very simple bitbanging I2C driver utilizing the
+	  arch-neutral GPIO API to control the SCL and SDA lines.
+
 config I2C_IMX
 	bool "MPC85xx/i.MX I2C Master driver"
 	depends on (ARCH_IMX && !ARCH_IMX1) || ARCH_MPC85XX
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index e4c5125..18c7c46 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -1,2 +1,3 @@
+obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_IMX) += i2c-imx.o
 obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 0000000..98ce2d5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,177 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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 <common.h>
+#include <driver.h>
+#include <i2c/i2c.h>
+#include <i2c/i2c-algo-bit.h>
+#include <i2c/i2c-gpio.h>
+#include <init.h>
+#include <gpio.h>
+
+struct i2c_gpio_private_data {
+	struct i2c_adapter adap;
+	struct i2c_algo_bit_data bit_data;
+	struct i2c_gpio_platform_data pdata;
+};
+
+/* Toggle SDA by changing the direction of the pin */
+static void i2c_gpio_setsda_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->sda_pin);
+	else
+		gpio_direction_output(pdata->sda_pin, 0);
+}
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->sda_pin, state);
+}
+
+/* Toggle SCL by changing the direction of the pin. */
+static void i2c_gpio_setscl_dir(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	if (state)
+		gpio_direction_input(pdata->scl_pin);
+	else
+		gpio_direction_output(pdata->scl_pin, 0);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	gpio_set_value(pdata->scl_pin, state);
+}
+
+static int i2c_gpio_getsda(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->sda_pin);
+}
+
+static int i2c_gpio_getscl(void *data)
+{
+	struct i2c_gpio_platform_data *pdata = data;
+
+	return gpio_get_value(pdata->scl_pin);
+}
+
+static int i2c_gpio_probe(struct device_d *dev)
+{
+	struct i2c_gpio_private_data *priv;
+	struct i2c_gpio_platform_data *pdata;
+	struct i2c_algo_bit_data *bit_data;
+	struct i2c_adapter *adap;
+	int ret;
+
+	priv = xzalloc(sizeof(*priv));
+
+	adap = &priv->adap;
+	bit_data = &priv->bit_data;
+	pdata = &priv->pdata;
+
+	if (!dev->platform_data)
+		return -ENXIO;
+	memcpy(pdata, dev->platform_data, sizeof(*pdata));
+
+	ret = gpio_request(pdata->sda_pin, "sda");
+	if (ret)
+		goto err_request_sda;
+	ret = gpio_request(pdata->scl_pin, "scl");
+	if (ret)
+		goto err_request_scl;
+
+	if (pdata->sda_is_open_drain) {
+		gpio_direction_output(pdata->sda_pin, 1);
+		bit_data->setsda = i2c_gpio_setsda_val;
+	} else {
+		gpio_direction_input(pdata->sda_pin);
+		bit_data->setsda = i2c_gpio_setsda_dir;
+	}
+
+	if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
+		gpio_direction_output(pdata->scl_pin, 1);
+		bit_data->setscl = i2c_gpio_setscl_val;
+	} else {
+		gpio_direction_input(pdata->scl_pin);
+		bit_data->setscl = i2c_gpio_setscl_dir;
+	}
+
+	if (!pdata->scl_is_output_only)
+		bit_data->getscl = i2c_gpio_getscl;
+	bit_data->getsda = i2c_gpio_getsda;
+
+	if (pdata->udelay)
+		bit_data->udelay = pdata->udelay;
+	else if (pdata->scl_is_output_only)
+		bit_data->udelay = 50;			/* 10 kHz */
+	else
+		bit_data->udelay = 5;			/* 100 kHz */
+
+	if (pdata->timeout_ms)
+		bit_data->timeout_ms = pdata->timeout_ms;
+	else
+		bit_data->timeout_ms = 100;		/* 100 ms */
+
+	bit_data->data = pdata;
+
+	adap->algo_data = bit_data;
+	adap->dev.parent = dev;
+
+	adap->nr = dev->id;
+	ret = i2c_bit_add_numbered_bus(adap);
+	if (ret)
+		goto err_add_bus;
+
+	dev_info(dev, "using pins %u (SDA) and %u (SCL%s)\n",
+		 pdata->sda_pin, pdata->scl_pin,
+		 pdata->scl_is_output_only
+		 ? ", no clock stretching" : "");
+
+	return 0;
+
+err_add_bus:
+	gpio_free(pdata->scl_pin);
+err_request_scl:
+	gpio_free(pdata->sda_pin);
+err_request_sda:
+	return ret;
+}
+
+static struct driver_d i2c_gpio_driver = {
+	.name	= "i2c-gpio",
+	.probe	= i2c_gpio_probe,
+};
+
+static int __init i2c_gpio_init(void)
+{
+	return platform_driver_register(&i2c_gpio_driver);
+}
+device_initcall(i2c_gpio_init);
diff --git a/include/i2c/i2c-gpio.h b/include/i2c/i2c-gpio.h
new file mode 100644
index 0000000..55feb82
--- /dev/null
+++ b/include/i2c/i2c-gpio.h
@@ -0,0 +1,38 @@
+/*
+ * i2c-gpio interface to platform code
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef _LINUX_I2C_GPIO_H
+#define _LINUX_I2C_GPIO_H
+
+/**
+ * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio
+ * @sda_pin: GPIO pin ID to use for SDA
+ * @scl_pin: GPIO pin ID to use for SCL
+ * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
+ * @timeout_ms: clock stretching timeout in ms. If the slave keeps
+ *	SCL low for longer than this, the transfer will time out.
+ * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin
+ *	isn't actively driven high when setting the output value high.
+ *	gpio_get_value() must return the actual pin state even if the
+ *	pin is configured as an output.
+ * @scl_is_open_drain: SCL is set up as open drain. Same requirements
+ *	as for sda_is_open_drain apply.
+ * @scl_is_output_only: SCL output drivers cannot be turned off.
+ */
+struct i2c_gpio_platform_data {
+	unsigned int	sda_pin;
+	unsigned int	scl_pin;
+	int		udelay;
+	int		timeout_ms;
+	unsigned int	sda_is_open_drain:1;
+	unsigned int	scl_is_open_drain:1;
+	unsigned int	scl_is_output_only:1;
+};
+
+#endif /* _LINUX_I2C_GPIO_H */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 4/4] i2c: add versatile support
  2012-11-02  9:36 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36   ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36   ` [PATCH 3/4] i2c: add i2c-gpio support Jean-Christophe PLAGNIOL-VILLARD
@ 2012-11-02  9:36   ` Jean-Christophe PLAGNIOL-VILLARD
  2 siblings, 0 replies; 6+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-02  9:36 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 drivers/i2c/busses/Kconfig         |    8 +++
 drivers/i2c/busses/Makefile        |    1 +
 drivers/i2c/busses/i2c-versatile.c |  112 ++++++++++++++++++++++++++++++++++++
 3 files changed, 121 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-versatile.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 17e33cb..68d9b46 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -20,4 +20,12 @@ config I2C_OMAP
 	bool "OMAP I2C Master driver"
 	depends on ARCH_OMAP
 
+config I2C_VERSATILE
+	tristate "ARM Versatile/Realview I2C bus support"
+	depends on ARCH_VERSATILE
+	select I2C_ALGOBIT
+	help
+	  Say yes if you want to support the I2C serial bus on ARMs Versatile
+	  range of platforms.
+
 endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 18c7c46..a30f9b8 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o
 obj-$(CONFIG_I2C_IMX) += i2c-imx.o
 obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
+obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o
diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c
new file mode 100644
index 0000000..7c99322
--- /dev/null
+++ b/drivers/i2c/busses/i2c-versatile.c
@@ -0,0 +1,112 @@
+/*
+ *  i2c-versatile.c
+ *
+ *  Copyright (C) 2006 ARM Ltd.
+ *  written by Russell King, Deep Blue Solutions 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 <common.h>
+#include <driver.h>
+#include <i2c/i2c.h>
+#include <i2c/i2c-algo-bit.h>
+#include <init.h>
+#include <malloc.h>
+#include <io.h>
+
+#define I2C_CONTROL	0x00
+#define I2C_CONTROLS	0x00
+#define I2C_CONTROLC	0x04
+#define SCL		(1 << 0)
+#define SDA		(1 << 1)
+
+struct i2c_versatile {
+	struct i2c_adapter	 adap;
+	struct i2c_algo_bit_data algo;
+	void __iomem		 *base;
+};
+
+static void i2c_versatile_setsda(void *data, int state)
+{
+	struct i2c_versatile *i2c = data;
+
+	writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static void i2c_versatile_setscl(void *data, int state)
+{
+	struct i2c_versatile *i2c = data;
+
+	writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
+}
+
+static int i2c_versatile_getsda(void *data)
+{
+	struct i2c_versatile *i2c = data;
+	return !!(readl(i2c->base + I2C_CONTROL) & SDA);
+}
+
+static int i2c_versatile_getscl(void *data)
+{
+	struct i2c_versatile *i2c = data;
+	return !!(readl(i2c->base + I2C_CONTROL) & SCL);
+}
+
+static struct i2c_algo_bit_data i2c_versatile_algo = {
+	.setsda	= i2c_versatile_setsda,
+	.setscl = i2c_versatile_setscl,
+	.getsda	= i2c_versatile_getsda,
+	.getscl = i2c_versatile_getscl,
+	.udelay	= 30,
+	.timeout_ms = 100,
+};
+
+static int i2c_versatile_probe(struct device_d *dev)
+{
+	struct i2c_versatile *i2c;
+	int ret;
+
+	i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
+	if (!i2c) {
+		ret = -ENOMEM;
+		goto err_release;
+	}
+
+	i2c->base = dev_request_mem_region(dev, 0);
+	if (!i2c->base) {
+		ret = -ENOMEM;
+		goto err_free;
+	}
+
+	writel(SCL | SDA, i2c->base + I2C_CONTROLS);
+
+	i2c->adap.algo_data = &i2c->algo;
+	i2c->adap.dev.parent = dev;
+	i2c->algo = i2c_versatile_algo;
+	i2c->algo.data = i2c;
+
+	i2c->adap.nr = dev->id;
+	ret = i2c_bit_add_numbered_bus(&i2c->adap);
+	if (ret >= 0) {
+		return 0;
+	}
+
+ err_free:
+	kfree(i2c);
+ err_release:
+	return ret;
+}
+
+static struct driver_d i2c_versatile_driver = {
+	.name	= "versatile-i2c",
+	.probe	= i2c_versatile_probe,
+};
+
+static int __init i2c_versatile_init(void)
+{
+	return platform_driver_register(&i2c_versatile_driver);
+}
+
+device_initcall(i2c_versatile_init);
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 0/4 v2] i2c: add algo-bit support with gpio and versatile support
  2012-11-02  9:27 [PATCH 0/4 v2] i2c: add algo-bit support with gpio and versatile support Jean-Christophe PLAGNIOL-VILLARD
  2012-11-02  9:36 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD
@ 2012-11-02 10:27 ` Sascha Hauer
  1 sibling, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2012-11-02 10:27 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

On Fri, Nov 02, 2012 at 10:27:18AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> HI,
> 
> 	v2: keep return -EBUSY if the adapter is already present
> 
> 	the foloing patch series add the i2c algo bit support with 2 drivers
> 	that use it
> 
> 	 - gpio
> 	 - versatile
> 
> 	 thie also create a device for i2c bus itself
> 
> 	 all the pedending branch are rebased on it
> 
> The following changes since commit 2d1ceaff2f905f4a2bd7e6c539e7dd3d8d8e9bef:
> 
>   uimage: Fix deleting of temporary file (2012-10-30 18:39:38 +0100)
> 
> are available in the git repository at:
> 
>   git://git.jcrosoft.org/barebox.git delivery/i2c
> 
> for you to fetch changes up to 5c90416b6ffb8d4ca7c4bc6aff92578b555cb965:
> 

Applied, thanks

Sascha

>   i2c: add versatile support (2012-11-02 02:17:04 +0800)
> 
> ----------------------------------------------------------------
> Jean-Christophe PLAGNIOL-VILLARD (4):
>       i2c: adapter: register it's own device
>       i2c: add i2c algo bit support
>       i2c: add i2c-gpio support
>       i2c: add versatile support
> 
>  drivers/i2c/Kconfig                |    1 +
>  drivers/i2c/Makefile               |    2 +-
>  drivers/i2c/algos/Kconfig          |    6 +++
>  drivers/i2c/algos/Makefile         |    5 ++
>  drivers/i2c/algos/i2c-algo-bit.c   |  585 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/i2c/busses/Kconfig         |   16 +++++++
>  drivers/i2c/busses/Makefile        |    2 +
>  drivers/i2c/busses/i2c-gpio.c      |  177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/i2c/busses/i2c-imx.c       |   20 ++++----
>  drivers/i2c/busses/i2c-omap.c      |   30 ++++++------
>  drivers/i2c/busses/i2c-versatile.c |  112 +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/i2c/i2c.c                  |   17 ++++++-
>  include/i2c/i2c-algo-bit.h         |   55 ++++++++++++++++++++++
>  include/i2c/i2c-gpio.h             |   38 +++++++++++++++
>  include/i2c/i2c.h                  |    4 +-
>  15 files changed, 1042 insertions(+), 28 deletions(-)
>  create mode 100644 drivers/i2c/algos/Kconfig
>  create mode 100644 drivers/i2c/algos/Makefile
>  create mode 100644 drivers/i2c/algos/i2c-algo-bit.c
>  create mode 100644 drivers/i2c/busses/i2c-gpio.c
>  create mode 100644 drivers/i2c/busses/i2c-versatile.c
>  create mode 100644 include/i2c/i2c-algo-bit.h
>  create mode 100644 include/i2c/i2c-gpio.h
> 
> Best Regards,
> J.
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2012-11-02 10:27 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-02  9:27 [PATCH 0/4 v2] i2c: add algo-bit support with gpio and versatile support Jean-Christophe PLAGNIOL-VILLARD
2012-11-02  9:36 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD
2012-11-02  9:36   ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD
2012-11-02  9:36   ` [PATCH 3/4] i2c: add i2c-gpio support Jean-Christophe PLAGNIOL-VILLARD
2012-11-02  9:36   ` [PATCH 4/4] i2c: add versatile support Jean-Christophe PLAGNIOL-VILLARD
2012-11-02 10:27 ` [PATCH 0/4 v2] i2c: add algo-bit support with gpio and " Sascha Hauer

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