diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/Makefile | 10 | ||||
| -rw-r--r-- | drivers/i2c/fsl_i2c.c | 216 | ||||
| -rw-r--r-- | drivers/i2c/fti2c010.c | 369 | ||||
| -rw-r--r-- | drivers/i2c/fti2c010.h | 81 | ||||
| -rw-r--r-- | drivers/i2c/i2c_core.c | 414 | ||||
| -rw-r--r-- | drivers/i2c/mxc_i2c.c | 62 | ||||
| -rw-r--r-- | drivers/i2c/ppc4xx_i2c.c | 193 | ||||
| -rw-r--r-- | drivers/i2c/soft_i2c.c | 104 | ||||
| -rw-r--r-- | drivers/i2c/tegra_i2c.c | 118 | 
9 files changed, 1235 insertions, 332 deletions
| diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 4ffbfdde3..37ccbd142 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 5d7e01031..38455e1c6 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]; +	dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr]; -		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 */ -	} +	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 000000000..24c4bb53f --- /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(®s->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), ®s->dr); +	writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); +	ret = fti2c010_wait(SR_DT); +	if (ret) +		return ret; + +	/* 2. Select device register */ +	writel(0, ®s->dr); +	writel(CR_ENABLE | CR_TBEN, ®s->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), ®s->dr); +	writel(CR_ENABLE | CR_TBEN | CR_START, ®s->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], ®s->dr); +		writel(ctrl, ®s->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), ®s->dr); +	writel(CR_ENABLE | CR_TBEN | CR_START, ®s->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, ®s->cr); +		ret = fti2c010_wait(stat); +		if (ret) +			break; +		buf[pos] = (uchar)(readl(®s->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), ®s->dr); +	writel(CR_ENABLE | CR_TBEN | CR_START, ®s->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], ®s->dr); +		writel(ctrl, ®s->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], ®s->dr); +		writel(ctrl, ®s->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, ®s->cr); +	mdelay(100); +	if (readl(®s->cr) & CR_I2CRST) { +		printf("fti2c010: reset timeout\n"); +		return -1; +	} + +	curr->speed = spd; + +	writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), ®s->tgsr); +	writel(CDR_DIV(div), ®s->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 000000000..18aec2c97 --- /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 000000000..3c01893c9 --- /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 3eadbac0c..06ba4e39f 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 52929ebc4..e7a15ba64 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(adap); -		/* Handle possible failed I2C state */ -		/* FIXME: put this into i2c_init_board()? */ -		_i2c_bus_reset(); +	/* 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 0a1423016..a2baec0ac 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 e96d5d5d0..9ac3969a0 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, ®, 1); +	rc = i2c_write_data(bus, chip, ®, 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) |