* [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