diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/s3c24x0_i2c.c | 83 | ||||
| -rw-r--r-- | drivers/i2c/s3c24x0_i2c.h | 8 | 
2 files changed, 90 insertions, 1 deletions
| diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 90d297a28..7ec01ec62 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,9 +27,11 @@   */  #include <common.h> +#include <fdtdec.h>  #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  #include <asm/arch/clk.h>  #include <asm/arch/cpu.h> +#include <asm/arch/pinmux.h>  #else  #include <asm/arch/s3c24x0_cpu.h>  #endif @@ -60,7 +62,14 @@  #define I2C_TIMEOUT 1		/* 1 second */ -static unsigned int g_current_bus;	/* Stores Current I2C Bus */ +/* + * For SPL boot some boards need i2c before SDRAM is initialised so force + * variables to live in SRAM + */ +static unsigned int g_current_bus __attribute__((section(".data"))); +static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] +			__attribute__((section(".data"))); +static int i2c_busses __attribute__((section(".data")));  #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)  static int GetI2CSDA(void) @@ -512,4 +521,76 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)  		(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,  		 len) != 0);  } + +#ifdef CONFIG_OF_CONTROL +void board_i2c_init(const void *blob) +{ +	int node_list[CONFIG_MAX_I2C_NUM]; +	int count, i; + +	count = fdtdec_find_aliases_for_id(blob, "i2c", +		COMPAT_SAMSUNG_S3C2440_I2C, node_list, +		CONFIG_MAX_I2C_NUM); + +	for (i = 0; i < count; i++) { +		struct s3c24x0_i2c_bus *bus; +		int node = node_list[i]; + +		if (node <= 0) +			continue; +		bus = &i2c_bus[i]; +		bus->regs = (struct s3c24x0_i2c *) +			fdtdec_get_addr(blob, node, "reg"); +		bus->id = pinmux_decode_periph_id(blob, node); +		bus->node = node; +		bus->bus_num = i2c_busses++; +		exynos_pinmux_config(bus->id, 0); +	} +} + +static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx) +{ +	if (bus_idx < i2c_busses) +		return &i2c_bus[bus_idx]; + +	debug("Undefined bus: %d\n", bus_idx); +	return NULL; +} + +int i2c_get_bus_num_fdt(int node) +{ +	int i; + +	for (i = 0; i < i2c_busses; i++) { +		if (node == i2c_bus[i].node) +			return i; +	} + +	debug("%s: Can't find any matched I2C bus\n", __func__); +	return -1; +} + +int i2c_reset_port_fdt(const void *blob, int node) +{ +	struct s3c24x0_i2c_bus *i2c; +	int bus; + +	bus = i2c_get_bus_num_fdt(node); +	if (bus < 0) { +		debug("could not get bus for node %d\n", node); +		return -1; +	} + +	i2c = get_bus(bus); +	if (!i2c) { +		debug("get_bus() failed for node node %d\n", node); +		return -1; +	} + +	i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + +	return 0; +} +#endif +  #endif /* CONFIG_HARD_I2C */ diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index 2dd4b06a2..1243bf1b1 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -30,4 +30,12 @@ struct s3c24x0_i2c {  	u32	iicds;  	u32	iiclc;  }; + +struct s3c24x0_i2c_bus { +	int node;	/* device tree node */ +	int bus_num;	/* i2c bus number */ +	struct s3c24x0_i2c *regs; +	enum periph_id id; +}; +  #endif /* _S3C24X0_I2C_H */ |