diff options
| author | Wolfgang Denk <wd@denx.de> | 2011-06-01 22:04:12 +0200 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2011-06-01 22:04:12 +0200 | 
| commit | 033cd2c42bf335d3b96e9612695f6c30b83dce2b (patch) | |
| tree | 1bc9e1d9163cd3114bfeb016d4f4311fbbbec491 /drivers/i2c/u8500_i2c.c | |
| parent | 2130b03309dcf56dab11b6fd0be3b4bedc7f628c (diff) | |
| parent | cd3af8b56749b3200cd858b5a9424c6661958e5f (diff) | |
| download | olio-uboot-2014.01-033cd2c42bf335d3b96e9612695f6c30b83dce2b.tar.xz olio-uboot-2014.01-033cd2c42bf335d3b96e9612695f6c30b83dce2b.zip | |
Merge branch 'master' of git://git.denx.de/u-boot-arm
* 'master' of git://git.denx.de/u-boot-arm:
  SMDKV310: Fix incorrect conditional compilation for MIU linear mapping
  SMDKV310: CPU fequency and mmc_pre_ratio modified
  armv7: Add support for ST-Ericsson U8500 href platform
  I2C: Add driver for ST-Ericsson U8500 i2c
  armv7: Add ST-Ericsson u8500 arch
  Kirkwood: boards cleanup for deprecated CONFIG_CMD_AUTOSCRIPT
  ARMV7: Vexpress: Add missing MMC header
  arm/km: update mgcoge3un board support
  mvgbe: enable configurability of PORT_SERIAL_CONTROL_VALUE
  arm/km: rename mgcoge2un to mgcoge3un
  arm/km: add second serial interface for kirkwood
  arm/km: disable ls (through jffs2 support)
  arm/km: introduce bootcount env variable and clean km_arm
  arm/km: move CONFIG_EXTRA_ENV_SETTINGS from board to km_arm file
  arm/km: remove CONFIG_SYS_KWD_CONFIG from keymile-common.h
  ARMV7: MMC SPL Boot support for SMDKV310 board
  ARMV7: Add support for Samsung SMDKV310 Board
  S5PC2XX: clock: support pwm clock for evt1 (cpu revision 1)
  S5P: add set_mmc_clk for external clock control
  S5PC2XX: Support the cpu revision
  S5P:SROM config code moved to s5p-common directory
  Add _end for the end of u-boot image for SMDK6400
  MMC S5P: Fix typo
  S5P: GPIO Macro Values Corrected.
  SMDK2410: various cleanup/code style fixes
  SMDK2410: use the CFI driver (and remove the old one)
  SMDK2410: remove unneeded config.mk
  SMDK2410: activate ARM relocation feature
  BeagleBoard: fixed typo in typecast
  mvsata: issue hard reset on initialization
  VCMA9: use ARM relocation feature to fix build error
  MX31: drop warnings due to missing prototype for mxc_watchdog_reset()
  MX5: drop config.mk from efikamx board
  MX31: Make get_reset_cause() static and drop unreachable code
  MX53: Remove CONFIG_SYS_BOOTMAPSZ from mx53 config files.
  MX53: Handle silicon revision 2.1 case
  mx5: board: code clean up for checkboard code
  MX51: vision2: Fix build for vision2 board.
  MX51: vision: Let video mode struct be independant of watchdog.
  MX53: Add initial support for MX53SMD board.
  MX53: support for freescale MX53LOCO board
  mx5: Fix CONFIG_OF_LIBFDT redefined warning
  mx5: Remove unnecessary CONFIG_SYS_BOOTMAPSZ definition
  mx31pdk: Clean up mx31pdk.h file
