* [PATCH 0/4] i2c: add algo-bit support with gpio and versatile support @ 2012-11-01 9:42 Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD 0 siblings, 1 reply; 8+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:42 UTC (permalink / raw) To: barebox HI, 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 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 d56fd9fa4f6872c2ce109fb25e8a48110750320b: i2c: add versatile support (2012-11-01 02:28:11 +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 | 18 ++++++-- include/i2c/i2c-algo-bit.h | 55 ++++++++++++++++++++++ include/i2c/i2c-gpio.h | 38 +++++++++++++++ include/i2c/i2c.h | 4 +- 15 files changed, 1041 insertions(+), 30 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] 8+ messages in thread
* [PATCH 1/4] i2c: adapter: register it's own device 2012-11-01 9:42 [PATCH 0/4] i2c: add algo-bit support with gpio and versatile support Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 ` Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD ` (3 more replies) 0 siblings, 4 replies; 8+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 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 | 18 +++++++++++++++--- include/i2c/i2c.h | 2 +- 4 files changed, 41 insertions(+), 29 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..2ca3aef 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,8 +366,17 @@ struct i2c_adapter *i2c_get_adapter(int busnum) */ int i2c_add_numbered_adapter(struct i2c_adapter *adapter) { - if (i2c_get_adapter(adapter->nr)) - return -EBUSY; + int ret; + + 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); 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] 8+ messages in thread
* [PATCH 2/4] i2c: add i2c algo bit support 2012-11-01 9:44 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 ` Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 3/4] i2c: add i2c-gpio support Jean-Christophe PLAGNIOL-VILLARD ` (2 subsequent siblings) 3 siblings, 0 replies; 8+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 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] 8+ messages in thread
* [PATCH 3/4] i2c: add i2c-gpio support 2012-11-01 9:44 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 ` Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 4/4] i2c: add versatile support Jean-Christophe PLAGNIOL-VILLARD 2012-11-02 7:29 ` [PATCH 1/4] i2c: adapter: register it's own device Sascha Hauer 3 siblings, 0 replies; 8+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 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] 8+ messages in thread
* [PATCH 4/4] i2c: add versatile support 2012-11-01 9:44 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 3/4] i2c: add i2c-gpio support Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 ` Jean-Christophe PLAGNIOL-VILLARD 2012-11-02 7:29 ` [PATCH 1/4] i2c: adapter: register it's own device Sascha Hauer 3 siblings, 0 replies; 8+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-01 9:44 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] 8+ messages in thread
* Re: [PATCH 1/4] i2c: adapter: register it's own device 2012-11-01 9:44 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD ` (2 preceding siblings ...) 2012-11-01 9:44 ` [PATCH 4/4] i2c: add versatile support Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-02 7:29 ` Sascha Hauer 2012-11-02 9:24 ` Jean-Christophe PLAGNIOL-VILLARD 3 siblings, 1 reply; 8+ messages in thread From: Sascha Hauer @ 2012-11-02 7:29 UTC (permalink / raw) To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox On Thu, Nov 01, 2012 at 10:44:49AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote: > 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 | 18 +++++++++++++++--- > include/i2c/i2c.h | 2 +- > 4 files changed, 41 insertions(+), 29 deletions(-) > > int i2c_add_numbered_adapter(struct i2c_adapter *adapter) > { > - if (i2c_get_adapter(adapter->nr)) > - return -EBUSY; If you remove this and instead depend on register_device bailing out later then you should change the error value register_device returns to -EBUSY. Currently it returns -EINVAL, -EBUSY seems much better here. > + int ret; > + > + adapter->dev.id = adapter->nr; > + strcpy(adapter->dev.name, "i2c"); > + > + if (adapter->dev.parent) > + dev_add_child(adapter->dev.parent, &adapter->dev); We should push the dev_add_child to the driver core. Doing this here means that... > + > + ret = register_device(&adapter->dev); > + if (ret) > + return ret; ... the parents child list will be corrupted when register_device fails. At least w1 and mdiobus have the same problem. But ok, we can fix that later. Sascha -- 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] 8+ messages in thread
* Re: [PATCH 1/4] i2c: adapter: register it's own device 2012-11-02 7:29 ` [PATCH 1/4] i2c: adapter: register it's own device Sascha Hauer @ 2012-11-02 9:24 ` Jean-Christophe PLAGNIOL-VILLARD 0 siblings, 0 replies; 8+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-11-02 9:24 UTC (permalink / raw) To: Sascha Hauer; +Cc: barebox On 08:29 Fri 02 Nov , Sascha Hauer wrote: > On Thu, Nov 01, 2012 at 10:44:49AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote: > > 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 | 18 +++++++++++++++--- > > include/i2c/i2c.h | 2 +- > > 4 files changed, 41 insertions(+), 29 deletions(-) > > > > int i2c_add_numbered_adapter(struct i2c_adapter *adapter) > > { > > - if (i2c_get_adapter(adapter->nr)) > > - return -EBUSY; > > If you remove this and instead depend on register_device bailing out > later then you should change the error value register_device returns > to -EBUSY. Currently it returns -EINVAL, -EBUSY seems much better here. > > > > + int ret; > > + > > + adapter->dev.id = adapter->nr; > > + strcpy(adapter->dev.name, "i2c"); > > + > > + if (adapter->dev.parent) > > + dev_add_child(adapter->dev.parent, &adapter->dev); > > We should push the dev_add_child to the driver core. Doing this here > means that... > > > + > > + ret = register_device(&adapter->dev); > > + if (ret) > > + return ret; > > ... the parents child list will be corrupted when register_device fails. > At least w1 and mdiobus have the same problem. But ok, we can fix that > later. ok I'll take a look after the whole sam9x5 stuff will merged Best Regards, J. _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 8+ messages in thread
* [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 0 siblings, 1 reply; 8+ 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] 8+ 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 0 siblings, 0 replies; 8+ 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] 8+ messages in thread
end of thread, other threads:[~2012-11-02 9:39 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-11-01 9:42 [PATCH 0/4] i2c: add algo-bit support with gpio and versatile support Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 1/4] i2c: adapter: register it's own device Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 2/4] i2c: add i2c algo bit support Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 3/4] i2c: add i2c-gpio support Jean-Christophe PLAGNIOL-VILLARD 2012-11-01 9:44 ` [PATCH 4/4] i2c: add versatile support Jean-Christophe PLAGNIOL-VILLARD 2012-11-02 7:29 ` [PATCH 1/4] i2c: adapter: register it's own device Sascha Hauer 2012-11-02 9:24 ` Jean-Christophe PLAGNIOL-VILLARD 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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox