
This enables CONFIG_SYS_I2C on Samsung, updating existing s3c24x0 i2c driver to support this.
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- These patches were tested on SMDK5420
patches adding Exynos5420 support can be found at. https://patches.linaro.org/21255/
Changes since v1: 1. Implemented double digit to get rid of indexing issue. 2. Use #ifdefs to define U_BOOT_I2C_ADAP_COMPLETE for various SoCs As discussed at http://lists.denx.de/pipermail/u-boot/2013-October/163903.html
drivers/i2c/Makefile | 2 +- drivers/i2c/s3c24x0_i2c.c | 197 +++++++++++++++++++++++++++++++-------------- 2 files changed, 139 insertions(+), 60 deletions(-)
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index df3092e..3090533 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -20,7 +20,7 @@ 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_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o +COBJS-$(CONFIG_SYS_I2C_S3C24X0_I2C) += s3c24x0_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS-$(CONFIG_SH_I2C) += sh_i2c.o diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 71f3637..b8dcc3a 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -23,8 +23,6 @@ #include <i2c.h> #include "s3c24x0_i2c.h"
-#ifdef CONFIG_HARD_I2C - #define I2C_WRITE 0 #define I2C_READ 1
@@ -123,34 +121,67 @@ #define CONFIG_MAX_I2C_NUM 1 #endif
+DECLARE_GLOBAL_DATA_PTR; + /* * 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] +static struct s3c24x0_i2c_bus i2c_controllers[CONFIG_MAX_I2C_NUM] __attribute__((section(".data")));
+static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd); +static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *); +static void hsi2c_ch_init(struct s3c24x0_i2c_bus *); + /** * Get a pointer to the given bus index * * @bus_idx: Bus index to look up * @return pointer to bus, or NULL if invalid or not available */ -static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx) +static struct s3c24x0_i2c_bus *s3c_i2c_get_bus(struct i2c_adapter *adap) { - if (bus_idx < ARRAY_SIZE(i2c_bus)) { - struct s3c24x0_i2c_bus *bus; + struct s3c24x0_i2c_bus *bus;
- bus = &i2c_bus[bus_idx]; - if (bus->active) - return bus; - } + bus = &i2c_controllers[adap->hwadapnr]; + if (bus->active) + return bus;
- debug("Undefined bus: %d\n", bus_idx); + debug("Undefined bus: %d\n", adap->hwadapnr); return NULL; }
+static unsigned int s3c_i2c_set_bus_speed(struct i2c_adapter *adap, + unsigned int speed) +{ + struct s3c24x0_i2c_bus *i2c_bus; + + i2c_bus = s3c_i2c_get_bus(adap); + if (!i2c_bus) + return -1; + i2c_bus->clock_frequency = speed; + + if (i2c_bus->is_highspeed) { + if (hsi2c_get_clk_details(i2c_bus)) + return -1; + hsi2c_ch_init(i2c_bus); + } else { + i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency, + CONFIG_SYS_I2C_SLAVE); + } + + return 0; +} + +static void exynos_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); + i2c_set_bus_speed(speed); +} + #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) { @@ -399,41 +430,8 @@ static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus) hsi2c_ch_init(i2c_bus); }
-/* - * MULTI BUS I2C support - */ - -#ifdef CONFIG_I2C_MULTI_BUS -int i2c_set_bus_num(unsigned int bus) -{ - struct s3c24x0_i2c_bus *i2c_bus; - - i2c_bus = get_bus(bus); - if (!i2c_bus) - return -1; - g_current_bus = bus; - - if (i2c_bus->is_highspeed) { - if (hsi2c_get_clk_details(i2c_bus)) - return -1; - hsi2c_ch_init(i2c_bus); - } else { - i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency, - CONFIG_SYS_I2C_SLAVE); - } - - return 0; -} - -unsigned int i2c_get_bus_num(void) -{ - return g_current_bus; -} -#endif - -void i2c_init(int speed, int slaveadd) +static void s3c_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) { - int i; struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -457,6 +455,8 @@ void i2c_init(int speed, int slaveadd) }
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) + int i; + if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) { #ifdef CONFIG_S3C2410 ulong old_gpecon = readl(&gpio->gpecon); @@ -501,7 +501,10 @@ void i2c_init(int speed, int slaveadd) #endif } #endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */ - i2c_ch_init(i2c, speed, slaveadd); + + /* This will override the speed selected in the fdt for that port */ + debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr); + i2c_ch_init(i2c, speed, slaveaddr); }
/* @@ -837,13 +840,13 @@ bailout: return result; }
-int i2c_probe(uchar chip) +int s3c_i2c_probe(struct i2c_adapter *adap, uchar chip) { struct s3c24x0_i2c_bus *i2c_bus; uchar buf[1]; int ret;
- i2c_bus = get_bus(g_current_bus); + i2c_bus = s3c_i2c_get_bus(adap); if (!i2c_bus) return -1; buf[0] = 0; @@ -865,7 +868,8 @@ int i2c_probe(uchar chip) return ret != I2C_OK; }
-int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +int s3c_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, int alen, + uchar *buffer, int len) { struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; @@ -899,7 +903,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif - i2c_bus = get_bus(g_current_bus); + i2c_bus = s3c_i2c_get_bus(adap); if (!i2c_bus) return -1;
@@ -919,7 +923,8 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) return 0; }
-int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +int s3c_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, int alen, + uchar *buffer, int len) { struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; @@ -952,7 +957,7 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); #endif - i2c_bus = get_bus(g_current_bus); + i2c_bus = s3c_i2c_get_bus(adap); if (!i2c_bus) return -1;
@@ -985,7 +990,7 @@ static void process_nodes(const void *blob, int node_list[], int count, if (node <= 0) continue;
- bus = &i2c_bus[i]; + bus = &i2c_controllers[i]; bus->active = true; bus->is_highspeed = is_highspeed;
@@ -1025,15 +1030,14 @@ void board_i2c_init(const void *blob) COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, CONFIG_MAX_I2C_NUM); process_nodes(blob, node_list, count, 1); - }
int i2c_get_bus_num_fdt(int node) { int i;
- for (i = 0; i < ARRAY_SIZE(i2c_bus); i++) { - if (node == i2c_bus[i].node) + for (i = 0; i < ARRAY_SIZE(i2c_controllers); i++) { + if (node == i2c_controllers[i].node) return i; }
@@ -1052,8 +1056,8 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
- i2c_bus = get_bus(bus); - if (!i2c_bus) { + i2c_bus = &i2c_controllers[bus]; + if (!i2c_bus->active) { debug("get_bus() failed for node node %d\n", node); return -1; } @@ -1071,4 +1075,79 @@ int i2c_reset_port_fdt(const void *blob, int node) } #endif
-#endif /* CONFIG_HARD_I2C */ +/* + * Register soft i2c adapters + */ +#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 8) +U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 9) +U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 10) +#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 8) +U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 9) +U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 10) +#else +U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 0) +#endif