Diffstat (limited to 'drivers/i2c/u8500_i2c.c')
| -rw-r--r-- | drivers/i2c/u8500_i2c.c | 613 | 
1 files changed, 613 insertions, 0 deletions
| diff --git a/drivers/i2c/u8500_i2c.c b/drivers/i2c/u8500_i2c.c new file mode 100644 index 000000000..ea8a71d86 --- /dev/null +++ b/drivers/i2c/u8500_i2c.c @@ -0,0 +1,613 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Basic U-Boot I2C interface for STn8500/DB8500 + * Author: Michael Brandt <Michael.Brandt@stericsson.com> for ST-Ericsson + * + * 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. + */ + +/* + * Only 7-bit I2C device addresses are supported. + */ + +#include <common.h> +#include <i2c.h> + +#include "u8500_i2c.h" +#include <asm/io.h> +#include <asm/arch/clock.h> + +#define U8500_I2C_ENDAD_COUNTER	(CONFIG_SYS_HZ/100)	/* I2C bus timeout */ +#define U8500_I2C_FIFO_FLUSH_COUNTER	500000		/* flush "timeout" */ +#define U8500_I2C_SCL_FREQ		100000		/* I2C bus clock freq */ +#define U8500_I2C_INPUT_FREQ		48000000	/* Input clock freq */ +#define TX_FIFO_THRESHOLD	0x4 +#define RX_FIFO_THRESHOLD	0x4 +#define SLAVE_SETUP_TIME 14 /* Slave data setup time, 250ns for 48MHz i2c_clk */ + +#define WRITE_FIELD(var, mask, shift, value) \ +			(var = ((var & ~(mask)) | ((value) << (shift)))) + +static unsigned int bus_initialized[CONFIG_SYS_U8500_I2C_BUS_MAX]; +static unsigned int i2c_bus_num; +static unsigned int i2c_bus_speed[] = { +	CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED, +	CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED +}; +static struct u8500_i2c_regs *i2c_dev[] = { +	(struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C0_BASE, +	(struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C1_BASE, +	(struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C2_BASE, +	(struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C3_BASE, +}; + +static struct { +	int periph; +	int pcken; +	int kcken; +} i2c_clock_bits[] = { +	{3, 3, 3}, /* I2C0 */ +	{1, 2, 2}, /* I2C1 */ +	{1, 6, 6}, /* I2C2 */ +	{2, 0, 0}, /* I2C3 */ +}; + +static void i2c_set_bit(void *reg, u32 mask) +{ +	writel(readl(reg) | mask, reg); +} + +static void i2c_clr_bit(void *reg, u32 mask) +{ +	writel(readl(reg) & ~mask, reg); +} + +static void i2c_write_field(void *reg, u32 mask, uint shift, u32 value) +{ +	writel((readl(reg) & ~mask) | (value << shift), reg); +} + +static int __i2c_set_bus_speed(unsigned int speed) +{ +	u32 value; +	struct u8500_i2c_regs *i2c_regs; + +	i2c_regs = i2c_dev[i2c_bus_num]; + +	/* Select standard (100 kbps) speed mode */ +	i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_SM, +			U8500_I2C_CR_SHIFT_SM, 0x0); + +	/* +	 * Set the Baud Rate Counter 2 value +	 * Baud rate (standard) = fi2cclk / ( (BRCNT2 x 2) + Foncycle ) +	 * Foncycle = 0 (no digital filtering) +	 */ +	value = (u32) (U8500_I2C_INPUT_FREQ / (speed * 2)); +	i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT2, +			U8500_I2C_BRCR_SHIFT_BRCNT2, value); + +	/* ensure that BRCNT value is zero */ +	i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT1, +			U8500_I2C_BRCR_SHIFT_BRCNT1, 0); + +	return U8500_I2C_INPUT_FREQ/(value * 2); +} + +/* + * i2c_init - initialize the i2c bus + * + *	speed: bus speed (in HZ) + *	slaveaddr: address of device in slave mode + * + *	Slave mode is not implemented. + */ +void i2c_init(int speed, int slaveaddr) +{ +	struct u8500_i2c_regs *i2c_regs; + +	debug("i2c_init bus %d, speed %d\n", i2c_bus_num, speed); + +	u8500_clock_enable(i2c_clock_bits[i2c_bus_num].periph, +			   i2c_clock_bits[i2c_bus_num].pcken, +			   i2c_clock_bits[i2c_bus_num].kcken); + +	i2c_regs = i2c_dev[i2c_bus_num]; + +	/* Disable the controller */ +	i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_PE); + +	/* Clear registers */ +	writel(0, &i2c_regs->cr); +	writel(0, &i2c_regs->scr); +	writel(0, &i2c_regs->hsmcr); +	writel(0, &i2c_regs->tftr); +	writel(0, &i2c_regs->rftr); +	writel(0, &i2c_regs->dmar); + +	i2c_bus_speed[i2c_bus_num] = __i2c_set_bus_speed(speed); + +	/* +	 * Set our own address. +	 * Set slave address mode to 7 bit addressing mode +	 */ +	i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_SAM); +	i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_ADDR, +			U8500_I2C_SCR_SHIFT_ADDR, slaveaddr); +	/* Slave Data Set up Time */ +	i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_DATA_SETUP_TIME, +			U8500_I2C_SCR_SHIFT_DATA_SETUP_TIME, SLAVE_SETUP_TIME); + +	/* Disable the DMA sync logic */ +	i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_DMA_SLE, +			U8500_I2C_CR_SHIFT_DMA_SLE, 0); + +	/* Disable interrupts */ +	writel(0, &i2c_regs->imscr); + +	/* Configure bus master mode */ +	i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_OM, U8500_I2C_CR_SHIFT_OM, +			U8500_I2C_BUS_MASTER_MODE); +	/* Set FIFO threshold values */ +	writel(TX_FIFO_THRESHOLD, &i2c_regs->tftr); +	writel(RX_FIFO_THRESHOLD, &i2c_regs->rftr); + +	/* Enable the I2C Controller */ +	i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_PE); + +	bus_initialized[i2c_bus_num] = 1; +} + + +/* + * loop_till_bit_clear - polls on a bit till it clears + * ioreg: register where you want to check status + * mask: bit mask for the bit you wish to check + * timeout: timeout in ticks/s + */ +static int loop_till_bit_clear(void *io_reg, u32 mask, unsigned long timeout) +{ +	unsigned long timebase = get_timer(0); + +	do { +		if ((readl(io_reg) & mask) == 0x0UL) +			return 0; +	} while (get_timer(timebase) < timeout); + +	debug("loop_till_bit_clear timed out\n"); +	return -1; +} + +/* + * loop_till_bit_set - polls on a bit till it is set. + * ioreg: register where you want to check status + * mask: bit mask for the bit you wish to check + * timeout: timeout in ticks/s + */ +static int loop_till_bit_set(void *io_reg, u32 mask, unsigned long timeout) +{ +	unsigned long timebase = get_timer(0); + +	do { +		if ((readl(io_reg) & mask) != 0x0UL) +			return 0; +	} while (get_timer(timebase) < timeout); + +	debug("loop_till_bit_set timed out\n"); +	return -1; +} + +/* + * flush_fifo - flush the I2C TX and RX FIFOs + */ +static void flush_fifo(struct u8500_i2c_regs *i2c_regs) +{ +	int counter = U8500_I2C_FIFO_FLUSH_COUNTER; + +	/* Flush Tx FIFO */ +	i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FTX); +	/* Flush Rx FIFO */ +	i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FRX); +	while (counter--) { +		if (!(readl(&i2c_regs->cr) & +				(U8500_I2C_CR_FTX | U8500_I2C_CR_FRX))) +			break; +	} +	return; +} + +#ifdef DEBUG +static void print_abort_reason(struct u8500_i2c_regs *i2c_regs) +{ +	int cause; + +	printf("abort: risr %08x, sr %08x\n", i2c_regs->risr, i2c_regs->sr); +	cause = (readl(&i2c_regs->sr) & U8500_I2C_SR_CAUSE) >> +				U8500_I2C_SR_SHIFT_CAUSE; +	switch (cause) { +	case U8500_I2C_NACK_ADDR: +		printf("No Ack received after Slave Address xmission\n"); +		break; +	case U8500_I2C_NACK_DATA: +		printf("Valid for MASTER_WRITE: No Ack received " +				"during data phase\n"); +		break; +	case U8500_I2C_ACK_MCODE: +		printf("Master recv ack after xmission of master code" +				"in hs mode\n"); +		break; +	case U8500_I2C_ARB_LOST: +		printf("Master Lost arbitration\n"); +		break; +	case U8500_I2C_BERR_START: +		printf("Slave restarts\n"); +		break; +	case U8500_I2C_BERR_STOP: +		printf("Slave reset\n"); +		break; +	case U8500_I2C_OVFL: +		printf("Overflow\n"); +		break; +	default: +		printf("Unknown error type\n"); +	} +} +#endif + +/* + * i2c_abort - called when a I2C transaction failed + */ +static void i2c_abort(struct u8500_i2c_regs *i2c_regs) +{ +#ifdef DEBUG +	print_abort_reason(i2c_regs); +#endif +	/* flush RX and TX fifos */ +	flush_fifo(i2c_regs); + +	/* Acknowledge the Master Transaction Done */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + +	/* Acknowledge the Master Transaction Done Without Stop */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + +	i2c_init(i2c_bus_speed[i2c_bus_num], CONFIG_SYS_I2C_SLAVE); +} + +/* + * write addr, alias index, to I2C bus. + */ +static int i2c_write_addr(struct u8500_i2c_regs *i2c_regs, uint addr, int alen) +{ +	while (alen--) { +		/* Wait until the Tx Fifo is not full */ +		if (loop_till_bit_clear((void *)&i2c_regs->risr, +					U8500_I2C_INT_TXFF, +					U8500_I2C_ENDAD_COUNTER)) { +			i2c_abort(i2c_regs); +			return -1; +		} + +		/* MSB first */ +		writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->tfr); +	} + +	return 0; +} + +/* + * Internal simplified read function: + *   i2c_regs:	Pointer to I2C registers for current bus + *   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) + *   value:	Where to put the data + * + *   Returns:	0 on success, not 0 on failure + */ +static int i2c_read_byte(struct u8500_i2c_regs *i2c_regs, uchar chip, +		uint addr, int alen, uchar *value) +{ +	u32   mcr = 0; + +	/* Set the address mode to 7 bit */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); + +	/* Store the slave address in the master control register */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); + +	if (alen != 0) { +		/* Master write operation */ +		mcr &= ~(U8500_I2C_MCR_OP); + +		/* Configure the Frame length to one byte */ +		WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, +				U8500_I2C_MCR_SHIFT_LENGTH, 1); + +		/* Repeated start, no stop */ +		mcr &= ~(U8500_I2C_MCR_STOP); + +		/* Write Master Control Register */ +		writel(mcr, &i2c_regs->mcr); + +		/* send addr/index */ +		if (i2c_write_addr(i2c_regs, addr, alen) != 0) +			return -1; + +		/* Check for the Master Transaction Done Without Stop */ +		if (loop_till_bit_set((void *)&i2c_regs->risr, +					U8500_I2C_INT_MTDWS, +					U8500_I2C_ENDAD_COUNTER)) { +			return -1; +		} + +		/* Acknowledge the Master Transaction Done Without Stop */ +		i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); +	} + +	/* Master control configuration for read operation  */ +	mcr |= U8500_I2C_MCR_OP; + +	/* Configure the STOP condition, we read only one byte */ +	mcr |= U8500_I2C_MCR_STOP; + +	/* Set the frame length to one byte, we support only 1 byte reads */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); + +	i2c_write_field(&i2c_regs->mcr, U8500_I2C_MCR_LENGTH_STOP_OP, +			U8500_I2C_MCR_SHIFT_LENGTH_STOP_OP, mcr); + +	/* +	 * receive_data_polling +	 */ + +	/* Wait until the Rx FIFO is not empty */ +	if (loop_till_bit_clear((void *)&i2c_regs->risr, +					U8500_I2C_INT_RXFE, +					U8500_I2C_ENDAD_COUNTER)) +		return -1; + +	/* Read the data byte from Rx FIFO */ +	*value = readb(&i2c_regs->rfr); + +	/* Wait until the work is done */ +	if (loop_till_bit_set((void *)&i2c_regs->risr, U8500_I2C_INT_MTD, +				U8500_I2C_ENDAD_COUNTER)) +		return -1; + +	/* Acknowledge the Master Transaction Done */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + +	/* If MTD is set, Master Transaction Done Without Stop is set too */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + +	return 0; +} + +/* + * Internal simplified write function: + *   i2c_regs:	Pointer to I2C registers for current bus + *   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) + *   data:	Where to read the data + *   len:	How many bytes to write + * + *   Returns:	0 on success, not 0 on failure + */ +static int __i2c_write(struct u8500_i2c_regs *i2c_regs, u8 chip, uint addr, +		int alen, u8 *data, int len) +{ +	int i; +	u32 mcr = 0; + +	/* Set the address mode to 7 bit */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); + +	/* Store the slave address in the master control register */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); + +	/* Write operation */ +	mcr &= ~(U8500_I2C_MCR_OP); + +	/* Current transaction is terminated by STOP condition */ +	mcr |= U8500_I2C_MCR_STOP; + +	/* Frame length: addr byte + len */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, +			(alen + len)); + +	/* Write MCR register */ +	writel(mcr, &i2c_regs->mcr); + +	if (i2c_write_addr(i2c_regs, addr, alen) != 0) +		return -1; + +	for (i = 0; i < len; i++) { +		/* Wait until the Tx FIFO is not full */ +		if (loop_till_bit_clear((void *)&i2c_regs->risr, +					U8500_I2C_INT_TXFF, +					U8500_I2C_ENDAD_COUNTER)) +			return -1; + +		/* it is a 32 bit register with upper 24 reserved R/O */ +		writeb(data[i], &i2c_regs->tfr); +	} + +	/* Check for Master Transaction Done */ +	if (loop_till_bit_set((void *)&i2c_regs->risr, +					U8500_I2C_INT_MTD, +					U8500_I2C_ENDAD_COUNTER)) { +		printf("i2c_write_byte error2: risr %08x\n", +				i2c_regs->risr); +		return -1; +	} + +	/* Acknowledge Master Transaction Done */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + +	/* Acknowledge Master Transaction Done Without Stop */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + +	return 0; +} + +/* + * Probe the given I2C chip address. Returns 0 if a chip responded, + * not 0 on failure. + */ +int i2c_probe(uchar chip) +{ +	u32 mcr = 0; +	struct u8500_i2c_regs *i2c_regs; + +	if (chip == CONFIG_SYS_I2C_SLAVE) +		return 1; + +	i2c_regs = i2c_dev[i2c_bus_num]; + +	/* Set the address mode to 7 bit */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); + +	/* Store the slave address in the master control register */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_A10, U8500_I2C_MCR_SHIFT_A7, chip); + +	/* Read operation */ +	mcr |= U8500_I2C_MCR_OP; + +	/* Set the frame length to one byte */ +	WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); + +	/* Current transaction is terminated by STOP condition */ +	mcr |= U8500_I2C_MCR_STOP; + +	/* Write MCR register */ +	writel(mcr, &i2c_regs->mcr); + +	/* Wait until the Rx Fifo is not empty */ +	if (loop_till_bit_clear((void *)&i2c_regs->risr, +					U8500_I2C_INT_RXFE, +					U8500_I2C_ENDAD_COUNTER)) { +		i2c_abort(i2c_regs); +		return -1; +	} + +	flush_fifo(i2c_regs); + +	/* Acknowledge the Master Transaction Done */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); + +	/* Acknowledge the Master Transaction Done Without Stop */ +	i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); + +	return 0; +} + +/* + * 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 *buffer, int len) +{ +	int i; +	int rc; +	struct u8500_i2c_regs *i2c_regs; + +	if (alen > 2) { +		debug("I2C read: addr len %d not supported\n", alen); +		return 1; +	} + +	i2c_regs = i2c_dev[i2c_bus_num]; + +	for (i = 0; i < len; i++) { +		rc = i2c_read_byte(i2c_regs, chip, addr + i, alen, &buffer[i]); +		if (rc != 0) { +			debug("I2C read: I/O error: %d\n", rc); +			i2c_abort(i2c_regs); +			return rc; +		} +	} + +	return 0; +} + +int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +{ +	int rc; +	struct u8500_i2c_regs *i2c_regs; +	i2c_regs = i2c_dev[i2c_bus_num]; + +	rc = __i2c_write(i2c_regs, chip, addr, alen, buffer, +			len); +	if (rc != 0) { +		debug("I2C write: I/O error\n"); +		i2c_abort(i2c_regs); +		return rc; +	} +	return 0; +} + +int i2c_set_bus_num(unsigned int bus) +{ +	if (bus > ARRAY_SIZE(i2c_dev) - 1) { +		debug("i2c_set_bus_num: only up to bus %d supported\n", +				ARRAY_SIZE(i2c_dev)-1); +		return -1; +	} + +	i2c_bus_num = bus; + +	if (!bus_initialized[i2c_bus_num]) +		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + +	return 0; +} + +int i2c_set_bus_speed(unsigned int speed) +{ + +	if (speed > U8500_I2C_MAX_STANDARD_SCL) { +		debug("i2c_set_bus_speed: only up to %d supported\n", +				U8500_I2C_MAX_STANDARD_SCL); +		return -1; +	} + +	/* sets as side effect i2c_bus_speed[i2c_bus_num] */ +	i2c_init(speed, CONFIG_SYS_I2C_SLAVE); + +	return 0; +} + +unsigned int i2c_get_bus_num(void) +{ +	return i2c_bus_num; +} + +unsigned int i2c_get_bus_speed(void) +{ +	return i2c_bus_speed[i2c_bus_num]; +} |