summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@ti.com>2013-07-24 09:22:28 -0400
committerTom Rini <trini@ti.com>2013-07-24 09:50:24 -0400
commitc2120fbfbc4d1f6953228f86be8bdbf38bacfdab (patch)
tree14cd8ec9a0a61f7113149be38d79808cd5e955f8 /drivers
parente85427fd66a21b39145a47e67871a8863c0e5591 (diff)
parentecbd7e1ec7280d90d151a99691f74b892588cadd (diff)
downloadtalos-obmc-uboot-c2120fbfbc4d1f6953228f86be8bdbf38bacfdab.tar.gz
talos-obmc-uboot-c2120fbfbc4d1f6953228f86be8bdbf38bacfdab.zip
Merge branch 'master' of git://git.denx.de/u-boot-i2c
The sandburst-specific i2c drivers have been deleted, conflict was just over the SPDX conversion. Conflicts: board/sandburst/common/ppc440gx_i2c.c board/sandburst/common/ppc440gx_i2c.h Signed-off-by: Tom Rini <trini@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/Makefile10
-rw-r--r--drivers/i2c/fsl_i2c.c218
-rw-r--r--drivers/i2c/fti2c010.c369
-rw-r--r--drivers/i2c/fti2c010.h81
-rw-r--r--drivers/i2c/i2c_core.c414
-rw-r--r--drivers/i2c/mxc_i2c.c62
-rw-r--r--drivers/i2c/ppc4xx_i2c.c193
-rw-r--r--drivers/i2c/soft_i2c.c104
-rw-r--r--drivers/i2c/tegra_i2c.c118
9 files changed, 1236 insertions, 333 deletions
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 4ffbfdde3c..37ccbd1423 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -12,7 +12,6 @@ LIB := $(obj)libi2c.o
COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
-COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
@@ -21,15 +20,18 @@ COBJS-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o
COBJS-$(CONFIG_DRIVER_OMAP34XX_I2C) += omap24xx_i2c.o
COBJS-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o
-COBJS-$(CONFIG_PPC4XX_I2C) += ppc4xx_i2c.o
COBJS-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o
COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o
-COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o
-COBJS-$(CONFIG_TEGRA_I2C) += tegra_i2c.o
COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o
COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o
COBJS-$(CONFIG_SH_I2C) += sh_i2c.o
COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o
+COBJS-$(CONFIG_SYS_I2C) += i2c_core.o
+COBJS-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
+COBJS-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
+COBJS-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o
+COBJS-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
+COBJS-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
COBJS-$(CONFIG_ZYNQ_I2C) += zynq_i2c.o
COBJS := $(COBJS-y)
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index 5d7e010319..38455e1c66 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -1,6 +1,9 @@
/*
* Copyright 2006,2009 Freescale Semiconductor, Inc.
*
+ * 2012, Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ * Changes for multibus/multiadapter I2C support.
+ *
* 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.
@@ -17,12 +20,8 @@
*/
#include <common.h>
-
-#ifdef CONFIG_HARD_I2C
-
#include <command.h>
#include <i2c.h> /* Functional interface */
-
#include <asm/io.h>
#include <asm/fsl_i2c.h> /* HW definitions */
@@ -47,25 +46,10 @@
DECLARE_GLOBAL_DATA_PTR;
-/* Initialize the bus pointer to whatever one the SPD EEPROM is on.
- * Default is bus 0. This is necessary because the DDR initialization
- * runs from ROM, and we can't switch buses because we can't modify
- * the global variables.
- */
-#ifndef CONFIG_SYS_SPD_BUS_NUM
-#define CONFIG_SYS_SPD_BUS_NUM 0
-#endif
-static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = CONFIG_SYS_SPD_BUS_NUM;
-#if defined(CONFIG_I2C_MUX)
-static unsigned int i2c_bus_num_mux __attribute__ ((section ("data"))) = 0;
-#endif
-
-static unsigned int i2c_bus_speed[2] = {CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED};
-
static const struct fsl_i2c *i2c_dev[2] = {
- (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET),
-#ifdef CONFIG_SYS_I2C2_OFFSET
- (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C2_OFFSET)
+ (struct fsl_i2c *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C_OFFSET),
+#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
+ (struct fsl_i2c *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C2_OFFSET)
#endif
};
@@ -222,12 +206,9 @@ static unsigned int get_i2c_clock(int bus)
return gd->arch.i2c1_clk; /* I2C1 clock */
}
-void
-i2c_init(int speed, int slaveadd)
+static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
{
const struct fsl_i2c *dev;
- unsigned int temp;
- int bus_num, i;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/* Call board specific i2c bus reset routine before accessing the
@@ -236,23 +217,14 @@ i2c_init(int speed, int slaveadd)
*/
i2c_init_board();
#endif
-#ifdef CONFIG_SYS_I2C2_OFFSET
- bus_num = 2;
-#else
- bus_num = 1;
-#endif
- for (i = 0; i < bus_num; i++) {
- dev = i2c_dev[i];
-
- writeb(0, &dev->cr); /* stop I2C controller */
- udelay(5); /* let it shutdown in peace */
- temp = set_i2c_bus_speed(dev, get_i2c_clock(i), speed);
- if (gd->flags & GD_FLG_RELOC)
- i2c_bus_speed[i] = temp;
- writeb(slaveadd << 1, &dev->adr);/* write slave address */
- writeb(0x0, &dev->sr); /* clear status register */
- writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
- }
+ dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
+
+ writeb(0, &dev->cr); /* stop I2C controller */
+ udelay(5); /* let it shutdown in peace */
+ set_i2c_bus_speed(dev, get_i2c_clock(adap->hwadapnr), speed);
+ writeb(slaveadd << 1, &dev->adr);/* write slave address */
+ writeb(0x0, &dev->sr); /* clear status register */
+ writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */
#ifdef CONFIG_SYS_I2C_BOARD_LATE_INIT
/* Call board specific i2c bus reset routine AFTER the bus has been
@@ -265,12 +237,13 @@ i2c_init(int speed, int slaveadd)
}
static int
-i2c_wait4bus(void)
+i2c_wait4bus(struct i2c_adapter *adap)
{
+ struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
- while (readb(&i2c_dev[i2c_bus_num]->sr) & I2C_SR_MBB) {
+ while (readb(&dev->sr) & I2C_SR_MBB) {
if ((get_ticks() - timeval) > timeout)
return -1;
}
@@ -279,20 +252,21 @@ i2c_wait4bus(void)
}
static __inline__ int
-i2c_wait(int write)
+i2c_wait(struct i2c_adapter *adap, int write)
{
u32 csr;
unsigned long long timeval = get_ticks();
const unsigned long long timeout = usec2ticks(CONFIG_I2C_TIMEOUT);
+ struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
do {
- csr = readb(&i2c_dev[i2c_bus_num]->sr);
+ csr = readb(&dev->sr);
if (!(csr & I2C_SR_MIF))
continue;
/* Read again to allow register to stabilise */
- csr = readb(&i2c_dev[i2c_bus_num]->sr);
+ csr = readb(&dev->sr);
- writeb(0x0, &i2c_dev[i2c_bus_num]->sr);
+ writeb(0x0, &dev->sr);
if (csr & I2C_SR_MAL) {
debug("i2c_wait: MAL\n");
@@ -317,29 +291,32 @@ i2c_wait(int write)
}
static __inline__ int
-i2c_write_addr (u8 dev, u8 dir, int rsta)
+i2c_write_addr(struct i2c_adapter *adap, u8 dev, u8 dir, int rsta)
{
+ struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
+
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
| (rsta ? I2C_CR_RSTA : 0),
- &i2c_dev[i2c_bus_num]->cr);
+ &device->cr);
- writeb((dev << 1) | dir, &i2c_dev[i2c_bus_num]->dr);
+ writeb((dev << 1) | dir, &device->dr);
- if (i2c_wait(I2C_WRITE_BIT) < 0)
+ if (i2c_wait(adap, I2C_WRITE_BIT) < 0)
return 0;
return 1;
}
static __inline__ int
-__i2c_write(u8 *data, int length)
+__i2c_write(struct i2c_adapter *adap, u8 *data, int length)
{
+ struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
int i;
for (i = 0; i < length; i++) {
- writeb(data[i], &i2c_dev[i2c_bus_num]->dr);
+ writeb(data[i], &dev->dr);
- if (i2c_wait(I2C_WRITE_BIT) < 0)
+ if (i2c_wait(adap, I2C_WRITE_BIT) < 0)
break;
}
@@ -347,57 +324,60 @@ __i2c_write(u8 *data, int length)
}
static __inline__ int
-__i2c_read(u8 *data, int length)
+__i2c_read(struct i2c_adapter *adap, u8 *data, int length)
{
+ struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
int i;
writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0),
- &i2c_dev[i2c_bus_num]->cr);
+ &dev->cr);
/* dummy read */
- readb(&i2c_dev[i2c_bus_num]->dr);
+ readb(&dev->dr);
for (i = 0; i < length; i++) {
- if (i2c_wait(I2C_READ_BIT) < 0)
+ if (i2c_wait(adap, I2C_READ_BIT) < 0)
break;
/* Generate ack on last next to last byte */
if (i == length - 2)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK,
- &i2c_dev[i2c_bus_num]->cr);
+ &dev->cr);
/* Do not generate stop on last byte */
if (i == length - 1)
writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
- &i2c_dev[i2c_bus_num]->cr);
+ &dev->cr);
- data[i] = readb(&i2c_dev[i2c_bus_num]->dr);
+ data[i] = readb(&dev->dr);
}
return i;
}
-int
-i2c_read(u8 dev, uint addr, int alen, u8 *data, int length)
+static int
+fsl_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, int alen, u8 *data,
+ int length)
{
+ struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
int i = -1; /* signal error */
u8 *a = (u8*)&addr;
- if (i2c_wait4bus() < 0)
+ if (i2c_wait4bus(adap) < 0)
return -1;
if ((!length || alen > 0)
- && i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0
- && __i2c_write(&a[4 - alen], alen) == alen)
+ && i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0
+ && __i2c_write(adap, &a[4 - alen], alen) == alen)
i = 0; /* No error so far */
if (length &&
- i2c_write_addr(dev, I2C_READ_BIT, alen ? 1 : 0) != 0)
- i = __i2c_read(data, length);
+ i2c_write_addr(adap, dev, I2C_READ_BIT, alen ? 1 : 0) != 0)
+ i = __i2c_read(adap, data, length);
- writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);
+ writeb(I2C_CR_MEN, &device->cr);
- if (i2c_wait4bus()) /* Wait until STOP */
+ if (i2c_wait4bus(adap)) /* Wait until STOP */
debug("i2c_read: wait4bus timed out\n");
if (i == length)
@@ -406,20 +386,22 @@ i2c_read(u8 dev, uint addr, int alen, u8 *data, int length)
return -1;
}
-int
-i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
+static int
+fsl_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, int alen,
+ u8 *data, int length)
{
+ struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
int i = -1; /* signal error */
u8 *a = (u8*)&addr;
- if (i2c_wait4bus() >= 0
- && i2c_write_addr(dev, I2C_WRITE_BIT, 0) != 0
- && __i2c_write(&a[4 - alen], alen) == alen) {
- i = __i2c_write(data, length);
+ if (i2c_wait4bus(adap) >= 0 &&
+ i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 &&
+ __i2c_write(adap, &a[4 - alen], alen) == alen) {
+ i = __i2c_write(adap, data, length);
}
- writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr);
- if (i2c_wait4bus()) /* Wait until STOP */
+ writeb(I2C_CR_MEN, &device->cr);
+ if (i2c_wait4bus(adap)) /* Wait until STOP */
debug("i2c_write: wait4bus timed out\n");
if (i == length)
@@ -428,72 +410,42 @@ i2c_write(u8 dev, uint addr, int alen, u8 *data, int length)
return -1;
}
-int
-i2c_probe(uchar chip)
+static int
+fsl_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
+ struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
/* For unknow reason the controller will ACK when
* probing for a slave with the same address, so skip
* it.
*/
- if (chip == (readb(&i2c_dev[i2c_bus_num]->adr) >> 1))
- return -1;
-
- return i2c_read(chip, 0, 0, NULL, 0);
-}
-
-int i2c_set_bus_num(unsigned int bus)
-{
-#if defined(CONFIG_I2C_MUX)
- if (bus < CONFIG_SYS_MAX_I2C_BUS) {
- i2c_bus_num = bus;
- } else {
- int ret;
-
- ret = i2x_mux_select_mux(bus);
- if (ret)
- return ret;
- i2c_bus_num = 0;
- }
- i2c_bus_num_mux = bus;
-#else
-#ifdef CONFIG_SYS_I2C2_OFFSET
- if (bus > 1) {
-#else
- if (bus > 0) {
-#endif
+ if (chip == (readb(&dev->adr) >> 1))
return -1;
- }
- i2c_bus_num = bus;
-#endif
- return 0;
+ return fsl_i2c_read(adap, chip, 0, 0, NULL, 0);
}
-int i2c_set_bus_speed(unsigned int speed)
+static unsigned int fsl_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
{
- unsigned int i2c_clk = (i2c_bus_num == 1)
- ? gd->arch.i2c2_clk : gd->arch.i2c1_clk;
+ struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
- writeb(0, &i2c_dev[i2c_bus_num]->cr); /* stop controller */
- i2c_bus_speed[i2c_bus_num] =
- set_i2c_bus_speed(i2c_dev[i2c_bus_num], i2c_clk, speed);
- writeb(I2C_CR_MEN, &i2c_dev[i2c_bus_num]->cr); /* start controller */
+ writeb(0, &dev->cr); /* stop controller */
+ set_i2c_bus_speed(dev, get_i2c_clock(adap->hwadapnr), speed);
+ writeb(I2C_CR_MEN, &dev->cr); /* start controller */
return 0;
}
-unsigned int i2c_get_bus_num(void)
-{
-#if defined(CONFIG_I2C_MUX)
- return i2c_bus_num_mux;
-#else
- return i2c_bus_num;
+/*
+ * Register fsl i2c adapters
+ */
+U_BOOT_I2C_ADAP_COMPLETE(fsl_0, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
+ fsl_i2c_write, fsl_i2c_set_bus_speed,
+ CONFIG_SYS_FSL_I2C_SPEED, CONFIG_SYS_FSL_I2C_SLAVE,
+ 0)
+#ifdef CONFIG_SYS_FSL_I2C2_OFFSET
+U_BOOT_I2C_ADAP_COMPLETE(fsl_1, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
+ fsl_i2c_write, fsl_i2c_set_bus_speed,
+ CONFIG_SYS_FSL_I2C2_SPEED, CONFIG_SYS_FSL_I2C2_SLAVE,
+ 1)
#endif
-}
-
-unsigned int i2c_get_bus_speed(void)
-{
- return i2c_bus_speed[i2c_bus_num];
-}
-
-#endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
new file mode 100644
index 0000000000..24c4bb53fa
--- /dev/null
+++ b/drivers/i2c/fti2c010.c
@@ -0,0 +1,369 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+
+#include "fti2c010.h"
+
+#ifndef CONFIG_HARD_I2C
+#error "fti2c010: CONFIG_HARD_I2C is not defined"
+#endif
+
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED 50000
+#endif
+
+#ifndef CONFIG_FTI2C010_FREQ
+#define CONFIG_FTI2C010_FREQ clk_get_rate("I2C")
+#endif
+
+/* command timeout */
+#define CFG_CMD_TIMEOUT 10 /* ms */
+
+/* 7-bit chip address + 1-bit read/write */
+#define I2C_RD(chip) ((((chip) << 1) & 0xff) | 1)
+#define I2C_WR(chip) (((chip) << 1) & 0xff)
+
+struct fti2c010_chip {
+ void __iomem *regs;
+ uint bus;
+ uint speed;
+};
+
+static struct fti2c010_chip chip_list[] = {
+ {
+ .bus = 0,
+ .regs = (void __iomem *)CONFIG_FTI2C010_BASE,
+ },
+#ifdef CONFIG_I2C_MULTI_BUS
+# ifdef CONFIG_FTI2C010_BASE1
+ {
+ .bus = 1,
+ .regs = (void __iomem *)CONFIG_FTI2C010_BASE1,
+ },
+# endif
+# ifdef CONFIG_FTI2C010_BASE2
+ {
+ .bus = 2,
+ .regs = (void __iomem *)CONFIG_FTI2C010_BASE2,
+ },
+# endif
+# ifdef CONFIG_FTI2C010_BASE3
+ {
+ .bus = 3,
+ .regs = (void __iomem *)CONFIG_FTI2C010_BASE3,
+ },
+# endif
+#endif /* #ifdef CONFIG_I2C_MULTI_BUS */
+};
+
+static struct fti2c010_chip *curr = chip_list;
+
+static int fti2c010_wait(uint32_t mask)
+{
+ int ret = -1;
+ uint32_t stat, ts;
+ struct fti2c010_regs *regs = curr->regs;
+
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ stat = readl(&regs->sr);
+ if ((stat & mask) == mask) {
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * u-boot I2C API
+ */
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+ if (speed || !curr->speed)
+ i2c_set_bus_speed(speed);
+
+ /* if slave mode disabled */
+ if (!slaveaddr)
+ return;
+
+ /*
+ * TODO:
+ * Implement slave mode, but is it really necessary?
+ */
+}
+
+/*
+ * Probe the given I2C chip address. Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uchar chip)
+{
+ int ret;
+ struct fti2c010_regs *regs = curr->regs;
+
+ i2c_init(0, 0);
+
+ /* 1. Select slave device (7bits Address + 1bit R/W) */
+ writel(I2C_WR(chip), &regs->dr);
+ writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+ if (ret)
+ return ret;
+
+ /* 2. Select device register */
+ writel(0, &regs->dr);
+ writel(CR_ENABLE | CR_TBEN, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+
+ return ret;
+}
+
+/*
+ * Read/Write interface:
+ * chip: I2C chip address, range 0..127
+ * addr: Memory (register) address within the chip
+ * alen: Number of bytes to use for addr (typically 1, 2 for larger
+ * memories, 0 for register type devices with only one
+ * register)
+ * buffer: Where to read/write the data
+ * len: How many bytes to read/write
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+ int ret, pos;
+ uchar paddr[4];
+ struct fti2c010_regs *regs = curr->regs;
+
+ i2c_init(0, 0);
+
+ paddr[0] = (addr >> 0) & 0xFF;
+ paddr[1] = (addr >> 8) & 0xFF;
+ paddr[2] = (addr >> 16) & 0xFF;
+ paddr[3] = (addr >> 24) & 0xFF;
+
+ /*
+ * Phase A. Set register address
+ */
+
+ /* A.1 Select slave device (7bits Address + 1bit R/W) */
+ writel(I2C_WR(chip), &regs->dr);
+ writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+ if (ret)
+ return ret;
+
+ /* A.2 Select device register */
+ for (pos = 0; pos < alen; ++pos) {
+ uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+ writel(paddr[pos], &regs->dr);
+ writel(ctrl, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Phase B. Get register data
+ */
+
+ /* B.1 Select slave device (7bits Address + 1bit R/W) */
+ writel(I2C_RD(chip), &regs->dr);
+ writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+ if (ret)
+ return ret;
+
+ /* B.2 Get register data */
+ for (pos = 0; pos < len; ++pos) {
+ uint32_t ctrl = CR_ENABLE | CR_TBEN;
+ uint32_t stat = SR_DR;
+
+ if (pos == len - 1) {
+ ctrl |= CR_NAK | CR_STOP;
+ stat |= SR_ACK;
+ }
+ writel(ctrl, &regs->cr);
+ ret = fti2c010_wait(stat);
+ if (ret)
+ break;
+ buf[pos] = (uchar)(readl(&regs->dr) & 0xFF);
+ }
+
+ return ret;
+}
+
+/*
+ * Read/Write interface:
+ * chip: I2C chip address, range 0..127
+ * addr: Memory (register) address within the chip
+ * alen: Number of bytes to use for addr (typically 1, 2 for larger
+ * memories, 0 for register type devices with only one
+ * register)
+ * buffer: Where to read/write the data
+ * len: How many bytes to read/write
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+ int ret, pos;
+ uchar paddr[4];
+ struct fti2c010_regs *regs = curr->regs;
+
+ i2c_init(0, 0);
+
+ paddr[0] = (addr >> 0) & 0xFF;
+ paddr[1] = (addr >> 8) & 0xFF;
+ paddr[2] = (addr >> 16) & 0xFF;
+ paddr[3] = (addr >> 24) & 0xFF;
+
+ /*
+ * Phase A. Set register address
+ *
+ * A.1 Select slave device (7bits Address + 1bit R/W)
+ */
+ writel(I2C_WR(chip), &regs->dr);
+ writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+ if (ret)
+ return ret;
+
+ /* A.2 Select device register */
+ for (pos = 0; pos < alen; ++pos) {
+ uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+ writel(paddr[pos], &regs->dr);
+ writel(ctrl, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Phase B. Set register data
+ */
+ for (pos = 0; pos < len; ++pos) {
+ uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+ if (pos == len - 1)
+ ctrl |= CR_STOP;
+ writel(buf[pos], &regs->dr);
+ writel(ctrl, &regs->cr);
+ ret = fti2c010_wait(SR_DT);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Functions for setting the current I2C bus and its speed
+ */
+#ifdef CONFIG_I2C_MULTI_BUS
+
+/*
+ * i2c_set_bus_num:
+ *
+ * Change the active I2C bus. Subsequent read/write calls will
+ * go to this one.
+ *
+ * bus - bus index, zero based
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_set_bus_num(uint bus)
+{
+ if (bus >= ARRAY_SIZE(chip_list))
+ return -1;
+ curr = chip_list + bus;
+ i2c_init(0, 0);
+ return 0;
+}
+
+/*
+ * i2c_get_bus_num:
+ *
+ * Returns index of currently active I2C bus. Zero-based.
+ */
+
+uint i2c_get_bus_num(void)
+{
+ return curr->bus;
+}
+
+#endif /* #ifdef CONFIG_I2C_MULTI_BUS */
+
+/*
+ * i2c_set_bus_speed:
+ *
+ * Change the speed of the active I2C bus
+ *
+ * speed - bus speed in Hz
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_set_bus_speed(uint speed)
+{
+ struct fti2c010_regs *regs = curr->regs;
+ uint clk = CONFIG_FTI2C010_FREQ;
+ uint gsr = 0, tsr = 32;
+ uint spd, div;
+
+ if (!speed)
+ speed = CONFIG_SYS_I2C_SPEED;
+
+ for (div = 0; div < 0x3ffff; ++div) {
+ /* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
+ spd = clk / (2 * (div + 2) + gsr);
+ if (spd <= speed)
+ break;
+ }
+
+ if (curr->speed == spd)
+ return 0;
+
+ writel(CR_I2CRST, &regs->cr);
+ mdelay(100);
+ if (readl(&regs->cr) & CR_I2CRST) {
+ printf("fti2c010: reset timeout\n");
+ return -1;
+ }
+
+ curr->speed = spd;
+
+ writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), &regs->tgsr);
+ writel(CDR_DIV(div), &regs->cdr);
+
+ return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ * Returns speed of currently active I2C bus in Hz
+ */
+
+uint i2c_get_bus_speed(void)
+{
+ return curr->speed;
+}
diff --git a/drivers/i2c/fti2c010.h b/drivers/i2c/fti2c010.h
new file mode 100644
index 0000000000..18aec2c976
--- /dev/null
+++ b/drivers/i2c/fti2c010.h
@@ -0,0 +1,81 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTI2C010_H
+#define __FTI2C010_H
+
+/*
+ * FTI2C010 registers
+ */
+struct fti2c010_regs {
+ uint32_t cr; /* 0x00: control register */
+ uint32_t sr; /* 0x04: status register */
+ uint32_t cdr; /* 0x08: clock division register */
+ uint32_t dr; /* 0x0c: data register */
+ uint32_t sar; /* 0x10: slave address register */
+ uint32_t tgsr;/* 0x14: time & glitch suppression register */
+ uint32_t bmr; /* 0x18: bus monitor register */
+ uint32_t rsvd[5];
+ uint32_t revr;/* 0x30: revision register */
+};
+
+/*
+ * control register
+ */
+#define CR_ALIRQ 0x2000 /* arbitration lost interrupt (master) */
+#define CR_SAMIRQ 0x1000 /* slave address match interrupt (slave) */
+#define CR_STOPIRQ 0x800 /* stop condition interrupt (slave) */
+#define CR_NAKRIRQ 0x400 /* NACK response interrupt (master) */
+#define CR_DRIRQ 0x200 /* rx interrupt (both) */
+#define CR_DTIRQ 0x100 /* tx interrupt (both) */
+#define CR_TBEN 0x80 /* tx enable (both) */
+#define CR_NAK 0x40 /* NACK (both) */
+#define CR_STOP 0x20 /* stop (master) */
+#define CR_START 0x10 /* start (master) */
+#define CR_GCEN 0x8 /* general call support (slave) */
+#define CR_SCLEN 0x4 /* enable clock out (master) */
+#define CR_I2CEN 0x2 /* enable I2C (both) */
+#define CR_I2CRST 0x1 /* reset I2C (both) */
+#define CR_ENABLE \
+ (CR_ALIRQ | CR_NAKRIRQ | CR_DRIRQ | CR_DTIRQ | CR_SCLEN | CR_I2CEN)
+
+/*
+ * status register
+ */
+#define SR_CLRAL 0x400 /* clear arbitration lost */
+#define SR_CLRGC 0x200 /* clear general call */
+#define SR_CLRSAM 0x100 /* clear slave address match */
+#define SR_CLRSTOP 0x80 /* clear stop */
+#define SR_CLRNAKR 0x40 /* clear NACK respond */
+#define SR_DR 0x20 /* rx ready */
+#define SR_DT 0x10 /* tx done */
+#define SR_BB 0x8 /* bus busy */
+#define SR_BUSY 0x4 /* chip busy */
+#define SR_ACK 0x2 /* ACK/NACK received */
+#define SR_RW 0x1 /* set when master-rx or slave-tx mode */
+
+/*
+ * clock division register
+ */
+#define CDR_DIV(n) ((n) & 0x3ffff)
+
+/*
+ * time & glitch suppression register
+ */
+#define TGSR_GSR(n) (((n) & 0x7) << 10)
+#define TGSR_TSR(n) ((n) & 0x3ff)
+
+/*
+ * bus monitor register
+ */
+#define BMR_SCL 0x2 /* SCL is pull-up */
+#define BMR_SDA 0x1 /* SDA is pull-up */
+
+#endif /* __FTI2C010_H */
diff --git a/drivers/i2c/i2c_core.c b/drivers/i2c/i2c_core.c
new file mode 100644
index 0000000000..3c01893c9c
--- /dev/null
+++ b/drivers/i2c/i2c_core.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * (C) Copyright 2012
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Multibus/multiadapter I2C core functions (wrappers)
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <common.h>
+#include <i2c.h>
+
+struct i2c_adapter *i2c_get_adapter(int index)
+{
+ struct i2c_adapter *i2c_adap_p = ll_entry_start(struct i2c_adapter,
+ i2c);
+ int max = ll_entry_count(struct i2c_adapter, i2c);
+ int i;
+
+ if (index >= max) {
+ printf("Error, wrong i2c adapter %d max %d possible\n",
+ index, max);
+ return i2c_adap_p;
+ }
+ if (index == 0)
+ return i2c_adap_p;
+
+ for (i = 0; i < index; i++)
+ i2c_adap_p++;
+
+ return i2c_adap_p;
+}
+
+#if !defined(CONFIG_SYS_I2C_DIRECT_BUS)
+struct i2c_bus_hose i2c_bus[CONFIG_SYS_NUM_I2C_BUSES] =
+ CONFIG_SYS_I2C_BUSES;
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void i2c_reloc_fixup(void)
+{
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ struct i2c_adapter *i2c_adap_p = ll_entry_start(struct i2c_adapter,
+ i2c);
+ struct i2c_adapter *tmp = i2c_adap_p;
+ int max = ll_entry_count(struct i2c_adapter, i2c);
+ int i;
+ unsigned long addr;
+
+ if (gd->reloc_off == 0)
+ return;
+
+ for (i = 0; i < max; i++) {
+ /* adapter itself */
+ addr = (unsigned long)i2c_adap_p;
+ addr += gd->reloc_off;
+ i2c_adap_p = (struct i2c_adapter *)addr;
+ /* i2c_init() */
+ addr = (unsigned long)i2c_adap_p->init;
+ addr += gd->reloc_off;
+ i2c_adap_p->init = (void (*)(int, int))addr;
+ /* i2c_probe() */
+ addr = (unsigned long)i2c_adap_p->probe;
+ addr += gd->reloc_off;
+ i2c_adap_p->probe = (int (*)(uint8_t))addr;
+ /* i2c_read() */
+ addr = (unsigned long)i2c_adap_p->read;
+ addr += gd->reloc_off;
+ i2c_adap_p->read = (int (*)(uint8_t, uint, int, uint8_t *,
+ int))addr;
+ /* i2c_write() */
+ addr = (unsigned long)i2c_adap_p->write;
+ addr += gd->reloc_off;
+ i2c_adap_p->write = (int (*)(uint8_t, uint, int, uint8_t *,
+ int))addr;
+ /* i2c_set_bus_speed() */
+ addr = (unsigned long)i2c_adap_p->set_bus_speed;
+ addr += gd->reloc_off;
+ i2c_adap_p->set_bus_speed = (uint (*)(uint))addr;
+ /* name */
+ addr = (unsigned long)i2c_adap_p->name;
+ addr += gd->reloc_off;
+ i2c_adap_p->name = (char *)addr;
+ tmp++;
+ i2c_adap_p = tmp;
+ }
+#endif
+}
+
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+/*
+ * i2c_mux_set()
+ * -------------
+ *
+ * This turns on the given channel on I2C multiplexer chip connected to
+ * a given I2C adapter directly or via other multiplexers. In the latter
+ * case the entire multiplexer chain must be initialized first starting
+ * with the one connected directly to the adapter. When disabling a chain
+ * muxes must be programmed in reverse order, starting with the one
+ * farthest from the adapter.
+ *
+ * mux_id is the multiplexer chip type from defined in i2c.h. So far only
+ * NXP (Philips) PCA954x multiplexers are supported. Switches are NOT
+ * supported (anybody uses them?)
+ */
+
+static int i2c_mux_set(struct i2c_adapter *adap, int mux_id, int chip,
+ int channel)
+{
+ uint8_t buf;
+ int ret;
+
+ /* channel < 0 - turn off the mux */
+ if (channel < 0) {
+ buf = 0;
+ ret = adap->write(adap, chip, 0, 0, &buf, 1);
+ if (ret)
+ printf("%s: Could not turn off the mux.\n", __func__);
+ return ret;
+ }
+
+ switch (mux_id) {
+ case I2C_MUX_PCA9540_ID:
+ case I2C_MUX_PCA9542_ID:
+ if (channel > 1)
+ return -1;
+ buf = (uint8_t)((channel & 0x01) | (1 << 2));
+ break;
+ case I2C_MUX_PCA9544_ID:
+ if (channel > 3)
+ return -1;
+ buf = (uint8_t)((channel & 0x03) | (1 << 2));
+ break;
+ case I2C_MUX_PCA9547_ID:
+ if (channel > 7)
+ return -1;
+ buf = (uint8_t)((channel & 0x07) | (1 << 3));
+ break;
+ default:
+ printf("%s: wrong mux id: %d\n", __func__, mux_id);
+ return -1;
+ }
+
+ ret = adap->write(adap, chip, 0, 0, &buf, 1);
+ if (ret)
+ printf("%s: could not set mux: id: %d chip: %x channel: %d\n",
+ __func__, mux_id, chip, channel);
+ return ret;
+}
+
+static int i2c_mux_set_all(void)
+{
+ struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
+ int i;
+
+ /* Connect requested bus if behind muxes */
+ if (i2c_bus_tmp->next_hop[0].chip != 0) {
+ /* Set all muxes along the path to that bus */
+ for (i = 0; i < CONFIG_SYS_I2C_MAX_HOPS; i++) {
+ int ret;
+
+ if (i2c_bus_tmp->next_hop[i].chip == 0)
+ break;
+
+ ret = i2c_mux_set(I2C_ADAP,
+ i2c_bus_tmp->next_hop[i].mux.id,
+ i2c_bus_tmp->next_hop[i].chip,
+ i2c_bus_tmp->next_hop[i].channel);
+ if (ret != 0)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int i2c_mux_disconnet_all(void)
+{
+ struct i2c_bus_hose *i2c_bus_tmp = &i2c_bus[I2C_BUS];
+ int i;
+ uint8_t buf;
+
+ if (I2C_ADAP->init_done == 0)
+ return 0;
+
+ /* Disconnect current bus (turn off muxes if any) */
+ if ((i2c_bus_tmp->next_hop[0].chip != 0) &&
+ (I2C_ADAP->init_done != 0)) {
+ i = CONFIG_SYS_I2C_MAX_HOPS;
+ do {
+ uint8_t chip;
+ int ret;
+
+ chip = i2c_bus_tmp->next_hop[--i].chip;
+ if (chip == 0)
+ continue;
+
+ ret = I2C_ADAP->write(I2C_ADAP, chip, 0, 0, &buf, 1);
+ if (ret != 0) {
+ printf("i2c: mux diconnect error\n");
+ return ret;
+ }
+ } while (i > 0);
+ }
+
+ return 0;
+}
+#endif
+
+/*
+ * i2c_init_bus():
+ * ---------------
+ *
+ * Initializes one bus. Will initialize the parent adapter. No current bus
+ * changes, no mux (if any) setup.
+ */
+static void i2c_init_bus(unsigned int bus_no, int speed, int slaveaddr)
+{
+ if (bus_no >= CONFIG_SYS_NUM_I2C_BUSES)
+ return;
+
+ I2C_ADAP->init(I2C_ADAP, speed, slaveaddr);
+
+ if (gd->flags & GD_FLG_RELOC) {
+ I2C_ADAP->init_done = 1;
+ I2C_ADAP->speed = speed;
+ I2C_ADAP->slaveaddr = slaveaddr;
+ }
+}
+
+/* implement possible board specific board init */
+static void __def_i2c_init_board(void)
+{
+}
+void i2c_init_board(void)
+ __attribute__((weak, alias("__def_i2c_init_board")));
+
+/*
+ * i2c_init_all():
+ *
+ * not longer needed, will deleted. Actual init the SPD_BUS
+ * for compatibility.
+ * i2c_adap[] must be initialized beforehead with function pointers and
+ * data, including speed and slaveaddr.
+ */
+void i2c_init_all(void)
+{
+ i2c_init_board();
+ i2c_set_bus_num(CONFIG_SYS_SPD_BUS_NUM);
+ return;
+}
+
+/*
+ * i2c_get_bus_num():
+ * ------------------
+ *
+ * Returns index of currently active I2C bus. Zero-based.
+ */
+unsigned int i2c_get_bus_num(void)
+{
+ return gd->cur_i2c_bus;
+}
+
+/*
+ * i2c_set_bus_num():
+ * ------------------
+ *
+ * Change the active I2C bus. Subsequent read/write calls will
+ * go to this one. Sets all of the muxes in a proper condition
+ * if that bus is behind muxes.
+ * If previously selected bus is behind the muxes turns off all the
+ * muxes along the path to that bus.
+ *
+ * bus - bus index, zero based
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_set_bus_num(unsigned int bus)
+{
+ int max = ll_entry_count(struct i2c_adapter, i2c);
+
+ if (I2C_ADAPTER(bus) >= max) {
+ printf("Error, wrong i2c adapter %d max %d possible\n",
+ I2C_ADAPTER(bus), max);
+ return -2;
+ }
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+ if (bus >= CONFIG_SYS_NUM_I2C_BUSES)
+ return -1;
+#endif
+
+ if ((bus == I2C_BUS) && (I2C_ADAP->init_done > 0))
+ return 0;
+
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+ i2c_mux_disconnet_all();
+#endif
+
+ gd->cur_i2c_bus = bus;
+ if (I2C_ADAP->init_done == 0)
+ i2c_init_bus(bus, I2C_ADAP->speed, I2C_ADAP->slaveaddr);
+
+#ifndef CONFIG_SYS_I2C_DIRECT_BUS
+ i2c_mux_set_all();
+#endif
+ return 0;
+}
+
+/*
+ * Probe the given I2C chip address. Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uint8_t chip)
+{
+ return I2C_ADAP->probe(I2C_ADAP, chip);
+}
+
+/*
+ * Read/Write interface:
+ * chip: I2C chip address, range 0..127
+ * addr: Memory (register) address within the chip
+ * alen: Number of bytes to use for addr (typically 1, 2 for larger
+ * memories, 0 for register type devices with only one
+ * register)
+ * buffer: Where to read/write the data
+ * len: How many bytes to read/write
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uint8_t chip, unsigned int addr, int alen,
+ uint8_t *buffer, int len)
+{
+ return I2C_ADAP->read(I2C_ADAP, chip, addr, alen, buffer, len);
+}
+
+int i2c_write(uint8_t chip, unsigned int addr, int alen,
+ uint8_t *buffer, int len)
+{
+ return I2C_ADAP->write(I2C_ADAP, chip, addr, alen, buffer, len);
+}
+
+unsigned int i2c_set_bus_speed(unsigned int speed)
+{
+ unsigned int ret;
+
+ if (I2C_ADAP->set_bus_speed == NULL)
+ return 0;
+ ret = I2C_ADAP->set_bus_speed(I2C_ADAP, speed);
+ if (gd->flags & GD_FLG_RELOC)
+ I2C_ADAP->speed = ret;
+
+ return ret;
+}
+
+unsigned int i2c_get_bus_speed(void)
+{
+ struct i2c_adapter *cur = I2C_ADAP;
+ return cur->speed;
+}
+
+uint8_t i2c_reg_read(uint8_t addr, uint8_t reg)
+{
+ uint8_t buf;
+
+#ifdef CONFIG_8xx
+ /* MPC8xx needs this. Maybe one day we can get rid of it. */
+ /* maybe it is now the time for it ... */
+ i2c_set_bus_num(i2c_get_bus_num());
+#endif
+ i2c_read(addr, reg, 1, &buf, 1);
+
+#ifdef DEBUG
+ printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
+ __func__, i2c_get_bus_num(), addr, reg, buf);
+#endif
+
+ return buf;
+}
+
+void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val)
+{
+#ifdef CONFIG_8xx
+ /* MPC8xx needs this. Maybe one day we can get rid of it. */
+ /* maybe it is now the time for it ... */
+ i2c_set_bus_num(i2c_get_bus_num());
+#endif
+
+#ifdef DEBUG
+ printf("%s: bus=%d addr=0x%02x, reg=0x%02x, val=0x%02x\n",
+ __func__, i2c_get_bus_num(), addr, reg, val);
+#endif
+
+ i2c_write(addr, reg, 1, &val, 1);
+}
+
+void __i2c_init(int speed, int slaveaddr)
+{
+ i2c_init_bus(i2c_get_bus_num(), speed, slaveaddr);
+}
+void i2c_init(int speed, int slaveaddr)
+ __attribute__((weak, alias("__i2c_init")));
diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c
index 3eadbac0cd..06ba4e39f1 100644
--- a/drivers/i2c/mxc_i2c.c
+++ b/drivers/i2c/mxc_i2c.c
@@ -22,6 +22,15 @@
#include <i2c.h>
#include <watchdog.h>
+#ifdef I2C_QUIRK_REG
+struct mxc_i2c_regs {
+ uint8_t iadr;
+ uint8_t ifdr;
+ uint8_t i2cr;
+ uint8_t i2sr;
+ uint8_t i2dr;
+};
+#else
struct mxc_i2c_regs {
uint32_t iadr;
uint32_t ifdr;
@@ -29,8 +38,8 @@ struct mxc_i2c_regs {
uint32_t i2sr;
uint32_t i2dr;
};
+#endif
-#define I2CR_IEN (1 << 7)
#define I2CR_IIEN (1 << 6)
#define I2CR_MSTA (1 << 5)
#define I2CR_MTX (1 << 4)
@@ -43,10 +52,39 @@ struct mxc_i2c_regs {
#define I2SR_IIF (1 << 1)
#define I2SR_RX_NO_AK (1 << 0)
+#ifdef I2C_QUIRK_REG
+#define I2CR_IEN (0 << 7)
+#define I2CR_IDIS (1 << 7)
+#define I2SR_IIF_CLEAR (1 << 1)
+#else
+#define I2CR_IEN (1 << 7)
+#define I2CR_IDIS (0 << 7)
+#define I2SR_IIF_CLEAR (0 << 1)
+#endif
+
#if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE)
#error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver"
#endif
+#ifdef I2C_QUIRK_REG
+static u16 i2c_clk_div[60][2] = {
+ { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 },
+ { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 },
+ { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D },
+ { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 },
+ { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 },
+ { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 },
+ { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 },
+ { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 },
+ { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 },
+ { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B },
+ { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 },
+ { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 },
+ { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B },
+ { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A },
+ { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E },
+};
+#else
static u16 i2c_clk_div[50][2] = {
{ 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
{ 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
@@ -62,6 +100,7 @@ static u16 i2c_clk_div[50][2] = {
{ 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
{ 3072, 0x1E }, { 3840, 0x1F }
};
+#endif
/*
* Calculate and set proper clock divider
@@ -109,7 +148,7 @@ static int bus_i2c_set_bus_speed(void *base, int speed)
writeb(idx, &i2c_regs->ifdr);
/* Reset module */
- writeb(0, &i2c_regs->i2cr);
+ writeb(I2CR_IDIS, &i2c_regs->i2cr);
writeb(0, &i2c_regs->i2sr);
return 0;
}
@@ -141,7 +180,11 @@ static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state)
for (;;) {
sr = readb(&i2c_regs->i2sr);
if (sr & I2SR_IAL) {
+#ifdef I2C_QUIRK_REG
+ writeb(sr | I2SR_IAL, &i2c_regs->i2sr);
+#else
writeb(sr & ~I2SR_IAL, &i2c_regs->i2sr);
+#endif
printf("%s: Arbitration lost sr=%x cr=%x state=%x\n",
__func__, sr, readb(&i2c_regs->i2cr), state);
return -ERESTART;
@@ -162,7 +205,7 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte)
{
int ret;
- writeb(0, &i2c_regs->i2sr);
+ writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
writeb(byte, &i2c_regs->i2dr);
ret = wait_for_sr_state(i2c_regs, ST_IIF);
if (ret < 0)
@@ -198,14 +241,18 @@ static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs,
int ret;
/* Enable I2C controller */
+#ifdef I2C_QUIRK_REG
+ if (readb(&i2c_regs->i2cr) & I2CR_IDIS) {
+#else
if (!(readb(&i2c_regs->i2cr) & I2CR_IEN)) {
+#endif
writeb(I2CR_IEN, &i2c_regs->i2cr);
/* Wait for controller to be stable */
udelay(50);
}
if (readb(&i2c_regs->iadr) == (chip << 1))
writeb((chip << 1) ^ 2, &i2c_regs->iadr);
- writeb(0, &i2c_regs->i2sr);
+ writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE);
if (ret < 0)
return ret;
@@ -253,7 +300,8 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs,
printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip,
retry);
if (ret != -ERESTART)
- writeb(0, &i2c_regs->i2cr); /* Disable controller */
+ /* Disable controller */
+ writeb(I2CR_IDIS, &i2c_regs->i2cr);
udelay(100);
if (i2c_idle_bus(i2c_regs) < 0)
break;
@@ -293,7 +341,7 @@ int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf,
if (len == 1)
temp |= I2CR_TX_NO_AK;
writeb(temp, &i2c_regs->i2cr);
- writeb(0, &i2c_regs->i2sr);
+ writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
readb(&i2c_regs->i2dr); /* dummy read to clear ICF */
/* read data */
@@ -315,7 +363,7 @@ int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf,
temp |= I2CR_TX_NO_AK;
writeb(temp, &i2c_regs->i2cr);
}
- writeb(0, &i2c_regs->i2sr);
+ writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr);
buf[i] = readb(&i2c_regs->i2dr);
}
i2c_imx_stop(i2c_regs);
diff --git a/drivers/i2c/ppc4xx_i2c.c b/drivers/i2c/ppc4xx_i2c.c
index 52929ebc4e..e7a15ba644 100644
--- a/drivers/i2c/ppc4xx_i2c.c
+++ b/drivers/i2c/ppc4xx_i2c.c
@@ -16,27 +16,29 @@
#include <i2c.h>
#include <asm/io.h>
-#ifdef CONFIG_HARD_I2C
-
DECLARE_GLOBAL_DATA_PTR;
-#if defined(CONFIG_I2C_MULTI_BUS)
-/*
- * Initialize the bus pointer to whatever one the SPD EEPROM is on.
- * Default is bus 0. This is necessary because the DDR initialization
- * runs from ROM, and we can't switch buses because we can't modify
- * the global variables.
- */
-#ifndef CONFIG_SYS_SPD_BUS_NUM
-#define CONFIG_SYS_SPD_BUS_NUM 0
+static inline struct ppc4xx_i2c *ppc4xx_get_i2c(int hwadapnr)
+{
+ unsigned long base;
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
+ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
+ defined(CONFIG_460EX) || defined(CONFIG_460GT)
+ base = CONFIG_SYS_PERIPHERAL_BASE + 0x00000700 + (hwadapnr * 0x100);
+#elif defined(CONFIG_440) || defined(CONFIG_405EX)
+/* all remaining 440 variants */
+ base = CONFIG_SYS_PERIPHERAL_BASE + 0x00000400 + (hwadapnr * 0x100);
+#else
+/* all 405 variants */
+ base = 0xEF600500 + (hwadapnr * 0x100);
#endif
-static unsigned int i2c_bus_num __attribute__ ((section (".data"))) =
- CONFIG_SYS_SPD_BUS_NUM;
-#endif /* CONFIG_I2C_MULTI_BUS */
+ return (struct ppc4xx_i2c *)base;
+}
-static void _i2c_bus_reset(void)
+static void _i2c_bus_reset(struct i2c_adapter *adap)
{
- struct ppc4xx_i2c *i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR;
+ struct ppc4xx_i2c *i2c = ppc4xx_get_i2c(adap->hwadapnr);
int i;
u8 dc;
@@ -75,11 +77,10 @@ static void _i2c_bus_reset(void)
out_8(&i2c->xtcntlss, 0);
}
-void i2c_init(int speed, int slaveaddr)
+static void ppc4xx_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
- struct ppc4xx_i2c *i2c;
+ struct ppc4xx_i2c *i2c = ppc4xx_get_i2c(adap->hwadapnr);
int val, divisor;
- int bus;
#ifdef CONFIG_SYS_I2C_INIT_BOARD
/*
@@ -90,67 +91,57 @@ void i2c_init(int speed, int slaveaddr)
i2c_init_board();
#endif
- for (bus = 0; bus < CONFIG_SYS_MAX_I2C_BUS; bus++) {
- I2C_SET_BUS(bus);
-
- /* Set i2c pointer after calling I2C_SET_BUS() */
- i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR;
-
- /* Handle possible failed I2C state */
- /* FIXME: put this into i2c_init_board()? */
- _i2c_bus_reset();
+ /* Handle possible failed I2C state */
+ /* FIXME: put this into i2c_init_board()? */
+ _i2c_bus_reset(adap);
- /* clear lo master address */
- out_8(&i2c->lmadr, 0);
+ /* clear lo master address */
+ out_8(&i2c->lmadr, 0);
- /* clear hi master address */
- out_8(&i2c->hmadr, 0);
-
- /* clear lo slave address */
- out_8(&i2c->lsadr, 0);
+ /* clear hi master address */
+ out_8(&i2c->hmadr, 0);
- /* clear hi slave address */
- out_8(&i2c->hsadr, 0);
+ /* clear lo slave address */
+ out_8(&i2c->lsadr, 0);
- /* Clock divide Register */
- /* set divisor according to freq_opb */
- divisor = (get_OPB_freq() - 1) / 10000000;
- if (divisor == 0)
- divisor = 1;
- out_8(&i2c->clkdiv, divisor);
+ /* clear hi slave address */
+ out_8(&i2c->hsadr, 0);
- /* no interrupts */
- out_8(&i2c->intrmsk, 0);
+ /* Clock divide Register */
+ /* set divisor according to freq_opb */
+ divisor = (get_OPB_freq() - 1) / 10000000;
+ if (divisor == 0)
+ divisor = 1;
+ out_8(&i2c->clkdiv, divisor);
- /* clear transfer count */
- out_8(&i2c->xfrcnt, 0);
+ /* no interrupts */
+ out_8(&i2c->intrmsk, 0);
- /* clear extended control & stat */
- /* write 1 in SRC SRS SWC SWS to clear these fields */
- out_8(&i2c->xtcntlss, 0xF0);
+ /* clear transfer count */
+ out_8(&i2c->xfrcnt, 0);
- /* Mode Control Register
- Flush Slave/Master data buffer */
- out_8(&i2c->mdcntl, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
+ /* clear extended control & stat */
+ /* write 1 in SRC SRS SWC SWS to clear these fields */
+ out_8(&i2c->xtcntlss, 0xF0);
- val = in_8(&i2c->mdcntl);
+ /* Mode Control Register
+ Flush Slave/Master data buffer */
+ out_8(&i2c->mdcntl, IIC_MDCNTL_FSDB | IIC_MDCNTL_FMDB);
- /* Ignore General Call, slave transfers are ignored,
- * disable interrupts, exit unknown bus state, enable hold
- * SCL 100kHz normaly or FastMode for 400kHz and above
- */
+ val = in_8(&i2c->mdcntl);
- val |= IIC_MDCNTL_EUBS | IIC_MDCNTL_HSCL;
- if (speed >= 400000)
- val |= IIC_MDCNTL_FSM;
- out_8(&i2c->mdcntl, val);
+ /* Ignore General Call, slave transfers are ignored,
+ * disable interrupts, exit unknown bus state, enable hold
+ * SCL 100kHz normaly or FastMode for 400kHz and above
+ */
- /* clear control reg */
- out_8(&i2c->cntl, 0x00);
- }
+ val |= IIC_MDCNTL_EUBS | IIC_MDCNTL_HSCL;
+ if (speed >= 400000)
+ val |= IIC_MDCNTL_FSM;
+ out_8(&i2c->mdcntl, val);
- /* set to SPD bus as default bus upon powerup */
- I2C_SET_BUS(CONFIG_SYS_SPD_BUS_NUM);
+ /* clear control reg */
+ out_8(&i2c->cntl, 0x00);
}
/*
@@ -178,14 +169,15 @@ void i2c_init(int speed, int slaveaddr)
*
* It does not check XFRCNT.
*/
-static int i2c_transfer(unsigned char cmd_type,
+static int _i2c_transfer(struct i2c_adapter *adap,
+ unsigned char cmd_type,
unsigned char chip,
unsigned char addr[],
unsigned char addr_len,
unsigned char data[],
unsigned short data_len)
{
- struct ppc4xx_i2c *i2c = (struct ppc4xx_i2c *)I2C_BASE_ADDR;
+ struct ppc4xx_i2c *i2c = ppc4xx_get_i2c(adap->hwadapnr);
u8 *ptr;
int reading;
int tran, cnt;
@@ -329,7 +321,7 @@ static int i2c_transfer(unsigned char cmd_type,
return result;
}
-int i2c_probe(uchar chip)
+static int ppc4xx_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
uchar buf[1];
@@ -340,11 +332,11 @@ int i2c_probe(uchar chip)
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
- return (i2c_transfer(1, chip << 1, 0, 0, buf, 1) != 0);
+ return (_i2c_transfer(adap, 1, chip << 1, 0, 0, buf, 1) != 0);
}
-static int ppc4xx_i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer,
- int len, int read)
+static int ppc4xx_i2c_transfer(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len, int read)
{
uchar xaddr[4];
int ret;
@@ -378,43 +370,50 @@ static int ppc4xx_i2c_transfer(uchar chip, uint addr, int alen, uchar *buffer,
chip |= ((addr >> (alen * 8)) &
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
#endif
- if ((ret = i2c_transfer(read, chip << 1, &xaddr[4 - alen], alen,
- buffer, len)) != 0) {
+ ret = _i2c_transfer(adap, read, chip << 1, &xaddr[4 - alen], alen,
+ buffer, len);
+ if (ret) {
printf("I2C %s: failed %d\n", read ? "read" : "write", ret);
-
return 1;
}
return 0;
}
-int i2c_read(uchar chip, uint addr, int alen, uchar * buffer, int len)
+static int ppc4xx_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
{
- return ppc4xx_i2c_transfer(chip, addr, alen, buffer, len, 1);
+ return ppc4xx_i2c_transfer(adap, chip, addr, alen, buffer, len, 1);
}
-int i2c_write(uchar chip, uint addr, int alen, uchar * buffer, int len)
+static int ppc4xx_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
{
- return ppc4xx_i2c_transfer(chip, addr, alen, buffer, len, 0);
+ return ppc4xx_i2c_transfer(adap, chip, addr, alen, buffer, len, 0);
}
-#if defined(CONFIG_I2C_MULTI_BUS)
-/*
- * Functions for multiple I2C bus handling
- */
-unsigned int i2c_get_bus_num(void)
+static unsigned int ppc4xx_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
{
- return i2c_bus_num;
-}
-
-int i2c_set_bus_num(unsigned int bus)
-{
- if (bus >= CONFIG_SYS_MAX_I2C_BUS)
+ if (speed != adap->speed)
return -1;
-
- i2c_bus_num = bus;
-
- return 0;
+ return speed;
}
-#endif /* CONFIG_I2C_MULTI_BUS */
-#endif /* CONFIG_HARD_I2C */
+
+/*
+ * Register ppc4xx i2c adapters
+ */
+#ifdef CONFIG_SYS_I2C_PPC4XX_CH0
+U_BOOT_I2C_ADAP_COMPLETE(ppc4xx_0, ppc4xx_i2c_init, ppc4xx_i2c_probe,
+ ppc4xx_i2c_read, ppc4xx_i2c_write,
+ ppc4xx_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_PPC4XX_SPEED_0,
+ CONFIG_SYS_I2C_PPC4XX_SLAVE_0, 0)
+#endif
+#ifdef CONFIG_SYS_I2C_PPC4XX_CH1
+U_BOOT_I2C_ADAP_COMPLETE(ppc4xx_1, ppc4xx_i2c_init, ppc4xx_i2c_probe,
+ ppc4xx_i2c_read, ppc4xx_i2c_write,
+ ppc4xx_i2c_set_bus_speed,
+ CONFIG_SYS_I2C_PPC4XX_SPEED_1,
+ CONFIG_SYS_I2C_PPC4XX_SLAVE_1, 1)
+#endif
diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c
index 0a1423016e..a2baec0ace 100644
--- a/drivers/i2c/soft_i2c.c
+++ b/drivers/i2c/soft_i2c.c
@@ -1,4 +1,8 @@
/*
+ * (C) Copyright 2009
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ * Changes for multibus/multiadapter I2C support.
+ *
* (C) Copyright 2001, 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
@@ -87,14 +91,30 @@
/* #define DEBUG_I2C */
-#ifdef DEBUG_I2C
DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef I2C_SOFT_DECLARATIONS
+# if defined(CONFIG_MPC8260)
+# define I2C_SOFT_DECLARATIONS volatile ioport_t *iop = \
+ ioport_addr((immap_t *)CONFIG_SYS_IMMR, I2C_PORT);
+# elif defined(CONFIG_8xx)
+# define I2C_SOFT_DECLARATIONS volatile immap_t *immr = \
+ (immap_t *)CONFIG_SYS_IMMR;
+# else
+# define I2C_SOFT_DECLARATIONS
+# endif
+#endif
+
+#if !defined(CONFIG_SYS_SOFT_I2C_SPEED)
+#define CONFIG_SYS_SOFT_I2C_SPEED CONFIG_SYS_I2C_SPEED
+#endif
+#if !defined(CONFIG_SYS_SOFT_I2C_SLAVE)
+#define CONFIG_SYS_SOFT_I2C_SLAVE CONFIG_SYS_I2C_SLAVE
#endif
/*-----------------------------------------------------------------------
* Definitions
*/
-
#define RETRIES 0
#define I2C_ACK 0 /* PD_SDA level to ack a byte */
@@ -109,10 +129,6 @@ DECLARE_GLOBAL_DATA_PTR;
#define PRINTD(fmt,args...)
#endif
-#if defined(CONFIG_I2C_MULTI_BUS)
-static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = 0;
-#endif /* CONFIG_I2C_MULTI_BUS */
-
/*-----------------------------------------------------------------------
* Local functions
*/
@@ -251,39 +267,6 @@ static int write_byte(uchar data)
return(nack); /* not a nack is an ack */
}
-#if defined(CONFIG_I2C_MULTI_BUS)
-/*
- * Functions for multiple I2C bus handling
- */
-unsigned int i2c_get_bus_num(void)
-{
- return i2c_bus_num;
-}
-
-int i2c_set_bus_num(unsigned int bus)
-{
-#if defined(CONFIG_I2C_MUX)
- if (bus < CONFIG_SYS_MAX_I2C_BUS) {
- i2c_bus_num = bus;
- } else {
- int ret;
-
- ret = i2x_mux_select_mux(bus);
- i2c_init_board();
- if (ret == 0)
- i2c_bus_num = bus;
- else
- return ret;
- }
-#else
- if (bus >= CONFIG_SYS_MAX_I2C_BUS)
- return -1;
- i2c_bus_num = bus;
-#endif
- return 0;
-}
-#endif
-
/*-----------------------------------------------------------------------
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
@@ -314,14 +297,10 @@ static uchar read_byte(int ack)
return(data);
}
-/*=====================================================================*/
-/* Public Functions */
-/*=====================================================================*/
-
/*-----------------------------------------------------------------------
* Initialization
*/
-void i2c_init (int speed, int slaveaddr)
+static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
#if defined(CONFIG_SYS_I2C_INIT_BOARD)
/* call board specific i2c bus reset routine before accessing the */
@@ -344,7 +323,7 @@ void i2c_init (int speed, int slaveaddr)
* completion of EEPROM writes since the chip stops responding until
* the write completes (typically 10mSec).
*/
-int i2c_probe(uchar addr)
+static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr)
{
int rc;
@@ -362,7 +341,8 @@ int i2c_probe(uchar addr)
/*-----------------------------------------------------------------------
* Read bytes
*/
-int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
{
int shift;
PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n",
@@ -436,7 +416,8 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
/*-----------------------------------------------------------------------
* Write bytes
*/
-int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
{
int shift, failures = 0;
@@ -466,3 +447,32 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
send_stop();
return(failures);
}
+
+/*
+ * Register soft i2c adapters
+ */
+U_BOOT_I2C_ADAP_COMPLETE(soft0, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE,
+ 0)
+#if defined(I2C_SOFT_DECLARATIONS2)
+U_BOOT_I2C_ADAP_COMPLETE(soft1, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_2,
+ CONFIG_SYS_I2C_SOFT_SLAVE_2,
+ 1)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS3)
+U_BOOT_I2C_ADAP_COMPLETE(soft2, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_3,
+ CONFIG_SYS_I2C_SOFT_SLAVE_3,
+ 2)
+#endif
+#if defined(I2C_SOFT_DECLARATIONS4)
+U_BOOT_I2C_ADAP_COMPLETE(soft3, soft_i2c_init, soft_i2c_probe,
+ soft_i2c_read, soft_i2c_write, NULL,
+ CONFIG_SYS_I2C_SOFT_SPEED_4,
+ CONFIG_SYS_I2C_SOFT_SLAVE_4,
+ 3)
+#endif
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index e96d5d5d09..9ac3969a07 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -19,8 +19,6 @@
DECLARE_GLOBAL_DATA_PTR;
-static unsigned int i2c_bus_num;
-
/* Information about i2c controller */
struct i2c_bus {
int id;
@@ -268,7 +266,8 @@ exit:
return error;
}
-static int tegra_i2c_write_data(u32 addr, u8 *data, u32 len)
+static int tegra_i2c_write_data(struct i2c_bus *bus, u32 addr, u8 *data,
+ u32 len)
{
int error;
struct i2c_trans_info trans_info;
@@ -279,14 +278,15 @@ static int tegra_i2c_write_data(u32 addr, u8 *data, u32 len)
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
- error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
+ error = send_recv_packets(bus, &trans_info);
if (error)
debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
return error;
}
-static int tegra_i2c_read_data(u32 addr, u8 *data, u32 len)
+static int tegra_i2c_read_data(struct i2c_bus *bus, u32 addr, u8 *data,
+ u32 len)
{
int error;
struct i2c_trans_info trans_info;
@@ -297,7 +297,7 @@ static int tegra_i2c_read_data(u32 addr, u8 *data, u32 len)
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
- error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
+ error = send_recv_packets(bus, &trans_info);
if (error)
debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
@@ -308,18 +308,35 @@ static int tegra_i2c_read_data(u32 addr, u8 *data, u32 len)
#error "Please enable device tree support to use this driver"
#endif
-unsigned int i2c_get_bus_speed(void)
+/**
+ * Check that a bus number is valid and return a pointer to it
+ *
+ * @param bus_num Bus number to check / return
+ * @return pointer to bus, if valid, else NULL
+ */
+static struct i2c_bus *tegra_i2c_get_bus(struct i2c_adapter *adap)
{
- return i2c_controllers[i2c_bus_num].speed;
+ struct i2c_bus *bus;
+
+ bus = &i2c_controllers[adap->hwadapnr];
+ if (!bus->inited) {
+ debug("%s: Bus %u not available\n", __func__, adap->hwadapnr);
+ return NULL;
+ }
+
+ return bus;
}
-int i2c_set_bus_speed(unsigned int speed)
+static unsigned int tegra_i2c_set_bus_speed(struct i2c_adapter *adap,
+ unsigned int speed)
{
- struct i2c_bus *i2c_bus;
+ struct i2c_bus *bus;
- i2c_bus = &i2c_controllers[i2c_bus_num];
- i2c_bus->speed = speed;
- i2c_init_controller(i2c_bus);
+ bus = tegra_i2c_get_bus(adap);
+ if (!bus)
+ return 0;
+ bus->speed = speed;
+ i2c_init_controller(bus);
return 0;
}
@@ -434,7 +451,7 @@ void i2c_init_board(void)
return;
}
-void i2c_init(int speed, int slaveaddr)
+static void tegra_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
{
/* This will override the speed selected in the fdt for that port */
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
@@ -442,7 +459,7 @@ void i2c_init(int speed, int slaveaddr)
}
/* i2c write version without the register address */
-int i2c_write_data(uchar chip, uchar *buffer, int len)
+int i2c_write_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
{
int rc;
@@ -454,7 +471,7 @@ int i2c_write_data(uchar chip, uchar *buffer, int len)
debug("\n");
/* Shift 7-bit address over for lower-level i2c functions */
- rc = tegra_i2c_write_data(chip << 1, buffer, len);
+ rc = tegra_i2c_write_data(bus, chip << 1, buffer, len);
if (rc)
debug("i2c_write_data(): rc=%d\n", rc);
@@ -462,13 +479,13 @@ int i2c_write_data(uchar chip, uchar *buffer, int len)
}
/* i2c read version without the register address */
-int i2c_read_data(uchar chip, uchar *buffer, int len)
+int i2c_read_data(struct i2c_bus *bus, uchar chip, uchar *buffer, int len)
{
int rc;
debug("inside i2c_read_data():\n");
/* Shift 7-bit address over for lower-level i2c functions */
- rc = tegra_i2c_read_data(chip << 1, buffer, len);
+ rc = tegra_i2c_read_data(bus, chip << 1, buffer, len);
if (rc) {
debug("i2c_read_data(): rc=%d\n", rc);
return rc;
@@ -484,14 +501,18 @@ int i2c_read_data(uchar chip, uchar *buffer, int len)
}
/* Probe to see if a chip is present. */
-int i2c_probe(uchar chip)
+static int tegra_i2c_probe(struct i2c_adapter *adap, uchar chip)
{
+ struct i2c_bus *bus;
int rc;
uchar reg;
debug("i2c_probe: addr=0x%x\n", chip);
+ bus = tegra_i2c_get_bus(adap);
+ if (!bus)
+ return 1;
reg = 0;
- rc = i2c_write_data(chip, &reg, 1);
+ rc = i2c_write_data(bus, chip, &reg, 1);
if (rc) {
debug("Error probing 0x%x.\n", chip);
return 1;
@@ -506,13 +527,18 @@ static int i2c_addr_ok(const uint addr, const int alen)
}
/* Read bytes */
-int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int tegra_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
{
+ struct i2c_bus *bus;
uint offset;
int i;
debug("i2c_read: chip=0x%x, addr=0x%x, len=0x%x\n",
chip, addr, len);
+ bus = tegra_i2c_get_bus(adap);
+ if (!bus)
+ return 1;
if (!i2c_addr_ok(addr, alen)) {
debug("i2c_read: Bad address %x.%d.\n", addr, alen);
return 1;
@@ -524,13 +550,13 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
data[alen - i - 1] =
(addr + offset) >> (8 * i);
}
- if (i2c_write_data(chip, data, alen)) {
+ if (i2c_write_data(bus, chip, data, alen)) {
debug("i2c_read: error sending (0x%x)\n",
addr);
return 1;
}
}
- if (i2c_read_data(chip, buffer + offset, 1)) {
+ if (i2c_read_data(bus, chip, buffer + offset, 1)) {
debug("i2c_read: error reading (0x%x)\n", addr);
return 1;
}
@@ -540,13 +566,18 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
}
/* Write bytes */
-int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
+static int tegra_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr,
+ int alen, uchar *buffer, int len)
{
+ struct i2c_bus *bus;
uint offset;
int i;
debug("i2c_write: chip=0x%x, addr=0x%x, len=0x%x\n",
chip, addr, len);
+ bus = tegra_i2c_get_bus(adap);
+ if (!bus)
+ return 1;
if (!i2c_addr_ok(addr, alen)) {
debug("i2c_write: Bad address %x.%d.\n", addr, alen);
return 1;
@@ -556,7 +587,7 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
for (i = 0; i < alen; i++)
data[alen - i - 1] = (addr + offset) >> (8 * i);
data[alen] = buffer[offset];
- if (i2c_write_data(chip, data, alen + 1)) {
+ if (i2c_write_data(bus, chip, data, alen + 1)) {
debug("i2c_write: error sending (0x%x)\n", addr);
return 1;
}
@@ -565,30 +596,11 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
return 0;
}
-#if defined(CONFIG_I2C_MULTI_BUS)
-/*
- * Functions for multiple I2C bus handling
- */
-unsigned int i2c_get_bus_num(void)
-{
- return i2c_bus_num;
-}
-
-int i2c_set_bus_num(unsigned int bus)
-{
- if (bus >= TEGRA_I2C_NUM_CONTROLLERS || !i2c_controllers[bus].inited)
- return -1;
- i2c_bus_num = bus;
-
- return 0;
-}
-#endif
-
int tegra_i2c_get_dvc_bus_num(void)
{
int i;
- for (i = 0; i < CONFIG_SYS_MAX_I2C_BUS; i++) {
+ for (i = 0; i < TEGRA_I2C_NUM_CONTROLLERS; i++) {
struct i2c_bus *bus = &i2c_controllers[i];
if (bus->inited && bus->is_dvc)
@@ -597,3 +609,19 @@ int tegra_i2c_get_dvc_bus_num(void)
return -1;
}
+
+/*
+ * Register soft i2c adapters
+ */
+U_BOOT_I2C_ADAP_COMPLETE(tegra0, tegra_i2c_init, tegra_i2c_probe,
+ tegra_i2c_read, tegra_i2c_write,
+ tegra_i2c_set_bus_speed, 100000, 0, 0)
+U_BOOT_I2C_ADAP_COMPLETE(tegra1, tegra_i2c_init, tegra_i2c_probe,
+ tegra_i2c_read, tegra_i2c_write,
+ tegra_i2c_set_bus_speed, 100000, 0, 1)
+U_BOOT_I2C_ADAP_COMPLETE(tegra2, tegra_i2c_init, tegra_i2c_probe,
+ tegra_i2c_read, tegra_i2c_write,
+ tegra_i2c_set_bus_speed, 100000, 0, 2)
+U_BOOT_I2C_ADAP_COMPLETE(tegra3, tegra_i2c_init, tegra_i2c_probe,
+ tegra_i2c_read, tegra_i2c_write,
+ tegra_i2c_set_bus_speed, 100000, 0, 3)
OpenPOWER on IntegriCloud