[U-Boot] [PATCH] i2c: s3c24xx: add hsi2c controller support

Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com --- drivers/i2c/s3c24x0_i2c.c | 389 ++++++++++++++++++++++++++++++++++++++++++--- drivers/i2c/s3c24x0_i2c.h | 33 ++++ 2 files changed, 397 insertions(+), 25 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 769a2ba..3117ab7 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -32,6 +32,7 @@ #include <asm/arch/clk.h> #include <asm/arch/cpu.h> #include <asm/arch/pinmux.h> +#include <asm/arch/clock.h> #else #include <asm/arch/s3c24x0_cpu.h> #endif @@ -50,6 +51,60 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */ + +/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31) + +/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4) + +/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff) + +/* I2C_INT_EN Register bits */ +#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) +#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9) + +/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29) + +/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31) + +/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31) + +/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_DONE (1u << 0) +#define HSI2C_TIMEOUT_AUTO (0u << 0) + +#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) + +/* Controller operating frequency, timing values for operation + * are calculated against this frequency + */ +#define HSI2C_FS_TX_CLOCK 1000000 + +/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -61,6 +116,7 @@
#define I2C_TIMEOUT 1 /* 1 second */
+#define HSI2C_TIMEOUT 100
/* * For SPL boot some boards need i2c before SDRAM is initialised so force @@ -120,9 +176,23 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; }
-static int IsACK(struct s3c24x0_i2c *i2c) +static int hsi2c_wait_for_irq(struct exynos5_hsi2c *i2c) { - return !(readl(&i2c->iicstat) & I2CSTAT_NACK); + int i = HSI2C_TIMEOUT * 10; + int ret = I2C_NOK_TOUT; + + while (i > 0) { + /* wait for a while and retry */ + udelay(50); + if (readl(&i2c->usi_int_stat) & + (HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN)) { + ret = I2C_OK; + break; + } + i--; + } + + return ret; }
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -130,6 +200,22 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c) writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); }
+static void hsi2c_clear_irqpd(struct exynos5_hsi2c *i2c) +{ + writel(readl(&i2c->usi_int_stat), &i2c->usi_int_stat); +} + +static int hsi2c_isack(struct exynos5_hsi2c *i2c) +{ + return readl(&i2c->usi_trans_status) & + (HSI2C_NO_DEV | HSI2C_NO_DEV_ACK); +} + +static int IsACK(struct s3c24x0_i2c *i2c) +{ + return !(readl(&i2c->iicstat) & I2CSTAT_NACK); +} + static struct s3c24x0_i2c *get_base_i2c(void) { #ifdef CONFIG_EXYNOS4 @@ -147,6 +233,18 @@ static struct s3c24x0_i2c *get_base_i2c(void) #endif }
+static struct exynos5_hsi2c *get_base_hsi2c(void) +{ + struct exynos5_hsi2c *i2c = NULL; + int bus = g_current_bus; + + if (proid_is_exynos5420()) + i2c = (struct exynos5_hsi2c *)(EXYNOS5420_I2C_BASE + + ((bus) * EXYNOS5_I2C_SPACING)); + + return i2c; +} + static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) { ulong freq, pres = 16, div; @@ -174,6 +272,74 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static void hsi2c_ch_init(struct exynos5_hsi2c *i2c, int speed) +{ + u32 i2c_timeout; + ulong clkin = get_i2c_clk(); + u32 i2c_timing_s1; + u32 i2c_timing_s2; + u32 i2c_timing_s3; + u32 i2c_timing_sla; + unsigned int op_clk = HSI2C_FS_TX_CLOCK; + unsigned int n_clkdiv; + unsigned int t_start_su, t_start_hd; + unsigned int t_stop_su; + unsigned int t_data_su, t_data_hd; + unsigned int t_scl_l, t_scl_h; + unsigned int t_sr_release; + unsigned int t_ftl_cycle; + unsigned int i = 0, utemp0 = 0, utemp1 = 0, utemp2 = 0; + + /* FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE + * uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * uTemp1 = (TSCLK_L + TSCLK_H + 2) + * uTemp2 = TSCLK_L + TSCLK_H + */ + t_ftl_cycle = (readl(&i2c->usi_conf) >> 16) & 0x7; + utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; + + /* CLK_DIV max is 256 */ + for (i = 0; i < 256; i++) { + utemp1 = utemp0 / (i + 1); + /* SCLK_L/H max is 256 / 2 */ + if (utemp1 < 128) { + utemp2 = utemp1 - 2; + break; + } + } + + n_clkdiv = i; + t_scl_l = utemp2 / 2; + t_scl_h = utemp2 / 2; + t_start_su = t_scl_l; + t_start_hd = t_scl_l; + t_stop_su = t_scl_l; + t_data_su = t_scl_l / 2; + t_data_hd = t_scl_l / 2; + t_sr_release = utemp2; + + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; + i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0; + i2c_timing_sla = t_data_hd << 0; + + writel(HSI2C_TRAILING_COUNT, &i2c->usi_trailing_ctl); + + /* Clear to enable Timeout */ + i2c_timeout = readl(&i2c->usi_timeout); + i2c_timeout &= ~HSI2C_TIMEOUT_EN; + writel(i2c_timeout, &i2c->usi_timeout); + + writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf); + + /* Currently operating in Fast speed mode. */ + writel(i2c_timing_s1, &i2c->usi_timing_fs1); + writel(i2c_timing_s2, &i2c->usi_timing_fs2); + writel(i2c_timing_s3, &i2c->usi_timing_fs3); + writel(i2c_timing_sla, &i2c->usi_timing_sla); +} + /* * MULTI BUS I2C support */ @@ -181,16 +347,18 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) { - struct s3c24x0_i2c *i2c; - if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { debug("Bad bus: %d\n", bus); return -1; }
g_current_bus = bus; - i2c = get_base_i2c(); - i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + if (proid_is_exynos5420() && (bus > 3)) { + hsi2c_ch_init(get_base_hsi2c(), + CONFIG_SYS_I2C_SPEED); + } else + i2c_ch_init(get_base_i2c(), CONFIG_SYS_I2C_SPEED, + CONFIG_SYS_I2C_SLAVE);
return 0; } @@ -269,24 +437,182 @@ void i2c_init(int speed, int slaveadd) }
/* + * Send a STOP event and wait for it to have completed + * + * @param mode If it is a master transmitter or receiver + * @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT otherwise + */ +static int hsi2c_send_stop(struct exynos5_hsi2c *i2c, int result) +{ + int timeout; + int ret = I2C_NOK_TOUT; + + /* Wait for the STOP to send and the bus to go idle */ + for (timeout = HSI2C_TIMEOUT; timeout > 0; timeout -= 5) { + if (!(readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY)) { + ret = I2C_OK; + goto out; + } + udelay(5); + } + out: + /* Setting the STOP event to fire */ + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); + writel(0x0, &i2c->usi_int_en); + + return (result == I2C_OK) ? ret : result; +} + +static int hsi2c_write(unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len) +{ + struct exynos5_hsi2c *i2c = get_base_hsi2c(); + int i = 0, result = I2C_OK; + u32 i2c_auto_conf; + u32 stat; + + /* Check I2C bus idle */ + i = HSI2C_TIMEOUT * 20; + while ((readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY) + && (i > 0)) { + udelay(50); + i--; + } + + stat = readl(&i2c->usi_trans_status); + + if (stat & HSI2C_MASTER_BUSY) { + debug("%s: bus busy\n", __func__); + return I2C_NOK_TOUT; + } + /* Disable TXFIFO and RXFIFO */ + writel(0, &i2c->usi_fifo_ctl); + + /* chip address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + /* Enable interrupts */ + writel((HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN), + &i2c->usi_int_en); + + /* usi_ctl enable i2c func, master write configure */ + writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* i2c_conf configure */ + writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf); + + /* auto_conf for write length and stop configure */ + i2c_auto_conf = ((len + alen) | HSI2C_STOP_AFTER_TRANS); + i2c_auto_conf &= ~HSI2C_READ_WRITE; + writel(i2c_auto_conf, &i2c->usi_auto_conf); + + /* Master run, start xfer */ + writel(readl(&i2c->usi_auto_conf) | HSI2C_MASTER_RUN, + &i2c->usi_auto_conf); + + result = hsi2c_wait_for_irq(i2c); + if ((result == I2C_OK) && hsi2c_isack(i2c)) { + result = I2C_NACK; + goto err; + } + + for (i = 0; i < alen && (result == I2C_OK); i++) { + writel(addr[i], &i2c->usi_txdata); + result = hsi2c_wait_for_irq(i2c); + } + + for (i = 0; i < len && (result == I2C_OK); i++) { + writel(data[i], &i2c->usi_txdata); + result = hsi2c_wait_for_irq(i2c); + } + + err: + hsi2c_clear_irqpd(i2c); + return hsi2c_send_stop(i2c, result); +} + +static int hsi2c_read(unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len, + int check) +{ + struct exynos5_hsi2c *i2c = get_base_hsi2c(); + int i, result; + u32 i2c_auto_conf; + + if (!check) { + result = hsi2c_write(chip, addr, alen, data, 0); + if (result != I2C_OK) { + debug("write failed Result = %d\n", result); + return result; + } + } + + /* start read */ + /* Disable TXFIFO and RXFIFO */ + writel(0, &i2c->usi_fifo_ctl); + + /* chip address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + /* Enable interrupts */ + writel(HSI2C_INT_I2C_EN, &i2c->usi_int_en); + + /* i2c_conf configure */ + writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf); + + /* auto_conf, length and stop configure */ + i2c_auto_conf = (len | HSI2C_STOP_AFTER_TRANS | HSI2C_READ_WRITE); + writel(i2c_auto_conf, &i2c->usi_auto_conf); + + /* usi_ctl enable i2c func, master WRITE configure */ + writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* Master run, start xfer */ + writel(readl(&i2c->usi_auto_conf) | HSI2C_MASTER_RUN, + &i2c->usi_auto_conf); + + result = hsi2c_wait_for_irq(i2c); + if ((result == I2C_OK) && hsi2c_isack(i2c)) { + result = I2C_NACK; + goto err; + } + + for (i = 0; i < len && (result == I2C_OK); i++) { + result = hsi2c_wait_for_irq(i2c); + data[i] = readl(&i2c->usi_rxdata); + } + err: + /* Stop and quit */ + hsi2c_clear_irqpd(i2c); + return hsi2c_send_stop(i2c, result); +} + +/* * cmd_type is 0 for write, 1 for read. * * addr_len can take any value from 0-255, it is only limited * by the char, we could make it larger if needed. If it is * 0 we skip the address write cycle. */ -static int i2c_transfer(struct s3c24x0_i2c *i2c, - unsigned char cmd_type, +static int i2c_transfer(unsigned char cmd_type, unsigned char chip, unsigned char addr[], unsigned char addr_len, unsigned char data[], unsigned short data_len) { + struct s3c24x0_i2c *i2c = get_base_i2c(); int i, result;
if (data == 0 || data_len == 0) { - /*Don't support data transfer of no length or to address 0 */ debug("i2c_transfer: bad call\n"); return I2C_NOK; } @@ -428,10 +754,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
int i2c_probe(uchar chip) { - struct s3c24x0_i2c *i2c; uchar buf[1];
- i2c = get_base_i2c(); buf[0] = 0;
/* @@ -439,12 +763,15 @@ 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(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; + if (proid_is_exynos5420() && (g_current_bus > 3)) + return (hsi2c_read(chip, 0, 1, buf, 1, 1) != I2C_OK); + else + return i2c_transfer( + I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; uchar xaddr[4]; int ret;
@@ -476,9 +803,13 @@ 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 = get_base_i2c(); - ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len); + if (proid_is_exynos5420() && (g_current_bus > 3)) + ret = hsi2c_read(chip, &xaddr[4 - alen], + alen, buffer, len, 0); + else + ret = i2c_transfer(I2C_READ, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + if (ret != 0) { debug("I2c read: failed %d\n", ret); return 1; @@ -488,7 +819,6 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; uchar xaddr[4];
if (alen > 4) { @@ -518,31 +848,36 @@ 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 = get_base_i2c(); - return (i2c_transfer - (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, - len) != 0); + if (proid_is_exynos5420() && (g_current_bus > 3)) + return (hsi2c_write(chip, &xaddr[4 - alen], + alen, buffer, len) != 0); + else + return (i2c_transfer(I2C_WRITE, chip << 1, + &xaddr[4 - alen], alen, buffer, len) != 0); }
#ifdef CONFIG_OF_CONTROL void board_i2c_init(const void *blob) { + struct s3c24x0_i2c_bus *bus; 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"); + fdtdec_get_addr(blob, node, "reg"); + bus->hsregs = (struct exynos5_hsi2c *) + fdtdec_get_addr(blob, node, "reg"); + bus->id = pinmux_decode_periph_id(blob, node); bus->node = node; bus->bus_num = i2c_busses++; @@ -589,7 +924,11 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
- i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + if (proid_is_exynos5420() && (bus > 3)) + hsi2c_ch_init(i2c->hsregs, CONFIG_SYS_I2C_SPEED); + else + i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, + CONFIG_SYS_I2C_SLAVE);
return 0; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index a56d749..81ed19c 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -31,10 +31,43 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c { + u32 usi_ctl; + u32 usi_fifo_ctl; + u32 usi_trailing_ctl; + u32 usi_clk_ctl; + u32 usi_clk_slot; + u32 spi_ctl; + u32 uart_ctl; + u32 res1; + u32 usi_int_en; + u32 usi_int_stat; + u32 usi_modem_stat; + u32 usi_error_stat; + u32 usi_fifo_stat; + u32 usi_txdata; + u32 usi_rxdata; + u32 res2; + u32 usi_conf; + u32 usi_auto_conf; + u32 usi_timeout; + u32 usi_manual_cmd; + u32 usi_trans_status; + u32 usi_timing_hs1; + u32 usi_timing_hs2; + u32 usi_timing_hs3; + u32 usi_timing_fs1; + u32 usi_timing_fs2; + u32 usi_timing_fs3; + u32 usi_timing_sla; + u32 i2c_addr; +}; + struct s3c24x0_i2c_bus { int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs; + struct exynos5_hsi2c *hsregs; int id; }; #endif /* _S3C24X0_I2C_H */

Hi Naveen,
On Tue, Mar 12, 2013 at 3:58 AM, Naveen Krishna Chatradhi < ch.naveen@samsung.com> wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com
I just commented on the Linux driver, so some comments may apply here also.
drivers/i2c/s3c24x0_i2c.c | 389 ++++++++++++++++++++++++++++++++++++++++++--- drivers/i2c/s3c24x0_i2c.h | 33 ++++ 2 files changed, 397 insertions(+), 25 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 769a2ba..3117ab7 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -32,6 +32,7 @@ #include <asm/arch/clk.h> #include <asm/arch/cpu.h> #include <asm/arch/pinmux.h> +#include <asm/arch/clock.h> #else #include <asm/arch/s3c24x0_cpu.h> #endif @@ -50,6 +51,60 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */
+/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31)
+/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4)
+/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff)
+/* I2C_INT_EN Register bits */ +#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) +#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9)
+/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29)
+/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31)
+/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31)
+/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_DONE (1u << 0) +#define HSI2C_TIMEOUT_AUTO (0u << 0)
+#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10)
+/* Controller operating frequency, timing values for operation
- are calculated against this frequency
- */
+#define HSI2C_FS_TX_CLOCK 1000000
+/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -61,6 +116,7 @@
#define I2C_TIMEOUT 1 /* 1 second */
+#define HSI2C_TIMEOUT 100
/*
- For SPL boot some boards need i2c before SDRAM is initialised so force
@@ -120,9 +176,23 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; }
-static int IsACK(struct s3c24x0_i2c *i2c) +static int hsi2c_wait_for_irq(struct exynos5_hsi2c *i2c) {
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
int i = HSI2C_TIMEOUT * 10;
int ret = I2C_NOK_TOUT;
while (i > 0) {
/* wait for a while and retry */
udelay(50);
if (readl(&i2c->usi_int_stat) &
(HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN)) {
ret = I2C_OK;
break;
}
i--;
Please can we use the get_timer() method for timeouts instead of udelay()?
}
return ret;
}
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -130,6 +200,22 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c) writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); }
+static void hsi2c_clear_irqpd(struct exynos5_hsi2c *i2c) +{
writel(readl(&i2c->usi_int_stat), &i2c->usi_int_stat);
+}
+static int hsi2c_isack(struct exynos5_hsi2c *i2c) +{
return readl(&i2c->usi_trans_status) &
(HSI2C_NO_DEV | HSI2C_NO_DEV_ACK);
+}
+static int IsACK(struct s3c24x0_i2c *i2c)
There are two functions - hsi2c_isack() and IsAck(). What is the difference?
+{
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
+}
static struct s3c24x0_i2c *get_base_i2c(void) { #ifdef CONFIG_EXYNOS4 @@ -147,6 +233,18 @@ static struct s3c24x0_i2c *get_base_i2c(void) #endif }
+static struct exynos5_hsi2c *get_base_hsi2c(void) +{
struct exynos5_hsi2c *i2c = NULL;
int bus = g_current_bus;
if (proid_is_exynos5420())
i2c = (struct exynos5_hsi2c *)(EXYNOS5420_I2C_BASE +
((bus) * EXYNOS5_I2C_SPACING));
return i2c;
+}
This should come from the device tree information that you are decoding (the ->reg property).
static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) { ulong freq, pres = 16, div; @@ -174,6 +272,74 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static void hsi2c_ch_init(struct exynos5_hsi2c *i2c, int speed) +{
u32 i2c_timeout;
ulong clkin = get_i2c_clk();
u32 i2c_timing_s1;
u32 i2c_timing_s2;
u32 i2c_timing_s3;
u32 i2c_timing_sla;
unsigned int op_clk = HSI2C_FS_TX_CLOCK;
unsigned int n_clkdiv;
unsigned int t_start_su, t_start_hd;
unsigned int t_stop_su;
unsigned int t_data_su, t_data_hd;
unsigned int t_scl_l, t_scl_h;
unsigned int t_sr_release;
unsigned int t_ftl_cycle;
unsigned int i = 0, utemp0 = 0, utemp1 = 0, utemp2 = 0;
/* FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
* uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
* uTemp1 = (TSCLK_L + TSCLK_H + 2)
* uTemp2 = TSCLK_L + TSCLK_H
*/
t_ftl_cycle = (readl(&i2c->usi_conf) >> 16) & 0x7;
utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle;
/* CLK_DIV max is 256 */
for (i = 0; i < 256; i++) {
utemp1 = utemp0 / (i + 1);
/* SCLK_L/H max is 256 / 2 */
if (utemp1 < 128) {
utemp2 = utemp1 - 2;
break;
}
}
n_clkdiv = i;
t_scl_l = utemp2 / 2;
t_scl_h = utemp2 / 2;
t_start_su = t_scl_l;
t_start_hd = t_scl_l;
t_stop_su = t_scl_l;
t_data_su = t_scl_l / 2;
t_data_hd = t_scl_l / 2;
t_sr_release = utemp2;
i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su <<
8;
i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0;
i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0;
i2c_timing_sla = t_data_hd << 0;
writel(HSI2C_TRAILING_COUNT, &i2c->usi_trailing_ctl);
/* Clear to enable Timeout */
i2c_timeout = readl(&i2c->usi_timeout);
i2c_timeout &= ~HSI2C_TIMEOUT_EN;
writel(i2c_timeout, &i2c->usi_timeout);
writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf);
/* Currently operating in Fast speed mode. */
writel(i2c_timing_s1, &i2c->usi_timing_fs1);
writel(i2c_timing_s2, &i2c->usi_timing_fs2);
writel(i2c_timing_s3, &i2c->usi_timing_fs3);
writel(i2c_timing_sla, &i2c->usi_timing_sla);
+}
/*
- MULTI BUS I2C support
*/ @@ -181,16 +347,18 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) {
struct s3c24x0_i2c *i2c;
if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { debug("Bad bus: %d\n", bus); return -1; } g_current_bus = bus;
i2c = get_base_i2c();
i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
if (proid_is_exynos5420() && (bus > 3)) {
hsi2c_ch_init(get_base_hsi2c(),
CONFIG_SYS_I2C_SPEED);
} else
i2c_ch_init(get_base_i2c(), CONFIG_SYS_I2C_SPEED,
CONFIG_SYS_I2C_SLAVE); return 0;
} @@ -269,24 +437,182 @@ void i2c_init(int speed, int slaveadd) }
/*
- Send a STOP event and wait for it to have completed
- @param mode If it is a master transmitter or receiver
- @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT
otherwise
- */
+static int hsi2c_send_stop(struct exynos5_hsi2c *i2c, int result) +{
int timeout;
int ret = I2C_NOK_TOUT;
/* Wait for the STOP to send and the bus to go idle */
for (timeout = HSI2C_TIMEOUT; timeout > 0; timeout -= 5) {
if (!(readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY)) {
ret = I2C_OK;
goto out;
}
udelay(5);
}
- out:
/* Setting the STOP event to fire */
writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl);
writel(0x0, &i2c->usi_int_en);
return (result == I2C_OK) ? ret : result;
+}
+static int hsi2c_write(unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len)
+{
struct exynos5_hsi2c *i2c = get_base_hsi2c();
int i = 0, result = I2C_OK;
u32 i2c_auto_conf;
u32 stat;
/* Check I2C bus idle */
i = HSI2C_TIMEOUT * 20;
while ((readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY)
&& (i > 0)) {
udelay(50);
i--;
}
It seems like perhaps you should have a function to wait until not busy and call it from the above function, and here.
stat = readl(&i2c->usi_trans_status);
if (stat & HSI2C_MASTER_BUSY) {
debug("%s: bus busy\n", __func__);
return I2C_NOK_TOUT;
}
/* Disable TXFIFO and RXFIFO */
writel(0, &i2c->usi_fifo_ctl);
/* chip address */
writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
/* Enable interrupts */
writel((HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN),
&i2c->usi_int_en);
/* usi_ctl enable i2c func, master write configure */
writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
&i2c->usi_ctl);
/* i2c_conf configure */
writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf);
/* auto_conf for write length and stop configure */
i2c_auto_conf = ((len + alen) | HSI2C_STOP_AFTER_TRANS);
i2c_auto_conf &= ~HSI2C_READ_WRITE;
writel(i2c_auto_conf, &i2c->usi_auto_conf);
/* Master run, start xfer */
writel(readl(&i2c->usi_auto_conf) | HSI2C_MASTER_RUN,
&i2c->usi_auto_conf);
result = hsi2c_wait_for_irq(i2c);
if ((result == I2C_OK) && hsi2c_isack(i2c)) {
result = I2C_NACK;
goto err;
}
for (i = 0; i < alen && (result == I2C_OK); i++) {
writel(addr[i], &i2c->usi_txdata);
result = hsi2c_wait_for_irq(i2c);
}
for (i = 0; i < len && (result == I2C_OK); i++) {
writel(data[i], &i2c->usi_txdata);
result = hsi2c_wait_for_irq(i2c);
Do we have to wait for an irq after every tx byte?
}
- err:
hsi2c_clear_irqpd(i2c);
return hsi2c_send_stop(i2c, result);
+}
+static int hsi2c_read(unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len,
int check)
This seems to have a lot of common code with the above. Should they be joined up?
+{
struct exynos5_hsi2c *i2c = get_base_hsi2c();
int i, result;
u32 i2c_auto_conf;
if (!check) {
result = hsi2c_write(chip, addr, alen, data, 0);
if (result != I2C_OK) {
debug("write failed Result = %d\n", result);
return result;
}
}
/* start read */
/* Disable TXFIFO and RXFIFO */
writel(0, &i2c->usi_fifo_ctl);
/* chip address */
writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
/* Enable interrupts */
writel(HSI2C_INT_I2C_EN, &i2c->usi_int_en);
/* i2c_conf configure */
outdent
writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf);
/* auto_conf, length and stop configure */
i2c_auto_conf = (len | HSI2C_STOP_AFTER_TRANS | HSI2C_READ_WRITE);
writel(i2c_auto_conf, &i2c->usi_auto_conf);
/* usi_ctl enable i2c func, master WRITE configure */
writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
&i2c->usi_ctl);
/* Master run, start xfer */
writel(readl(&i2c->usi_auto_conf) | HSI2C_MASTER_RUN,
&i2c->usi_auto_conf);
result = hsi2c_wait_for_irq(i2c);
if ((result == I2C_OK) && hsi2c_isack(i2c)) {
result = I2C_NACK;
goto err;
}
for (i = 0; i < len && (result == I2C_OK); i++) {
result = hsi2c_wait_for_irq(i2c);
data[i] = readl(&i2c->usi_rxdata);
}
I suppose the FIFOs are not used here. How larger are the FIFOs?
- err:
/* Stop and quit */
hsi2c_clear_irqpd(i2c);
return hsi2c_send_stop(i2c, result);
+}
+/*
- cmd_type is 0 for write, 1 for read.
- addr_len can take any value from 0-255, it is only limited
- by the char, we could make it larger if needed. If it is
- 0 we skip the address write cycle.
*/ -static int i2c_transfer(struct s3c24x0_i2c *i2c,
unsigned char cmd_type,
+static int i2c_transfer(unsigned char cmd_type, unsigned char chip, unsigned char addr[], unsigned char addr_len, unsigned char data[], unsigned short data_len) {
struct s3c24x0_i2c *i2c = get_base_i2c(); int i, result; if (data == 0 || data_len == 0) {
/*Don't support data transfer of no length or to address 0
*/ debug("i2c_transfer: bad call\n"); return I2C_NOK; } @@ -428,10 +754,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
int i2c_probe(uchar chip) {
struct s3c24x0_i2c *i2c; uchar buf[1];
i2c = get_base_i2c(); buf[0] = 0; /*
@@ -439,12 +763,15 @@ 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(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) !=
I2C_OK;
if (proid_is_exynos5420() && (g_current_bus > 3))
return (hsi2c_read(chip, 0, 1, buf, 1, 1) != I2C_OK);
I think the type of i2c port should be set by the FDT, not hard-coded according to the chip type.
else
return i2c_transfer(
I2C_READ, chip << 1, 0, 0, buf, 1) !=
I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) {
struct s3c24x0_i2c *i2c; uchar xaddr[4]; int ret;
@@ -476,9 +803,13 @@ 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 = get_base_i2c();
ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen],
alen,
buffer, len);
if (proid_is_exynos5420() && (g_current_bus > 3))
ret = hsi2c_read(chip, &xaddr[4 - alen],
alen, buffer, len, 0);
+ else
ret = i2c_transfer(I2C_READ, chip << 1,
&xaddr[4 - alen], alen, buffer, len);
if (ret != 0) { debug("I2c read: failed %d\n", ret); return 1;
@@ -488,7 +819,6 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) {
struct s3c24x0_i2c *i2c; uchar xaddr[4]; if (alen > 4) {
@@ -518,31 +848,36 @@ 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 = get_base_i2c();
return (i2c_transfer
(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
len) != 0);
if (proid_is_exynos5420() && (g_current_bus > 3))
return (hsi2c_write(chip, &xaddr[4 - alen],
alen, buffer, len) != 0);
else
return (i2c_transfer(I2C_WRITE, chip << 1,
&xaddr[4 - alen], alen, buffer, len) != 0);
}
#ifdef CONFIG_OF_CONTROL void board_i2c_init(const void *blob) {
struct s3c24x0_i2c_bus *bus; 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");
fdtdec_get_addr(blob, node, "reg");
Here you have bus->regs so you should use it in the driver.
bus->hsregs = (struct exynos5_hsi2c *)
fdtdec_get_addr(blob, node, "reg");
All of the ports here will be COMPAT_SAMSUNG_S3C2440_I2C. I think you need to find ports of a different type for the high speed i2c. Perhaps look at how tegra i2c handles having two different node types in the same driver.
The type of a port needs to be stored in the bus structure, and I think this should be done even in the non-FDT case, to simplify the code.
bus->id = pinmux_decode_periph_id(blob, node); bus->node = node; bus->bus_num = i2c_busses++;
@@ -589,7 +924,11 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
if (proid_is_exynos5420() && (bus > 3))
hsi2c_ch_init(i2c->hsregs, CONFIG_SYS_I2C_SPEED);
else
i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED,
CONFIG_SYS_I2C_SLAVE); return 0;
} diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index a56d749..81ed19c 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -31,10 +31,43 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c {
u32 usi_ctl;
u32 usi_fifo_ctl;
u32 usi_trailing_ctl;
u32 usi_clk_ctl;
u32 usi_clk_slot;
u32 spi_ctl;
u32 uart_ctl;
u32 res1;
u32 usi_int_en;
u32 usi_int_stat;
u32 usi_modem_stat;
u32 usi_error_stat;
u32 usi_fifo_stat;
u32 usi_txdata;
u32 usi_rxdata;
u32 res2;
u32 usi_conf;
u32 usi_auto_conf;
u32 usi_timeout;
u32 usi_manual_cmd;
u32 usi_trans_status;
u32 usi_timing_hs1;
u32 usi_timing_hs2;
u32 usi_timing_hs3;
u32 usi_timing_fs1;
u32 usi_timing_fs2;
u32 usi_timing_fs3;
u32 usi_timing_sla;
u32 i2c_addr;
+};
struct s3c24x0_i2c_bus { int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs;
struct exynos5_hsi2c *hsregs; int id;
};
#endif /* _S3C24X0_I2C_H */
1.7.9.5
Regards,
Simon

On 12 March 2013 22:11, Simon Glass sjg@chromium.org wrote:
Hi Naveen,
On Tue, Mar 12, 2013 at 3:58 AM, Naveen Krishna Chatradhi < ch.naveen@samsung.com> wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com
I just commented on the Linux driver, so some comments may apply here also.
drivers/i2c/s3c24x0_i2c.c | 389 ++++++++++++++++++++++++++++++++++++++++++--- drivers/i2c/s3c24x0_i2c.h | 33 ++++ 2 files changed, 397 insertions(+), 25 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 769a2ba..3117ab7 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -32,6 +32,7 @@ #include <asm/arch/clk.h> #include <asm/arch/cpu.h> #include <asm/arch/pinmux.h> +#include <asm/arch/clock.h> #else #include <asm/arch/s3c24x0_cpu.h> #endif @@ -50,6 +51,60 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */
+/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31)
+/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4)
+/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff)
+/* I2C_INT_EN Register bits */ +#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) +#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9)
+/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29)
+/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31)
+/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31)
+/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_DONE (1u << 0) +#define HSI2C_TIMEOUT_AUTO (0u << 0)
+#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10)
+/* Controller operating frequency, timing values for operation
- are calculated against this frequency
- */
+#define HSI2C_FS_TX_CLOCK 1000000
+/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -61,6 +116,7 @@
#define I2C_TIMEOUT 1 /* 1 second */
+#define HSI2C_TIMEOUT 100
/*
- For SPL boot some boards need i2c before SDRAM is initialised so force
@@ -120,9 +176,23 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; }
-static int IsACK(struct s3c24x0_i2c *i2c) +static int hsi2c_wait_for_irq(struct exynos5_hsi2c *i2c) {
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
int i = HSI2C_TIMEOUT * 10;
int ret = I2C_NOK_TOUT;
while (i > 0) {
/* wait for a while and retry */
udelay(50);
if (readl(&i2c->usi_int_stat) &
(HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN)) {
ret = I2C_OK;
break;
}
i--;
Please can we use the get_timer() method for timeouts instead of udelay()?
Sure thing
}
return ret;
}
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -130,6 +200,22 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c) writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); }
+static void hsi2c_clear_irqpd(struct exynos5_hsi2c *i2c) +{
writel(readl(&i2c->usi_int_stat), &i2c->usi_int_stat);
+}
+static int hsi2c_isack(struct exynos5_hsi2c *i2c) +{
return readl(&i2c->usi_trans_status) &
(HSI2C_NO_DEV | HSI2C_NO_DEV_ACK);
+}
+static int IsACK(struct s3c24x0_i2c *i2c)
There are two functions - hsi2c_isack() and IsAck(). What is the difference?
There are 3 similar functions re-written for I2C and HSI2C. May be i can use one function once the DT is completely implemented in this driver
+{
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
+}
static struct s3c24x0_i2c *get_base_i2c(void) { #ifdef CONFIG_EXYNOS4 @@ -147,6 +233,18 @@ static struct s3c24x0_i2c *get_base_i2c(void) #endif }
+static struct exynos5_hsi2c *get_base_hsi2c(void) +{
struct exynos5_hsi2c *i2c = NULL;
int bus = g_current_bus;
if (proid_is_exynos5420())
i2c = (struct exynos5_hsi2c *)(EXYNOS5420_I2C_BASE +
((bus) * EXYNOS5_I2C_SPACING));
return i2c;
+}
This should come from the device tree information that you are decoding (the ->reg property).
I've not used the DT yet. I just followed the legacy code in the driver. Will implement it and send v2 soon.
static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) { ulong freq, pres = 16, div; @@ -174,6 +272,74 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static void hsi2c_ch_init(struct exynos5_hsi2c *i2c, int speed) +{
u32 i2c_timeout;
ulong clkin = get_i2c_clk();
u32 i2c_timing_s1;
u32 i2c_timing_s2;
u32 i2c_timing_s3;
u32 i2c_timing_sla;
unsigned int op_clk = HSI2C_FS_TX_CLOCK;
unsigned int n_clkdiv;
unsigned int t_start_su, t_start_hd;
unsigned int t_stop_su;
unsigned int t_data_su, t_data_hd;
unsigned int t_scl_l, t_scl_h;
unsigned int t_sr_release;
unsigned int t_ftl_cycle;
unsigned int i = 0, utemp0 = 0, utemp1 = 0, utemp2 = 0;
/* FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
* uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
* uTemp1 = (TSCLK_L + TSCLK_H + 2)
* uTemp2 = TSCLK_L + TSCLK_H
*/
t_ftl_cycle = (readl(&i2c->usi_conf) >> 16) & 0x7;
utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle;
/* CLK_DIV max is 256 */
for (i = 0; i < 256; i++) {
utemp1 = utemp0 / (i + 1);
/* SCLK_L/H max is 256 / 2 */
if (utemp1 < 128) {
utemp2 = utemp1 - 2;
break;
}
}
n_clkdiv = i;
t_scl_l = utemp2 / 2;
t_scl_h = utemp2 / 2;
t_start_su = t_scl_l;
t_start_hd = t_scl_l;
t_stop_su = t_scl_l;
t_data_su = t_scl_l / 2;
t_data_hd = t_scl_l / 2;
t_sr_release = utemp2;
i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su <<
8;
i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0;
i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0;
i2c_timing_sla = t_data_hd << 0;
writel(HSI2C_TRAILING_COUNT, &i2c->usi_trailing_ctl);
/* Clear to enable Timeout */
i2c_timeout = readl(&i2c->usi_timeout);
i2c_timeout &= ~HSI2C_TIMEOUT_EN;
writel(i2c_timeout, &i2c->usi_timeout);
writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf);
/* Currently operating in Fast speed mode. */
writel(i2c_timing_s1, &i2c->usi_timing_fs1);
writel(i2c_timing_s2, &i2c->usi_timing_fs2);
writel(i2c_timing_s3, &i2c->usi_timing_fs3);
writel(i2c_timing_sla, &i2c->usi_timing_sla);
+}
/*
- MULTI BUS I2C support
*/ @@ -181,16 +347,18 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) {
struct s3c24x0_i2c *i2c;
if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { debug("Bad bus: %d\n", bus); return -1; } g_current_bus = bus;
i2c = get_base_i2c();
i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
if (proid_is_exynos5420() && (bus > 3)) {
hsi2c_ch_init(get_base_hsi2c(),
CONFIG_SYS_I2C_SPEED);
} else
i2c_ch_init(get_base_i2c(), CONFIG_SYS_I2C_SPEED,
CONFIG_SYS_I2C_SLAVE); return 0;
} @@ -269,24 +437,182 @@ void i2c_init(int speed, int slaveadd) }
/*
- Send a STOP event and wait for it to have completed
- @param mode If it is a master transmitter or receiver
- @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT
otherwise
- */
+static int hsi2c_send_stop(struct exynos5_hsi2c *i2c, int result) +{
int timeout;
int ret = I2C_NOK_TOUT;
/* Wait for the STOP to send and the bus to go idle */
for (timeout = HSI2C_TIMEOUT; timeout > 0; timeout -= 5) {
if (!(readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY)) {
ret = I2C_OK;
goto out;
}
udelay(5);
}
- out:
/* Setting the STOP event to fire */
writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl);
writel(0x0, &i2c->usi_int_en);
return (result == I2C_OK) ? ret : result;
+}
+static int hsi2c_write(unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len)
+{
struct exynos5_hsi2c *i2c = get_base_hsi2c();
int i = 0, result = I2C_OK;
u32 i2c_auto_conf;
u32 stat;
/* Check I2C bus idle */
i = HSI2C_TIMEOUT * 20;
while ((readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY)
&& (i > 0)) {
udelay(50);
i--;
}
It seems like perhaps you should have a function to wait until not busy and call it from the above function, and here.
Sure.
stat = readl(&i2c->usi_trans_status);
if (stat & HSI2C_MASTER_BUSY) {
debug("%s: bus busy\n", __func__);
return I2C_NOK_TOUT;
}
/* Disable TXFIFO and RXFIFO */
writel(0, &i2c->usi_fifo_ctl);
/* chip address */
writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
/* Enable interrupts */
writel((HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN),
&i2c->usi_int_en);
/* usi_ctl enable i2c func, master write configure */
writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
&i2c->usi_ctl);
/* i2c_conf configure */
writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf);
/* auto_conf for write length and stop configure */
i2c_auto_conf = ((len + alen) | HSI2C_STOP_AFTER_TRANS);
i2c_auto_conf &= ~HSI2C_READ_WRITE;
writel(i2c_auto_conf, &i2c->usi_auto_conf);
/* Master run, start xfer */
writel(readl(&i2c->usi_auto_conf) | HSI2C_MASTER_RUN,
&i2c->usi_auto_conf);
result = hsi2c_wait_for_irq(i2c);
if ((result == I2C_OK) && hsi2c_isack(i2c)) {
result = I2C_NACK;
goto err;
}
for (i = 0; i < alen && (result == I2C_OK); i++) {
writel(addr[i], &i2c->usi_txdata);
result = hsi2c_wait_for_irq(i2c);
}
for (i = 0; i < len && (result == I2C_OK); i++) {
writel(data[i], &i2c->usi_txdata);
result = hsi2c_wait_for_irq(i2c);
Do we have to wait for an irq after every tx byte?
Actually, FIFOs were not implemented at all in the u-boot driver. FIFOs are 64 depth and of variable sizes. Will test with them enabled
}
- err:
hsi2c_clear_irqpd(i2c);
return hsi2c_send_stop(i2c, result);
+}
+static int hsi2c_read(unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len,
int check)
This seems to have a lot of common code with the above. Should they be joined up?
Common initialization code can be split out.
+{
struct exynos5_hsi2c *i2c = get_base_hsi2c();
int i, result;
u32 i2c_auto_conf;
if (!check) {
result = hsi2c_write(chip, addr, alen, data, 0);
if (result != I2C_OK) {
debug("write failed Result = %d\n", result);
return result;
}
}
/* start read */
/* Disable TXFIFO and RXFIFO */
writel(0, &i2c->usi_fifo_ctl);
/* chip address */
writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
/* Enable interrupts */
writel(HSI2C_INT_I2C_EN, &i2c->usi_int_en);
/* i2c_conf configure */
outdent
writel(readl(&i2c->usi_conf) | HSI2C_AUTO_MODE, &i2c->usi_conf);
/* auto_conf, length and stop configure */
i2c_auto_conf = (len | HSI2C_STOP_AFTER_TRANS | HSI2C_READ_WRITE);
writel(i2c_auto_conf, &i2c->usi_auto_conf);
/* usi_ctl enable i2c func, master WRITE configure */
writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER),
&i2c->usi_ctl);
/* Master run, start xfer */
writel(readl(&i2c->usi_auto_conf) | HSI2C_MASTER_RUN,
&i2c->usi_auto_conf);
result = hsi2c_wait_for_irq(i2c);
if ((result == I2C_OK) && hsi2c_isack(i2c)) {
result = I2C_NACK;
goto err;
}
for (i = 0; i < len && (result == I2C_OK); i++) {
result = hsi2c_wait_for_irq(i2c);
data[i] = readl(&i2c->usi_rxdata);
}
I suppose the FIFOs are not used here. How larger are the FIFOs?
- err:
/* Stop and quit */
hsi2c_clear_irqpd(i2c);
return hsi2c_send_stop(i2c, result);
+}
+/*
- cmd_type is 0 for write, 1 for read.
- addr_len can take any value from 0-255, it is only limited
- by the char, we could make it larger if needed. If it is
- 0 we skip the address write cycle.
*/ -static int i2c_transfer(struct s3c24x0_i2c *i2c,
unsigned char cmd_type,
+static int i2c_transfer(unsigned char cmd_type, unsigned char chip, unsigned char addr[], unsigned char addr_len, unsigned char data[], unsigned short data_len) {
struct s3c24x0_i2c *i2c = get_base_i2c(); int i, result; if (data == 0 || data_len == 0) {
/*Don't support data transfer of no length or to address 0
*/ debug("i2c_transfer: bad call\n"); return I2C_NOK; } @@ -428,10 +754,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
int i2c_probe(uchar chip) {
struct s3c24x0_i2c *i2c; uchar buf[1];
i2c = get_base_i2c(); buf[0] = 0; /*
@@ -439,12 +763,15 @@ 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(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) !=
I2C_OK;
if (proid_is_exynos5420() && (g_current_bus > 3))
return (hsi2c_read(chip, 0, 1, buf, 1, 1) != I2C_OK);
I think the type of i2c port should be set by the FDT, not hard-coded according to the chip type.
Will implement it, that would simplify a lot of checks for future aswell.
else
return i2c_transfer(
I2C_READ, chip << 1, 0, 0, buf, 1) !=
I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) {
struct s3c24x0_i2c *i2c; uchar xaddr[4]; int ret;
@@ -476,9 +803,13 @@ 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 = get_base_i2c();
ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen],
alen,
buffer, len);
if (proid_is_exynos5420() && (g_current_bus > 3))
ret = hsi2c_read(chip, &xaddr[4 - alen],
alen, buffer, len, 0);
else
ret = i2c_transfer(I2C_READ, chip << 1,
&xaddr[4 - alen], alen, buffer, len);
if (ret != 0) { debug("I2c read: failed %d\n", ret); return 1;
@@ -488,7 +819,6 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) {
struct s3c24x0_i2c *i2c; uchar xaddr[4]; if (alen > 4) {
@@ -518,31 +848,36 @@ 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 = get_base_i2c();
return (i2c_transfer
(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
len) != 0);
if (proid_is_exynos5420() && (g_current_bus > 3))
return (hsi2c_write(chip, &xaddr[4 - alen],
alen, buffer, len) != 0);
else
return (i2c_transfer(I2C_WRITE, chip << 1,
&xaddr[4 - alen], alen, buffer, len) != 0);
}
#ifdef CONFIG_OF_CONTROL void board_i2c_init(const void *blob) {
struct s3c24x0_i2c_bus *bus; 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");
fdtdec_get_addr(blob, node, "reg");
Here you have bus->regs so you should use it in the driver.
bus->hsregs = (struct exynos5_hsi2c *)
fdtdec_get_addr(blob, node, "reg");
All of the ports here will be COMPAT_SAMSUNG_S3C2440_I2C. I think you need to find ports of a different type for the high speed i2c. Perhaps look at how tegra i2c handles having two different node types in the same driver.
This would help Simon, Thanks.
The type of a port needs to be stored in the bus structure, and I think this should be done even in the non-FDT case, to simplify the code.
Right, Will go through the references and submit a v2 with the DT changes fixed.
bus->id = pinmux_decode_periph_id(blob, node); bus->node = node; bus->bus_num = i2c_busses++;
@@ -589,7 +924,11 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
if (proid_is_exynos5420() && (bus > 3))
hsi2c_ch_init(i2c->hsregs, CONFIG_SYS_I2C_SPEED);
else
i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED,
CONFIG_SYS_I2C_SLAVE); return 0;
} diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index a56d749..81ed19c 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -31,10 +31,43 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c {
u32 usi_ctl;
u32 usi_fifo_ctl;
u32 usi_trailing_ctl;
u32 usi_clk_ctl;
u32 usi_clk_slot;
u32 spi_ctl;
u32 uart_ctl;
u32 res1;
u32 usi_int_en;
u32 usi_int_stat;
u32 usi_modem_stat;
u32 usi_error_stat;
u32 usi_fifo_stat;
u32 usi_txdata;
u32 usi_rxdata;
u32 res2;
u32 usi_conf;
u32 usi_auto_conf;
u32 usi_timeout;
u32 usi_manual_cmd;
u32 usi_trans_status;
u32 usi_timing_hs1;
u32 usi_timing_hs2;
u32 usi_timing_hs3;
u32 usi_timing_fs1;
u32 usi_timing_fs2;
u32 usi_timing_fs3;
u32 usi_timing_sla;
u32 i2c_addr;
+};
struct s3c24x0_i2c_bus { int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs;
struct exynos5_hsi2c *hsregs; int id;
};
#endif /* _S3C24X0_I2C_H */
1.7.9.5
Regards,
Simon
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com Reviewed-by: Vadim Bendebury vbendeb@google.com Reviewed-by: Simon Glass sjg@google.com --- Changes since v3:
1. Implemented get_timer instead of while and udelay for master busy function 2. Use reg base address from device tree 3. Split the timing function to check for the errors 4. Implemented reset function for to recover from failure cases 5. Implemented a comat string for hsi2c to distingush the channels 6. Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 46d2506..32be91b 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -50,6 +50,60 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */ + +/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31) + +/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4) + +/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff) + +/* I2C_INT_EN Register bits */ +#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) +#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9) + +/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29) + +/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31) + +/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31) + +/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_DONE (1u << 0) +#define HSI2C_TIMEOUT_AUTO (0u << 0) + +#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) + +/* Controller operating frequency, timing values for operation + * are calculated against this frequency + */ +#define HSI2C_FS_TX_CLOCK 1000000 + +/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -61,6 +115,7 @@
#define I2C_TIMEOUT 1 /* 1 second */
+#define HSI2C_TIMEOUT 100
/* * For SPL boot some boards need i2c before SDRAM is initialised so force @@ -73,6 +128,15 @@ static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif
+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; +} + #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) { @@ -113,9 +177,23 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; }
-static int IsACK(struct s3c24x0_i2c *i2c) +static int hsi2c_wait_for_irq(struct exynos5_hsi2c *i2c) { - return !(readl(&i2c->iicstat) & I2CSTAT_NACK); + int i = HSI2C_TIMEOUT * 10; + int ret = I2C_NOK_TOUT; + + while (i > 0) { + /* wait for a while and retry */ + udelay(100); + if (readl(&i2c->usi_int_stat) & + (HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN)) { + ret = I2C_OK; + break; + } + i--; + } + + return ret; }
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -123,6 +201,22 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c) writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); }
+static void hsi2c_clear_irqpd(struct exynos5_hsi2c *i2c) +{ + writel(readl(&i2c->usi_int_stat), &i2c->usi_int_stat); +} + +static int hsi2c_isack(struct exynos5_hsi2c *i2c) +{ + return readl(&i2c->usi_trans_status) & + (HSI2C_NO_DEV | HSI2C_NO_DEV_ACK); +} + +static int IsACK(struct s3c24x0_i2c *i2c) +{ + return !(readl(&i2c->iicstat) & I2CSTAT_NACK); +} + static struct s3c24x0_i2c *get_base_i2c(void) { #ifdef CONFIG_EXYNOS4 @@ -167,6 +261,97 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + ulong clkin = get_i2c_clk(); + unsigned int op_clk = HSI2C_FS_TX_CLOCK; + unsigned int i = 0, utemp0 = 0, utemp1 = 0; + unsigned int t_ftl_cycle; + + /* FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE + * uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * uTemp1 = (TSCLK_L + TSCLK_H + 2) + * uTemp2 = TSCLK_L + TSCLK_H + */ + t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7; + utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; + + /* CLK_DIV max is 256 */ + for (i = 0; i < 256; i++) { + utemp1 = utemp0 / (i + 1); + if ((utemp1 < 512) && (utemp1 > 4)) { + i2c_bus->clk_cycle = utemp1 - 2; + i2c_bus->clk_div = i; + return 0; + } + } + return -1; +} + +static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + unsigned int t_sr_release; + unsigned int n_clkdiv; + unsigned int t_start_su, t_start_hd; + unsigned int t_stop_su; + unsigned int t_data_su, t_data_hd; + unsigned int t_scl_l, t_scl_h; + u32 i2c_timing_s1; + u32 i2c_timing_s2; + u32 i2c_timing_s3; + u32 i2c_timing_sla; + + n_clkdiv = i2c_bus->clk_div; + t_scl_l = i2c_bus->clk_cycle / 2; + t_scl_h = i2c_bus->clk_cycle / 2; + t_start_su = t_scl_l; + t_start_hd = t_scl_l; + t_stop_su = t_scl_l; + t_data_su = t_scl_l / 2; + t_data_hd = t_scl_l / 2; + t_sr_release = i2c_bus->clk_cycle; + + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; + i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0; + i2c_timing_sla = t_data_hd << 0; + + writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl); + + /* Clear to enable Timeout */ + clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0); + + writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf); + + /* Currently operating in Fast speed mode. */ + writel(i2c_timing_s1, &hsregs->usi_timing_fs1); + writel(i2c_timing_s2, &hsregs->usi_timing_fs2); + writel(i2c_timing_s3, &hsregs->usi_timing_fs3); + writel(i2c_timing_sla, &hsregs->usi_timing_sla); +} + +/* SW reset for the high speed bus */ +static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *i2c = i2c_bus->hsregs; + u32 i2c_ctl; + + /* Set and clear the bit for reset */ + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl |= HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl &= ~HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + /* Initialize the configure registers */ + hsi2c_ch_init(i2c_bus); +} + /* * MULTI BUS I2C support */ @@ -174,7 +359,7 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus;
if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { debug("Bad bus: %d\n", bus); @@ -182,8 +367,16 @@ int i2c_set_bus_num(unsigned int bus) }
g_current_bus = bus; - i2c = get_base_i2c(); - i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + i2c_bus = get_bus(i2c_get_bus_num()); + + 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, CONFIG_SYS_I2C_SPEED, + CONFIG_SYS_I2C_SLAVE); + }
return 0; } @@ -261,6 +454,165 @@ void i2c_init(int speed, int slaveadd) i2c_ch_init(i2c, speed, slaveadd); }
+static int hsi2c_master_busy(struct exynos5_hsi2c *i2c) +{ + ulong start = get_timer(0); + + /* Check I2C bus idle */ + while ((readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY)) { + if (get_timer(start) > (HSI2C_TIMEOUT)) + return I2C_NOK_TOUT; + udelay(10); + } + + return I2C_OK; +} + +/* + * Send a STOP event and wait for it to have completed + * + * @param mode If it is a master transmitter or receiver + * @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT otherwise + */ +static int hsi2c_send_stop(struct exynos5_hsi2c *i2c, int result) +{ + int ret = hsi2c_master_busy(i2c); + + /* Setting the STOP event to fire */ + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); + writel(0x0, &i2c->usi_int_en); + + return (result == I2C_OK) ? ret : result; +} + +static int hsi2c_write(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len) +{ + int i = 0, result = I2C_OK; + u32 i2c_auto_conf; + int ret = hsi2c_master_busy(i2c); + + if (ret) { + debug("%s: bus busy\n", __func__); + return I2C_NOK_TOUT; + } + + /* Disable TXFIFO and RXFIFO */ + writel(0, &i2c->usi_fifo_ctl); + + /* chip address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + /* Enable interrupts */ + writel((HSI2C_INT_I2C_EN | + HSI2C_INT_TX_ALMOSTEMPTY_EN), &i2c->usi_int_en); + + /* usi_ctl enable i2c func, master write configure */ + writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | + HSI2C_MASTER), &i2c->usi_ctl); + + /* i2c_conf configure */ + writel(readl(&i2c->usi_conf) | + HSI2C_AUTO_MODE, &i2c->usi_conf); + + /* auto_conf for write length and stop configure */ + i2c_auto_conf = ((len + alen) | HSI2C_STOP_AFTER_TRANS); + i2c_auto_conf &= ~HSI2C_READ_WRITE; + writel(i2c_auto_conf, &i2c->usi_auto_conf); + + /* Master run, start xfer */ + writel(readl(&i2c->usi_auto_conf) | + HSI2C_MASTER_RUN, &i2c->usi_auto_conf); + + result = hsi2c_wait_for_irq(i2c); + if ((result == I2C_OK) && hsi2c_isack(i2c)) { + result = I2C_NACK; + goto err; + } + + for (i = 0; i < alen && (result == I2C_OK); i++) { + writel(addr[i], &i2c->usi_txdata); + result = hsi2c_wait_for_irq(i2c); + } + + for (i = 0; i < len && (result == I2C_OK); i++) { + writel(data[i], &i2c->usi_txdata); + result = hsi2c_wait_for_irq(i2c); + } + + err: + hsi2c_clear_irqpd(i2c); + return hsi2c_send_stop(i2c, result); +} + +static int hsi2c_read(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len, + int check) +{ + int i, result; + u32 i2c_auto_conf; + + if (!check) { + result = hsi2c_write(i2c, chip, addr, alen, data, 0); + if (result != I2C_OK) { + debug("write failed Result = %d\n", result); + return result; + } + } + + /* start read */ + /* Disable TXFIFO and RXFIFO */ + writel(0, &i2c->usi_fifo_ctl); + + /* chip address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + /* Enable interrupts */ + writel(HSI2C_INT_I2C_EN, &i2c->usi_int_en); + + /* i2c_conf configure */ + writel(readl(&i2c->usi_conf) | + HSI2C_AUTO_MODE, &i2c->usi_conf); + + /* auto_conf, length and stop configure */ + i2c_auto_conf = + (len | HSI2C_STOP_AFTER_TRANS | HSI2C_READ_WRITE); + + writel(i2c_auto_conf, &i2c->usi_auto_conf); + + /* usi_ctl enable i2c func, master WRITE configure */ + writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | + HSI2C_MASTER), &i2c->usi_ctl); + + /* Master run, start xfer */ + writel(readl(&i2c->usi_auto_conf) | + HSI2C_MASTER_RUN, &i2c->usi_auto_conf); + + result = hsi2c_wait_for_irq(i2c); + if ((result == I2C_OK) && hsi2c_isack(i2c)) { + result = I2C_NACK; + goto err; + } + + for (i = 0; i < len && (result == I2C_OK); i++) { + result = hsi2c_wait_for_irq(i2c); + data[i] = readl(&i2c->usi_rxdata); + udelay(100); + } + err: + /* Stop and quit */ + hsi2c_clear_irqpd(i2c); + return hsi2c_send_stop(i2c, result); +} + /* * cmd_type is 0 for write, 1 for read. * @@ -279,7 +631,6 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, int i, result;
if (data == 0 || data_len == 0) { - /*Don't support data transfer of no length or to address 0 */ debug("i2c_transfer: bad call\n"); return I2C_NOK; } @@ -419,23 +770,29 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
int i2c_probe(uchar chip) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c; uchar buf[1]; + int ret;
- i2c = get_base_i2c(); + i2c = get_bus(g_current_bus); + if (!i2c) + return -1; buf[0] = 0;
- /* - * What is needed is to send the chip address and verify that the - * address was <ACK>ed (i.e. there was a chip at that address which - * drove the data line low). - */ - return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; + if (i2c->is_highspeed) { + ret = hsi2c_read(i2c->hsregs, + chip, 0, 1, buf, 1, 1); + } else { + ret = i2c_transfer(i2c->regs, + I2C_READ, chip << 1, 0, 0, buf, 1); + } + + return ret != I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; int ret;
@@ -467,10 +824,19 @@ 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 = get_base_i2c(); - ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len); - if (ret != 0) { + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len, 0); + else + ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret) { + exynos5_i2c_reset(i2c_bus); debug("I2c read: failed %d\n", ret); return 1; } @@ -479,8 +845,9 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; + int ret;
if (alen > 4) { debug("I2C write: addr len %d not supported\n", alen); @@ -509,45 +876,77 @@ 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 = get_base_i2c(); - return (i2c_transfer - (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, - len) != 0); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len); + else + ret = i2c_transfer(i2c_bus->regs, I2C_WRITE, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + + if (ret != 0) { + exynos5_i2c_reset(i2c_bus); + return 1; + } + + return 0; }
-#ifdef CONFIG_OF_CONTROL -void board_i2c_init(const void *blob) +static void process_nodes(const void *blob, int node_list[], int count, + int is_highspeed) { - 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); + struct s3c24x0_i2c_bus *bus; + int i;
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->is_highspeed = is_highspeed; + + if (is_highspeed) + bus->hsregs = (struct exynos5_hsi2c *) + fdtdec_get_addr(blob, node, "reg"); + else + 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); + + /* Mark position as used */ + node_list[i] = -1; } }
-static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx) +#ifdef CONFIG_OF_CONTROL +void board_i2c_init(const void *blob) { - if (bus_idx < i2c_busses) - return &i2c_bus[bus_idx]; + int node_list[CONFIG_MAX_I2C_NUM]; + int count;
- debug("Undefined bus: %d\n", bus_idx); - return NULL; + /* First get the normal i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_S3C2440_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 0); + + /* Now look for high speed i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 1); + + return; }
int i2c_get_bus_num_fdt(int node) @@ -565,7 +964,7 @@ int i2c_get_bus_num_fdt(int node)
int i2c_reset_port_fdt(const void *blob, int node) { - struct s3c24x0_i2c_bus *i2c; + struct s3c24x0_i2c_bus *i2c_bus; int bus;
bus = i2c_get_bus_num_fdt(node); @@ -574,13 +973,20 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
- i2c = get_bus(bus); - if (!i2c) { + i2c_bus = get_bus(bus); + if (!i2c_bus) { 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); + 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, + CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + }
return 0; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index a56d749..55931e8 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -31,10 +31,46 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c { + u32 usi_ctl; + u32 usi_fifo_ctl; + u32 usi_trailing_ctl; + u32 usi_clk_ctl; + u32 usi_clk_slot; + u32 spi_ctl; + u32 uart_ctl; + u32 res1; + u32 usi_int_en; + u32 usi_int_stat; + u32 usi_modem_stat; + u32 usi_error_stat; + u32 usi_fifo_stat; + u32 usi_txdata; + u32 usi_rxdata; + u32 res2; + u32 usi_conf; + u32 usi_auto_conf; + u32 usi_timeout; + u32 usi_manual_cmd; + u32 usi_trans_status; + u32 usi_timing_hs1; + u32 usi_timing_hs2; + u32 usi_timing_hs3; + u32 usi_timing_fs1; + u32 usi_timing_fs2; + u32 usi_timing_fs3; + u32 usi_timing_sla; + u32 i2c_addr; +}; + struct s3c24x0_i2c_bus { int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs; + struct exynos5_hsi2c *hsregs; + int is_highspeed; /* High speed type, rather than I2C */ int id; + unsigned clk_cycle; + unsigned clk_div; }; #endif /* _S3C24X0_I2C_H */

On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com Reviewed-by: Vadim Bendebury vbendeb@google.com Reviewed-by: Simon Glass sjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy function
- Use reg base address from device tree
- Split the timing function to check for the errors
- Implemented reset function for to recover from failure cases
- Implemented a comat string for hsi2c to distingush the channels
- Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 46d2506..32be91b 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -50,6 +50,60 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */
+/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31)
+/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4)
+/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff)
+/* I2C_INT_EN Register bits */ +#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) +#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9)
+/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29)
+/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31)
+/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31)
+/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_DONE (1u << 0) +#define HSI2C_TIMEOUT_AUTO (0u << 0)
+#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10)
+/* Controller operating frequency, timing values for operation
- are calculated against this frequency
- */
+#define HSI2C_FS_TX_CLOCK 1000000
+/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -61,6 +115,7 @@
#define I2C_TIMEOUT 1 /* 1 second */
+#define HSI2C_TIMEOUT 100
/*
- For SPL boot some boards need i2c before SDRAM is initialised so force
@@ -73,6 +128,15 @@ static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif
+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;
+}
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) { @@ -113,9 +177,23 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; }
-static int IsACK(struct s3c24x0_i2c *i2c) +static int hsi2c_wait_for_irq(struct exynos5_hsi2c *i2c) {
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
int i = HSI2C_TIMEOUT * 10;
int ret = I2C_NOK_TOUT;
while (i > 0) {
/* wait for a while and retry */
udelay(100);
if (readl(&i2c->usi_int_stat) &
(HSI2C_INT_I2C_EN | HSI2C_INT_TX_ALMOSTEMPTY_EN)) {
ret = I2C_OK;
break;
}
i--;
}
return ret;
}
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -123,6 +201,22 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c) writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); }
+static void hsi2c_clear_irqpd(struct exynos5_hsi2c *i2c) +{
writel(readl(&i2c->usi_int_stat), &i2c->usi_int_stat);
+}
+static int hsi2c_isack(struct exynos5_hsi2c *i2c) +{
return readl(&i2c->usi_trans_status) &
(HSI2C_NO_DEV | HSI2C_NO_DEV_ACK);
+}
+static int IsACK(struct s3c24x0_i2c *i2c) +{
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
+}
static struct s3c24x0_i2c *get_base_i2c(void) { #ifdef CONFIG_EXYNOS4 @@ -167,6 +261,97 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus) +{
struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
ulong clkin = get_i2c_clk();
unsigned int op_clk = HSI2C_FS_TX_CLOCK;
unsigned int i = 0, utemp0 = 0, utemp1 = 0;
unsigned int t_ftl_cycle;
/* FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
* uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
* uTemp1 = (TSCLK_L + TSCLK_H + 2)
* uTemp2 = TSCLK_L + TSCLK_H
*/
t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7;
utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle;
/* CLK_DIV max is 256 */
for (i = 0; i < 256; i++) {
utemp1 = utemp0 / (i + 1);
if ((utemp1 < 512) && (utemp1 > 4)) {
i2c_bus->clk_cycle = utemp1 - 2;
i2c_bus->clk_div = i;
return 0;
}
}
return -1;
+}
+static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus) +{
struct exynos5_hsi2c *hsregs = i2c_bus->hsregs;
unsigned int t_sr_release;
unsigned int n_clkdiv;
unsigned int t_start_su, t_start_hd;
unsigned int t_stop_su;
unsigned int t_data_su, t_data_hd;
unsigned int t_scl_l, t_scl_h;
u32 i2c_timing_s1;
u32 i2c_timing_s2;
u32 i2c_timing_s3;
u32 i2c_timing_sla;
n_clkdiv = i2c_bus->clk_div;
t_scl_l = i2c_bus->clk_cycle / 2;
t_scl_h = i2c_bus->clk_cycle / 2;
t_start_su = t_scl_l;
t_start_hd = t_scl_l;
t_stop_su = t_scl_l;
t_data_su = t_scl_l / 2;
t_data_hd = t_scl_l / 2;
t_sr_release = i2c_bus->clk_cycle;
i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8;
i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0;
i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0;
i2c_timing_sla = t_data_hd << 0;
writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl);
/* Clear to enable Timeout */
clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0);
writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf);
/* Currently operating in Fast speed mode. */
writel(i2c_timing_s1, &hsregs->usi_timing_fs1);
writel(i2c_timing_s2, &hsregs->usi_timing_fs2);
writel(i2c_timing_s3, &hsregs->usi_timing_fs3);
writel(i2c_timing_sla, &hsregs->usi_timing_sla);
+}
+/* SW reset for the high speed bus */ +static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus) +{
struct exynos5_hsi2c *i2c = i2c_bus->hsregs;
u32 i2c_ctl;
/* Set and clear the bit for reset */
i2c_ctl = readl(&i2c->usi_ctl);
i2c_ctl |= HSI2C_SW_RST;
writel(i2c_ctl, &i2c->usi_ctl);
i2c_ctl = readl(&i2c->usi_ctl);
i2c_ctl &= ~HSI2C_SW_RST;
writel(i2c_ctl, &i2c->usi_ctl);
/* Initialize the configure registers */
hsi2c_ch_init(i2c_bus);
+}
/*
- MULTI BUS I2C support
*/ @@ -174,7 +359,7 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) {
struct s3c24x0_i2c *i2c;
struct s3c24x0_i2c_bus *i2c_bus; if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { debug("Bad bus: %d\n", bus);
@@ -182,8 +367,16 @@ int i2c_set_bus_num(unsigned int bus) }
g_current_bus = bus;
i2c = get_base_i2c();
i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
i2c_bus = get_bus(i2c_get_bus_num());
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, CONFIG_SYS_I2C_SPEED,
CONFIG_SYS_I2C_SLAVE);
} return 0;
} @@ -261,6 +454,165 @@ void i2c_init(int speed, int slaveadd) i2c_ch_init(i2c, speed, slaveadd); }
+static int hsi2c_master_busy(struct exynos5_hsi2c *i2c) +{
ulong start = get_timer(0);
/* Check I2C bus idle */
while ((readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY)) {
if (get_timer(start) > (HSI2C_TIMEOUT))
return I2C_NOK_TOUT;
udelay(10);
}
return I2C_OK;
+}
+/*
- Send a STOP event and wait for it to have completed
- @param mode If it is a master transmitter or receiver
- @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT otherwise
- */
+static int hsi2c_send_stop(struct exynos5_hsi2c *i2c, int result) +{
int ret = hsi2c_master_busy(i2c);
/* Setting the STOP event to fire */
writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl);
writel(0x0, &i2c->usi_int_en);
return (result == I2C_OK) ? ret : result;
+}
+static int hsi2c_write(struct exynos5_hsi2c *i2c,
unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len)
+{
int i = 0, result = I2C_OK;
u32 i2c_auto_conf;
int ret = hsi2c_master_busy(i2c);
if (ret) {
debug("%s: bus busy\n", __func__);
return I2C_NOK_TOUT;
}
/* Disable TXFIFO and RXFIFO */
writel(0, &i2c->usi_fifo_ctl);
/* chip address */
writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
/* Enable interrupts */
writel((HSI2C_INT_I2C_EN |
HSI2C_INT_TX_ALMOSTEMPTY_EN), &i2c->usi_int_en);
/* usi_ctl enable i2c func, master write configure */
writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C |
HSI2C_MASTER), &i2c->usi_ctl);
/* i2c_conf configure */
writel(readl(&i2c->usi_conf) |
HSI2C_AUTO_MODE, &i2c->usi_conf);
/* auto_conf for write length and stop configure */
i2c_auto_conf = ((len + alen) | HSI2C_STOP_AFTER_TRANS);
i2c_auto_conf &= ~HSI2C_READ_WRITE;
writel(i2c_auto_conf, &i2c->usi_auto_conf);
/* Master run, start xfer */
writel(readl(&i2c->usi_auto_conf) |
HSI2C_MASTER_RUN, &i2c->usi_auto_conf);
result = hsi2c_wait_for_irq(i2c);
if ((result == I2C_OK) && hsi2c_isack(i2c)) {
result = I2C_NACK;
goto err;
}
for (i = 0; i < alen && (result == I2C_OK); i++) {
writel(addr[i], &i2c->usi_txdata);
result = hsi2c_wait_for_irq(i2c);
}
for (i = 0; i < len && (result == I2C_OK); i++) {
writel(data[i], &i2c->usi_txdata);
result = hsi2c_wait_for_irq(i2c);
}
- err:
hsi2c_clear_irqpd(i2c);
return hsi2c_send_stop(i2c, result);
+}
+static int hsi2c_read(struct exynos5_hsi2c *i2c,
unsigned char chip,
unsigned char addr[],
unsigned char alen,
unsigned char data[],
unsigned short len,
int check)
+{
int i, result;
u32 i2c_auto_conf;
if (!check) {
result = hsi2c_write(i2c, chip, addr, alen, data, 0);
if (result != I2C_OK) {
debug("write failed Result = %d\n", result);
return result;
}
}
/* start read */
/* Disable TXFIFO and RXFIFO */
writel(0, &i2c->usi_fifo_ctl);
/* chip address */
writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr);
/* Enable interrupts */
writel(HSI2C_INT_I2C_EN, &i2c->usi_int_en);
/* i2c_conf configure */
writel(readl(&i2c->usi_conf) |
HSI2C_AUTO_MODE, &i2c->usi_conf);
/* auto_conf, length and stop configure */
i2c_auto_conf =
(len | HSI2C_STOP_AFTER_TRANS | HSI2C_READ_WRITE);
writel(i2c_auto_conf, &i2c->usi_auto_conf);
/* usi_ctl enable i2c func, master WRITE configure */
writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C |
HSI2C_MASTER), &i2c->usi_ctl);
/* Master run, start xfer */
writel(readl(&i2c->usi_auto_conf) |
HSI2C_MASTER_RUN, &i2c->usi_auto_conf);
result = hsi2c_wait_for_irq(i2c);
if ((result == I2C_OK) && hsi2c_isack(i2c)) {
result = I2C_NACK;
goto err;
}
for (i = 0; i < len && (result == I2C_OK); i++) {
result = hsi2c_wait_for_irq(i2c);
data[i] = readl(&i2c->usi_rxdata);
udelay(100);
}
- err:
/* Stop and quit */
hsi2c_clear_irqpd(i2c);
return hsi2c_send_stop(i2c, result);
+}
/*
- cmd_type is 0 for write, 1 for read.
@@ -279,7 +631,6 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, int i, result;
if (data == 0 || data_len == 0) {
/*Don't support data transfer of no length or to address 0 */ debug("i2c_transfer: bad call\n"); return I2C_NOK; }
@@ -419,23 +770,29 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c,
int i2c_probe(uchar chip) {
struct s3c24x0_i2c *i2c;
struct s3c24x0_i2c_bus *i2c; uchar buf[1];
int ret;
i2c = get_base_i2c();
i2c = get_bus(g_current_bus);
if (!i2c)
return -1; buf[0] = 0;
/*
* What is needed is to send the chip address and verify that the
* address was <ACK>ed (i.e. there was a chip at that address which
* drove the data line low).
*/
return i2c_transfer(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
if (i2c->is_highspeed) {
ret = hsi2c_read(i2c->hsregs,
chip, 0, 1, buf, 1, 1);
} else {
ret = i2c_transfer(i2c->regs,
I2C_READ, chip << 1, 0, 0, buf, 1);
}
return ret != I2C_OK;
}
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) {
struct s3c24x0_i2c *i2c;
struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; int ret;
@@ -467,10 +824,19 @@ 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 = get_base_i2c();
ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
buffer, len);
if (ret != 0) {
i2c_bus = get_bus(g_current_bus);
if (!i2c_bus)
return -1;
if (i2c_bus->is_highspeed)
ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen],
alen, buffer, len, 0);
else
ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1,
&xaddr[4 - alen], alen, buffer, len);
if (ret) {
exynos5_i2c_reset(i2c_bus); debug("I2c read: failed %d\n", ret); return 1; }
@@ -479,8 +845,9 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) {
struct s3c24x0_i2c *i2c;
struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4];
int ret; if (alen > 4) { debug("I2C write: addr len %d not supported\n", alen);
@@ -509,45 +876,77 @@ 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 = get_base_i2c();
return (i2c_transfer
(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
len) != 0);
i2c_bus = get_bus(g_current_bus);
if (!i2c_bus)
return -1;
if (i2c_bus->is_highspeed)
ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen],
alen, buffer, len);
else
ret = i2c_transfer(i2c_bus->regs, I2C_WRITE, chip << 1,
&xaddr[4 - alen], alen, buffer, len);
if (ret != 0) {
exynos5_i2c_reset(i2c_bus);
return 1;
}
return 0;
}
-#ifdef CONFIG_OF_CONTROL -void board_i2c_init(const void *blob) +static void process_nodes(const void *blob, int node_list[], int count,
int is_highspeed)
{
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);
struct s3c24x0_i2c_bus *bus;
int i; 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->is_highspeed = is_highspeed;
if (is_highspeed)
bus->hsregs = (struct exynos5_hsi2c *)
fdtdec_get_addr(blob, node, "reg");
else
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);
/* Mark position as used */
node_list[i] = -1; }
}
-static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx) +#ifdef CONFIG_OF_CONTROL +void board_i2c_init(const void *blob) {
if (bus_idx < i2c_busses)
return &i2c_bus[bus_idx];
int node_list[CONFIG_MAX_I2C_NUM];
int count;
debug("Undefined bus: %d\n", bus_idx);
return NULL;
/* First get the normal i2c ports */
count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_S3C2440_I2C, node_list,
CONFIG_MAX_I2C_NUM);
process_nodes(blob, node_list, count, 0);
/* Now look for high speed i2c ports */
count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
CONFIG_MAX_I2C_NUM);
process_nodes(blob, node_list, count, 1);
return;
}
int i2c_get_bus_num_fdt(int node) @@ -565,7 +964,7 @@ int i2c_get_bus_num_fdt(int node)
int i2c_reset_port_fdt(const void *blob, int node) {
struct s3c24x0_i2c_bus *i2c;
struct s3c24x0_i2c_bus *i2c_bus; int bus; bus = i2c_get_bus_num_fdt(node);
@@ -574,13 +973,20 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
i2c = get_bus(bus);
if (!i2c) {
i2c_bus = get_bus(bus);
if (!i2c_bus) { 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);
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,
CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
} return 0;
} diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index a56d749..55931e8 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -31,10 +31,46 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c {
u32 usi_ctl;
u32 usi_fifo_ctl;
u32 usi_trailing_ctl;
u32 usi_clk_ctl;
u32 usi_clk_slot;
u32 spi_ctl;
u32 uart_ctl;
u32 res1;
u32 usi_int_en;
u32 usi_int_stat;
u32 usi_modem_stat;
u32 usi_error_stat;
u32 usi_fifo_stat;
u32 usi_txdata;
u32 usi_rxdata;
u32 res2;
u32 usi_conf;
u32 usi_auto_conf;
u32 usi_timeout;
u32 usi_manual_cmd;
u32 usi_trans_status;
u32 usi_timing_hs1;
u32 usi_timing_hs2;
u32 usi_timing_hs3;
u32 usi_timing_fs1;
u32 usi_timing_fs2;
u32 usi_timing_fs3;
u32 usi_timing_sla;
u32 i2c_addr;
+};
struct s3c24x0_i2c_bus { int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs;
struct exynos5_hsi2c *hsregs;
int is_highspeed; /* High speed type, rather than I2C */ int id;
unsigned clk_cycle;
unsigned clk_div;
};
#endif /* _S3C24X0_I2C_H */
1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
-- Shine bright, (: Nav :)

Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com Reviewed-by: Vadim Bendeburyvbendeb@google.com Reviewed-by: Simon Glasssjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy function
- Use reg base address from device tree
- Split the timing function to check for the errors
- Implemented reset function for to recover from failure cases
- Implemented a comat string for hsi2c to distingush the channels
- Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
-- 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?, added to cc):
Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
bye, Heiko

On Mon, Apr 15, 2013 at 07:48:04AM +0200, Heiko Schocher wrote:
Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com Reviewed-by: Vadim Bendeburyvbendeb@google.com Reviewed-by: Simon Glasssjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy function
- Use reg base address from device tree
- Split the timing function to check for the errors
- Implemented reset function for to recover from failure cases
- Implemented a comat string for hsi2c to distingush the channels
- Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
-- 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?,
When in doubt, my fault.

On 14 April 2013 22:48, Heiko Schocher hs@denx.de wrote:
Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com Reviewed-by: Vadim Bendeburyvbendeb@google.com Reviewed-by: Simon Glasssjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy
function 2. Use reg base address from device tree 3. Split the timing function to check for the errors 4. Implemented reset function for to recover from failure cases 5. Implemented a comat string for hsi2c to distingush the channels 6. Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
-- 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?, added to cc):
Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
Hello Minkyu Kang,
This patch was Acked and reviewed a while ago. Can you please update on this.
bye, Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
-- Shine bright, (: Nav :)

On 26/04/13 12:08, Naveen Krishna Ch wrote:
On 14 April 2013 22:48, Heiko Schocher hs@denx.de wrote:
Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com Reviewed-by: Vadim Bendeburyvbendeb@google.com Reviewed-by: Simon Glasssjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy
function 2. Use reg base address from device tree 3. Split the timing function to check for the errors 4. Implemented reset function for to recover from failure cases 5. Implemented a comat string for hsi2c to distingush the channels 6. Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
-- 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?, added to cc):
Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
Hello Minkyu Kang,
This patch was Acked and reviewed a while ago. Can you please update on this.
I delegate owner to Heiko.
Heiko, please take this patch to your tree.
Thanks, Minkyu Kang.

Hello Naveen,
On 26.04.2013 05:08, Naveen Krishna Ch wrote:
On 14 April 2013 22:48, Heiko Schocher hs@denx.de wrote:
Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com Reviewed-by: Vadim Bendeburyvbendeb@google.com Reviewed-by: Simon Glasssjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy
function 2. Use reg base address from device tree 3. Split the timing function to check for the errors 4. Implemented reset function for to recover from failure cases 5. Implemented a comat string for hsi2c to distingush the channels 6. Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
-- 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?, added to cc):
Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
Hello Minkyu Kang,
This patch was Acked and reviewed a while ago. Can you please update on this.
Tom Rini wrote:
Naveen Krishna Ch (1): i2c: s3c24xx: add hsi2c controller support
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ drivers/i2c/s3c24x0_i2c.h | 36 ++++++++++ post/drivers/i2c.c | 2 + 3 Dateien ge?ndert, 488 Zeilen hinzugef?gt(+), 44 Zeilen entfernt(-)
NAK. MAKEALL -a arm: --------------------- SUMMARY ---------------------------- Boards compiled: 306 Boards with errors: 3 ( snow VCMA9 smdk5250 )
And the problem is: s3c24x0_i2c.c: In function 'board_i2c_init': s3c24x0_i2c.c:945:3: error: 'COMPAT_SAMSUNG_EXYNOS5_I2C' undeclared (first use in this function)
Please fix, thanks!
bye, Heiko

Hello Heiko,
On 29 April 2013 21:14, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
On 26.04.2013 05:08, Naveen Krishna Ch wrote:
On 14 April 2013 22:48, Heiko Schocher hs@denx.de wrote:
Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com Reviewed-by: Vadim Bendeburyvbendeb@google.com Reviewed-by: Simon Glasssjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy
function 2. Use reg base address from device tree 3. Split the timing function to check for the errors 4. Implemented reset function for to recover from failure cases 5. Implemented a comat string for hsi2c to distingush the channels 6. Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
-- 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?, added to cc):
Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
Hello Minkyu Kang,
This patch was Acked and reviewed a while ago. Can you please update on this.
Tom Rini wrote:
Naveen Krishna Ch (1): i2c: s3c24xx: add hsi2c controller support
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ drivers/i2c/s3c24x0_i2c.h | 36 ++++++++++ post/drivers/i2c.c | 2 + 3 Dateien ge?ndert, 488 Zeilen hinzugef?gt(+), 44 Zeilen entfernt(-)
NAK. MAKEALL -a arm: --------------------- SUMMARY ---------------------------- Boards compiled: 306 Boards with errors: 3 ( snow VCMA9 smdk5250 )
And the problem is: s3c24x0_i2c.c: In function 'board_i2c_init': s3c24x0_i2c.c:945:3: error: 'COMPAT_SAMSUNG_EXYNOS5_I2C' undeclared (first use in this function)
Please fix, thanks!
I've submitted a patch to u-boot@lists.denx.de as soon as i saw the build error.
"fdtdec: Add compatible string for High speed i2c" http://www.mail-archive.com/u-boot@lists.denx.de/msg112143.html
which should fix. Can you please confirm the same.
Thanks
bye, Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
-- Shine bright, (: Nav :)

Hello Naveen,
On 01.05.2013 21:04, Naveen Krishna Ch wrote:
Hello Heiko,
On 29 April 2013 21:14, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
On 26.04.2013 05:08, Naveen Krishna Ch wrote:
On 14 April 2013 22:48, Heiko Schocher hs@denx.de wrote:
Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com Reviewed-by: Vadim Bendeburyvbendeb@google.com Reviewed-by: Simon Glasssjg@google.com
Changes since v3:
- Implemented get_timer instead of while and udelay for master busy
function 2. Use reg base address from device tree 3. Split the timing function to check for the errors 4. Implemented reset function for to recover from failure cases 5. Implemented a comat string for hsi2c to distingush the channels 6. Minor cosmotic changes
Note: FIFOs will be implemented in subsequent patches
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 36 ++++ 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
-- 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?, added to cc):
Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
Hello Minkyu Kang,
This patch was Acked and reviewed a while ago. Can you please update on this.
Tom Rini wrote:
Naveen Krishna Ch (1): i2c: s3c24xx: add hsi2c controller support
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ drivers/i2c/s3c24x0_i2c.h | 36 ++++++++++ post/drivers/i2c.c | 2 + 3 Dateien ge?ndert, 488 Zeilen hinzugef?gt(+), 44 Zeilen entfernt(-)
NAK. MAKEALL -a arm: --------------------- SUMMARY ---------------------------- Boards compiled: 306 Boards with errors: 3 ( snow VCMA9 smdk5250 )
And the problem is: s3c24x0_i2c.c: In function 'board_i2c_init': s3c24x0_i2c.c:945:3: error: 'COMPAT_SAMSUNG_EXYNOS5_I2C' undeclared (first use in this function)
Please fix, thanks!
I've submitted a patch to u-boot@lists.denx.de as soon as i saw the build error.
"fdtdec: Add compatible string for High speed i2c" http://www.mail-archive.com/u-boot@lists.denx.de/msg112143.html
which should fix. Can you please confirm the same.
On current HEAD with your 2 patches, I see:
[hs@pollux u-boot]$ ./MAKEALL VCMA9 Configuring for VCMA9 board... s3c24x0_i2c.c:133:16: error: 'i2c_busses' undeclared (first use in this function) s3c24x0_i2c.c:134:11: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c:911:10: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c:923:18: error: 'i2c_busses' undeclared (first use in this function) arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c: In function 'get_bus': s3c24x0_i2c.c:133:16: error: 'i2c_busses' undeclared (first use in this function) s3c24x0_i2c.c:133:16: note: each undeclared identifier is reported only once for each function it appears in s3c24x0_i2c.c:134:11: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c: In function 'hsi2c_get_clk_details': s3c24x0_i2c.c:267:2: warning: implicit declaration of function 'get_i2c_clk' [-Wimplicit-function-declaration] s3c24x0_i2c.c: In function 'process_nodes': s3c24x0_i2c.c:911:10: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c:921:3: warning: implicit declaration of function 'pinmux_decode_periph_id' [-Wimplicit-function-declaration] s3c24x0_i2c.c:923:18: error: 'i2c_busses' undeclared (first use in this function) s3c24x0_i2c.c:924:3: warning: implicit declaration of function 'exynos_pinmux_config' [-Wimplicit-function-declaration] s3c24x0_i2c.c: At top level: s3c24x0_i2c.c:264:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] s3c24x0_i2c.c:899:13: warning: 'process_nodes' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make: *** [drivers/i2c/libi2c.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
--------------------- SUMMARY ---------------------------- Boards compiled: 1 Boards with errors: 1 ( VCMA9 ) ---------------------------------------------------------- [hs@pollux u-boot]$ git log commit b89874f919da1255d50f47b4b349224f5f4fb4a7 Author: Naveen Krishna Ch naveenkrishna.ch@gmail.com Date: Fri Apr 5 15:37:57 2013 +0000
i2c: s3c24xx: add hsi2c controller support
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com Reviewed-by: Vadim Bendebury vbendeb@google.com Reviewed-by: Simon Glass sjg@google.com Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
commit 1d3381320c9f9181c4dd4f1edf5e7e28285b1c41 Author: Naveen Krishna Ch naveenkrishna.ch@gmail.com Date: Mon Apr 29 12:58:52 2013 +0000
fdtdec: Add compatible string for High speed i2c
Adds a new COMPAT string exynos5-hsi2c for high speed i2c controller available on exynos5 SoCs from Samsung.
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com
ommit 971020c755e5633c9a8f532356ee1750b38dd86f Author: Simon Glass sjg@chromium.org Date: Sat Apr 20 08:42:52 2013 +0000
sandbox: config: Enable CONFIG_FIT and CONFIG_CMD_FIT
Enable these options to use FITs on sandbox.
Signed-off-by: Simon Glass sjg@chromium.org
bye, Heiko

Hello Heiko,
On 2 May 2013 03:06, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
On 01.05.2013 21:04, Naveen Krishna Ch wrote:
Hello Heiko,
On 29 April 2013 21:14, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
On 26.04.2013 05:08, Naveen Krishna Ch wrote:
On 14 April 2013 22:48, Heiko Schocher hs@denx.de wrote:
Hello Naveen Krishna,
On 13.04.2013 06:42, Naveen Krishna Ch wrote:
On 6 April 2013 07:07, Naveen Krishna Chatradhi naveenkrishna.ch@gmail.com wrote: > > Add support for hsi2c controller available on exynos5420. > > Note: driver currently supports only fast speed mode 100kbps > > Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 > Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com > Signed-off-by: R. Chandrasekarrc.sekar@samsung.com > Reviewed-by: Vadim Bendeburyvbendeb@google.com > Reviewed-by: Simon Glasssjg@google.com > --- > Changes since v3: > > 1. Implemented get_timer instead of while and udelay for master busy > function > 2. Use reg base address from device tree > 3. Split the timing function to check for the errors > 4. Implemented reset function for to recover from failure cases > 5. Implemented a comat string for hsi2c to distingush the channels > 6. Minor cosmotic changes > > Note: FIFOs will be implemented in subsequent patches > > drivers/i2c/s3c24x0_i2c.c | 494 > +++++++++++++++++++++++++++++++++++++++++---- > drivers/i2c/s3c24x0_i2c.h | 36 ++++ > 2 files changed, 486 insertions(+), 44 deletions(-)
[...]
> -- > 1.7.9.5
Hello all i got it review by Simon and Vadim. Any updates on this driver please
As this patch in patchwork is in the responsibilty of Minkyu Kang (why?, added to cc):
Reviewed-by: Heiko Schocherhs@denx.de Acked-by: Heiko Schocher hs@denx.de
Hello Minkyu Kang,
This patch was Acked and reviewed a while ago. Can you please update on this.
Tom Rini wrote:
Naveen Krishna Ch (1): i2c: s3c24xx: add hsi2c controller support
drivers/i2c/s3c24x0_i2c.c | 494 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ drivers/i2c/s3c24x0_i2c.h | 36 ++++++++++ post/drivers/i2c.c | 2 + 3 Dateien ge?ndert, 488 Zeilen hinzugef?gt(+), 44 Zeilen entfernt(-)
NAK. MAKEALL -a arm: --------------------- SUMMARY ---------------------------- Boards compiled: 306 Boards with errors: 3 ( snow VCMA9 smdk5250 )
And the problem is: s3c24x0_i2c.c: In function 'board_i2c_init': s3c24x0_i2c.c:945:3: error: 'COMPAT_SAMSUNG_EXYNOS5_I2C' undeclared (first use in this function)
Please fix, thanks!
I've submitted a patch to u-boot@lists.denx.de as soon as i saw the build error.
"fdtdec: Add compatible string for High speed i2c" http://www.mail-archive.com/u-boot@lists.denx.de/msg112143.html
which should fix. Can you please confirm the same.
On current HEAD with your 2 patches, I see:
[hs@pollux u-boot]$ ./MAKEALL VCMA9 Configuring for VCMA9 board... s3c24x0_i2c.c:133:16: error: 'i2c_busses' undeclared (first use in this function) s3c24x0_i2c.c:134:11: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c:911:10: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c:923:18: error: 'i2c_busses' undeclared (first use in this function) arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c: In function 'get_bus': s3c24x0_i2c.c:133:16: error: 'i2c_busses' undeclared (first use in this function) s3c24x0_i2c.c:133:16: note: each undeclared identifier is reported only once for each function it appears in s3c24x0_i2c.c:134:11: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c: In function 'hsi2c_get_clk_details': s3c24x0_i2c.c:267:2: warning: implicit declaration of function 'get_i2c_clk' [-Wimplicit-function-declaration] s3c24x0_i2c.c: In function 'process_nodes': s3c24x0_i2c.c:911:10: error: 'i2c_bus' undeclared (first use in this function) s3c24x0_i2c.c:921:3: warning: implicit declaration of function 'pinmux_decode_periph_id' [-Wimplicit-function-declaration] s3c24x0_i2c.c:923:18: error: 'i2c_busses' undeclared (first use in this function) s3c24x0_i2c.c:924:3: warning: implicit declaration of function 'exynos_pinmux_config' [-Wimplicit-function-declaration] s3c24x0_i2c.c: At top level: s3c24x0_i2c.c:264:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] s3c24x0_i2c.c:899:13: warning: 'process_nodes' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make: *** [drivers/i2c/libi2c.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
A quick look at the driver shows "i2c_busses and i2c_bus are defined under #ifdef CONFIG_OF_CONTROL"
A fix submitted by Author: Rajeshwari Shinde rajeshwari.s@samsung.com http://lists.denx.de/pipermail/u-boot/2013-January/144145.html
"I2C: S3C24X0: Resolve build error for VCMA9" seems to be blocking those variables for not OF_CONTROL builds
Will look for a fix.
--------------------- SUMMARY ---------------------------- Boards compiled: 1 Boards with errors: 1 ( VCMA9 )
[hs@pollux u-boot]$ git log commit b89874f919da1255d50f47b4b349224f5f4fb4a7 Author: Naveen Krishna Ch naveenkrishna.ch@gmail.com Date: Fri Apr 5 15:37:57 2013 +0000
i2c: s3c24xx: add hsi2c controller support Add support for hsi2c controller available on exynos5420. Note: driver currently supports only fast speed mode 100kbps Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com> Signed-off-by: R. Chandrasekar <rc.sekar@samsung.com> Reviewed-by: Vadim Bendebury <vbendeb@google.com> Reviewed-by: Simon Glass <sjg@google.com> Reviewed-by: Heiko Schocher<hs@denx.de> Acked-by: Heiko Schocher <hs@denx.de>
commit 1d3381320c9f9181c4dd4f1edf5e7e28285b1c41 Author: Naveen Krishna Ch naveenkrishna.ch@gmail.com Date: Mon Apr 29 12:58:52 2013 +0000
fdtdec: Add compatible string for High speed i2c Adds a new COMPAT string exynos5-hsi2c for high speed i2c controller available on exynos5 SoCs from Samsung. Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
ommit 971020c755e5633c9a8f532356ee1750b38dd86f Author: Simon Glass sjg@chromium.org Date: Sat Apr 20 08:42:52 2013 +0000
sandbox: config: Enable CONFIG_FIT and CONFIG_CMD_FIT Enable these options to use FITs on sandbox. Signed-off-by: Simon Glass <sjg@chromium.org>
bye, Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
-- Shine bright, (: Nav :)

This patchset fixes few bugs in the existing s3c24x0.c code (standard i2c) and add support for High-speed i2c bus controller available on Exynos5 SoCs from Samsung.
Exynos5250 channels [0 ~ 3] can configured for I2C contoller or new HSI2C controller channels [3 ~ 7] are standard I2C controller channels Exynos5420 channels [0 ~ 3] are standard I2C controller channels and channels [4 ~ 10] are High-speed controller channels
Patchset: 1. exynos: i2c: Fix i2c driver to handle NACKs properly Improvements and fixes from Vadim Bendebury for standard i2c calls
2. exynos: i2c: Change FDT bus setup code to enumerate ports correctly FDT bus setup code from Simon Glass
3. PATCH v5: i2c: s3c24xx: add hsi2c controller support High-speed controller register description and defines new i2c read/write, probe and set_bus calls.
This is been reviewed earlier at http://lists.denx.de/pipermail/u-boot/2013-May/153245.html Thanks for review and improvements from Vadim Bendebury.
Question: 4. RFC: samsung: i2c: Enable new CONFIG_SYS_I2C framework I've tried to implement the new I2C multi bus framework in u-boot tree, taking tegra-i2c.c as reference.
a). We have different number of channels on Exynos5250 and Exynos5420 (as explained above). How are we supposed to define the U_BOOT_I2C_ADAP_COMPLETE in such cases. Can i use #ifdef EXYNOS5420 or EXYNOS5250 b). When i define 11 buses as in the case of Exynos5420, the "i2c bus" lists them SMDK5420 # i2c bus Bus 0: s3c0 Bus 1: s3c1 Bus 2: s3c10 Bus 3: s3c2 Bus 4: s3c3 Bus 5: s3c4 Bus 6: s3c5 Bus 7: s3c6 Bus 8: s3c7 Bus 9: s3c8 Bus 10: s3c9 or (If i change the name to hsi2c) SMDK5420 # i2c bus Bus 0: hsi2c10 Bus 1: hsi2c4 Bus 2: hsi2c5 Bus 3: hsi2c6 Bus 4: hsi2c7 Bus 5: hsi2c8 Bus 6: hsi2c9 Bus 7: s3c0 Bus 8: s3c1 Bus 9: s3c2 Bus 10: s3c3
Whats the expected behaviour. If the above result is correct, I need to changei the strings to get them in the correct order.
c). What's the alternative for the board_i2c_init(), i2c_get_bus_num_fdt(), i2c_reset_port_fdt(). "Functions to get the I2C bus number and reset I2C bus using FDT node"
I think, these functions are still needed.
Kindly, help me with the above questions. I'm willing to implement the new i2c frame work.
Thanks in advance.
Naveen Krishna Chatradhi (3): exynos: i2c: Fix i2c driver to handle NACKs properly i2c: s3c24xx: add hsi2c controller support RFC: samsung: i2c: Enable new CONFIG_SYS_I2C framework
Simon Glass (1): exynos: i2c: Change FDT bus setup code to enumerate ports correctly
drivers/i2c/Makefile | 2 +- drivers/i2c/s3c24x0_i2c.c | 912 ++++++++++++++++++++++++++++++++++++--------- drivers/i2c/s3c24x0_i2c.h | 38 ++ 3 files changed, 771 insertions(+), 181 deletions(-)

The Exynos5 i2c driver does not handle NACKs properly. This change:
- fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
- eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Reviewed-by: Simon Glass sjg@google.com Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- drivers/i2c/s3c24x0_i2c.c | 213 +++++++++++++++++++-------------------------- 1 file changed, 89 insertions(+), 124 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index cd09c78..b69da54 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -43,7 +43,7 @@ #define I2C_START_STOP 0x20 /* START / STOP */ #define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
-#define I2C_TIMEOUT 1 /* 1 second */ +#define I2C_TIMEOUT_MS 1000 /* 1 second */
/* @@ -84,22 +84,26 @@ static void SetI2CSCL(int x) } #endif
+/* + * Wait til the byte transfer is completed. + * + * @param i2c- pointer to the appropriate i2c register bank. + * @return I2C_OK, if transmission was ACKED + * I2C_NACK, if transmission was NACKED + * I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS + */ + static int WaitForXfer(struct s3c24x0_i2c *i2c) { - int i; + ulong start_time = get_timer(0);
- i = I2C_TIMEOUT * 10000; - while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) { - udelay(100); - i--; - } + do { + if (readl(&i2c->iiccon) & I2CCON_IRPND) + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ? + I2C_NACK : I2C_OK; + } while (get_timer(start_time) < I2C_TIMEOUT_MS);
- return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; -} - -static int IsACK(struct s3c24x0_i2c *i2c) -{ - return !(readl(&i2c->iicstat) & I2CSTAT_NACK); + return I2C_NOK_TOUT; }
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -184,17 +188,22 @@ void i2c_init(int speed, int slaveadd) #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #endif - int i; + ulong start_time = get_timer(0);
/* By default i2c channel 0 is the current bus */ g_current_bus = 0; i2c = get_base_i2c();
- /* wait for some time to give previous transfer a chance to finish */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + /* + * In case the previous transfer is still going, wait to give it a + * chance to finish. + */ + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) { + printf("%s: I2C bus busy for %p\n", __func__, + &i2c->iicstat); + return; + } }
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -260,7 +269,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, unsigned char data[], unsigned short data_len) { - int i, result; + int i = 0, result; + ulong start_time = get_timer(0);
if (data == 0 || data_len == 0) { /*Don't support data transfer of no length or to address 0 */ @@ -268,128 +278,78 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, return I2C_NOK; }
- /* Check I2C bus idle */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) + return I2C_NOK_TOUT; }
- if (readl(&i2c->iicstat) & I2CSTAT_BSY) - return I2C_NOK_TOUT; - writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon); - result = I2C_OK;
- switch (cmd_type) { - case I2C_WRITE: - if (addr && addr_len) { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - } else { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } + /* Get the slave chip address going */ + writel(chip, &i2c->iicds); + if ((cmd_type == I2C_WRITE) || (addr && addr_len)) + writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + else + writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + + /* Wait for chip address to transmit. */ + result = WaitForXfer(i2c); + if (result != I2C_OK) + goto bailout; + + /* If register address needs to be transmitted - do it now. */ + if (addr && addr_len) { + while ((i < addr_len) && (result == I2C_OK)) { + writel(addr[i++], &i2c->iicds); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); } + i = 0; + if (result != I2C_OK) + goto bailout; + }
- if (result == I2C_OK) + switch (cmd_type) { + case I2C_WRITE: + while ((i < data_len) && (result == I2C_OK)) { + writel(data[i++], &i2c->iicds); + ReadWriteByte(i2c); result = WaitForXfer(i2c); - - /* send STOP */ - writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + } break;
case I2C_READ: if (addr && addr_len) { + /* + * Register address has been sent, now send slave chip + * address again to start the actual read transaction. + */ writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - result = WaitForXfer(i2c); - if (IsACK(i2c)) { - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i++; - } - - writel(chip, &i2c->iicds); - /* resend START */ - writel(I2C_MODE_MR | I2C_TXRX_ENA | - I2C_START_STOP, &i2c->iicstat); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) - & ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } - - } else { - writel(chip, &i2c->iicds); - /* send START */ + + /* Generate a re-START. */ writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, &i2c->iicstat); + ReadWriteByte(i2c); result = WaitForXfer(i2c);
- if (IsACK(i2c)) { - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) & - ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } + if (result != I2C_OK) + goto bailout; }
- /* send STOP */ - writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + while ((i < data_len) && (result == I2C_OK)) { + /* disable ACK for final READ */ + if (i == data_len - 1) + writel(readl(&i2c->iiccon) + & ~I2CCON_ACKGEN, + &i2c->iiccon); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); + data[i++] = readl(&i2c->iicds); + } + if (result == I2C_NACK) + result = I2C_OK; /* Normal terminated read. */ break;
default: @@ -398,6 +358,11 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, break; }
+bailout: + /* Send STOP. */ + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); + ReadWriteByte(i2c); + return result; }

Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
The Exynos5 i2c driver does not handle NACKs properly. This change:
fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendeburyvbendeb@chromium.org Reviewed-by: Simon Glasssjg@google.com Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
drivers/i2c/s3c24x0_i2c.c | 213 +++++++++++++++++++-------------------------- 1 file changed, 89 insertions(+), 124 deletions(-)
Patch introduces a compileerror for the VCMA9 board:
Testing VCMA9 on -00058-ga882b9e Wed Oct 2 09:02:24 EDT 2013 Configuring for VCMA9 board... s3c24x0_i2c.c:234:3: error: 'i' undeclared (first use in this function) make[1]: *** [/home/trini/work/u-boot/u-boot/VCMA9/drivers/i2c/s3c24x0_i2c.o] Error 1 make: *** [/home/trini/work/u-boot/u-boot/VCMA9/drivers/i2c/libi2c.o] Error 2 /opt/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2013.03-20130313_linux/bin/arm-linux-gnueabihf-size: 'VCMA9/u-boot': No such file s3c24x0_i2c.c: In function 'i2c_init': s3c24x0_i2c.c:234:3: error: 'i' undeclared (first use in this function) s3c24x0_i2c.c:234:3: note: each undeclared identifier is reported only once for each function it appears in make[1]: *** [/home/trini/work/u-boot/u-boot/VCMA9/drivers/i2c/s3c24x0_i2c.o] Error 1 make: *** [/home/trini/work/u-boot/u-boot/VCMA9/drivers/i2c/libi2c.o] Error 2 make: *** Waiting for unfinished jobs....
Please check this and add, when posting this patch again, the board Maintainer:
David Müller d.mueller@elsoft.ch
to Cc, so he maybe can test it ...
Thanks!
bye, Heiko

From: Simon Glass sjg@chromium.org
At present the i2c ports are enumerated in a strange way - the fdtdec_find_aliases_for_id() function is used, but then the ID returned is ignored and the ports are renumbered. The effect is the same provided that the device tree has the ports in the same order, or uses aliases, and has no gaps, but it is not correct.
Adjust the code to use the function as intended. This will allows device tree aliases to change the device order if required.
As a result, the i2c_busses variable is dropped. We can't be sure that there are no 'holes' in the list of buses, so must check the whole array.
Note: it seems that non-FDT operation is now broken in this drive and will need to be reinstated for upstream.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-on: https://gerrit.chromium.org/gerrit/59369 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- drivers/i2c/s3c24x0_i2c.c | 25 ++++++++++++++++++------- drivers/i2c/s3c24x0_i2c.h | 1 + 2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index b69da54..9c9b3ba 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -52,7 +52,6 @@ */ static unsigned int g_current_bus __attribute__((section(".data"))); #ifdef CONFIG_OF_CONTROL -static int i2c_busses __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif @@ -164,8 +163,8 @@ int i2c_set_bus_num(unsigned int bus) { struct s3c24x0_i2c *i2c;
- if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { - debug("Bad bus: %d\n", bus); + i2c_bus = get_bus(bus); + if (!i2c_bus) return -1; }
@@ -482,19 +481,31 @@ void board_i2c_init(const void *blob) if (node <= 0) continue; bus = &i2c_bus[i]; + bus->active = true; 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++; + bus->bus_num = i; exynos_pinmux_config(bus->id, 0); } }
+/** + * 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) { - if (bus_idx < i2c_busses) - return &i2c_bus[bus_idx]; + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + }
debug("Undefined bus: %d\n", bus_idx); return NULL; @@ -504,7 +515,7 @@ int i2c_get_bus_num_fdt(int node) { int i;
- for (i = 0; i < i2c_busses; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_bus); i++) { if (node == i2c_bus[i].node) return i; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index b4a337a..882af62 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -16,6 +16,7 @@ struct s3c24x0_i2c { };
struct s3c24x0_i2c_bus { + bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs;

From: Simon Glass sjg@chromium.org
At present the i2c ports are enumerated in a strange way - the fdtdec_find_aliases_for_id() function is used, but then the ID returned is ignored and the ports are renumbered. The effect is the same provided that the device tree has the ports in the same order, or uses aliases, and has no gaps, but it is not correct.
Adjust the code to use the function as intended. This will allows device tree aliases to change the device order if required.
As a result, the i2c_busses variable is dropped. We can't be sure that there are no 'holes' in the list of buses, so must check the whole array.
Note: it seems that non-FDT operation is now broken in this drive and will need to be reinstated for upstream.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-on: https://gerrit.chromium.org/gerrit/59369 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- drivers/i2c/s3c24x0_i2c.c | 25 ++++++++++++++++++------- drivers/i2c/s3c24x0_i2c.h | 1 + 2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index c65360d..0e6f241 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -52,7 +52,6 @@ */ static unsigned int g_current_bus __attribute__((section(".data"))); #ifdef CONFIG_OF_CONTROL -static int i2c_busses __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif @@ -164,8 +163,8 @@ int i2c_set_bus_num(unsigned int bus) { struct s3c24x0_i2c *i2c;
- if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { - debug("Bad bus: %d\n", bus); + i2c_bus = get_bus(bus); + if (!i2c_bus) return -1; }
@@ -483,19 +482,31 @@ void board_i2c_init(const void *blob) if (node <= 0) continue; bus = &i2c_bus[i]; + bus->active = true; 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++; + bus->bus_num = i; exynos_pinmux_config(bus->id, 0); } }
+/** + * 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) { - if (bus_idx < i2c_busses) - return &i2c_bus[bus_idx]; + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + }
debug("Undefined bus: %d\n", bus_idx); return NULL; @@ -505,7 +516,7 @@ int i2c_get_bus_num_fdt(int node) { int i;
- for (i = 0; i < i2c_busses; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_bus); i++) { if (node == i2c_bus[i].node) return i; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index b4a337a..882af62 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -16,6 +16,7 @@ struct s3c24x0_i2c { };
struct s3c24x0_i2c_bus { + bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs;

From: Simon Glass sjg@chromium.org
At present the i2c ports are enumerated in a strange way - the fdtdec_find_aliases_for_id() function is used, but then the ID returned is ignored and the ports are renumbered. The effect is the same provided that the device tree has the ports in the same order, or uses aliases, and has no gaps, but it is not correct.
Adjust the code to use the function as intended. This will allows device tree aliases to change the device order if required.
As a result, the i2c_busses variable is dropped. We can't be sure that there are no 'holes' in the list of buses, so must check the whole array.
Note: it seems that non-FDT operation is now broken in this drive and will need to be reinstated for upstream.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-on: https://gerrit.chromium.org/gerrit/59369 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- Changes since v1: Nonei
Changes since v2: None
Changes since v3: None; ran # ./MAKEALL -v samsung
drivers/i2c/s3c24x0_i2c.c | 25 ++++++++++++++++++------- drivers/i2c/s3c24x0_i2c.h | 1 + 2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index c65360d..0e6f241 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -52,7 +52,6 @@ */ static unsigned int g_current_bus __attribute__((section(".data"))); #ifdef CONFIG_OF_CONTROL -static int i2c_busses __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif @@ -164,8 +163,8 @@ int i2c_set_bus_num(unsigned int bus) { struct s3c24x0_i2c *i2c;
- if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { - debug("Bad bus: %d\n", bus); + i2c_bus = get_bus(bus); + if (!i2c_bus) return -1; }
@@ -483,19 +482,31 @@ void board_i2c_init(const void *blob) if (node <= 0) continue; bus = &i2c_bus[i]; + bus->active = true; 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++; + bus->bus_num = i; exynos_pinmux_config(bus->id, 0); } }
+/** + * 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) { - if (bus_idx < i2c_busses) - return &i2c_bus[bus_idx]; + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + }
debug("Undefined bus: %d\n", bus_idx); return NULL; @@ -505,7 +516,7 @@ int i2c_get_bus_num_fdt(int node) { int i;
- for (i = 0; i < i2c_busses; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_bus); i++) { if (node == i2c_bus[i].node) return i; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index b4a337a..882af62 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -16,6 +16,7 @@ struct s3c24x0_i2c { };
struct s3c24x0_i2c_bus { + bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs;

Hello Naveen,
Am 15.10.2013 12:32, schrieb Naveen Krishna Ch:
From: Simon Glasssjg@chromium.org
At present the i2c ports are enumerated in a strange way - the fdtdec_find_aliases_for_id() function is used, but then the ID returned is ignored and the ports are renumbered. The effect is the same provided that the device tree has the ports in the same order, or uses aliases, and has no gaps, but it is not correct.
Adjust the code to use the function as intended. This will allows device tree aliases to change the device order if required.
As a result, the i2c_busses variable is dropped. We can't be sure that there are no 'holes' in the list of buses, so must check the whole array.
Note: it seems that non-FDT operation is now broken in this drive and will need to be reinstated for upstream.
Signed-off-by: Simon Glasssjg@chromium.org Reviewed-on: https://gerrit.chromium.org/gerrit/59369 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
Changes since v1: Nonei
Changes since v2: None
Changes since v3: None; ran # ./MAKEALL -v samsung
drivers/i2c/s3c24x0_i2c.c | 25 ++++++++++++++++++------- drivers/i2c/s3c24x0_i2c.h | 1 + 2 files changed, 19 insertions(+), 7 deletions(-)
Thanks!
Applied to u-boot-i2c.git
bye, Heiko

Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com --- drivers/i2c/s3c24x0_i2c.c | 612 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 37 +++ 2 files changed, 601 insertions(+), 48 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9c9b3ba..604d43d 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -34,6 +34,76 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */ + +/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31) + +/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4) + +/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff) + +/* I2C_INT_EN Register bits */ +#define HSI2C_TX_UNDERRUN_EN (1u << 2) +#define HSI2C_TX_OVERRUN_EN (1u << 3) +#define HSI2C_RX_UNDERRUN_EN (1u << 4) +#define HSI2C_RX_OVERRUN_EN (1u << 5) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9) + +#define HSI2C_INT_ERROR_MASK (HSI2C_TX_UNDERRUN_EN |\ + HSI2C_TX_OVERRUN_EN |\ + HSI2C_RX_UNDERRUN_EN |\ + HSI2C_RX_OVERRUN_EN |\ + HSI2C_INT_TRAILING_EN) + +/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29) + +/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31) + +/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31) + +/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_TIMEOUT_AUTO (1u << 4) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_SUCCESS (1u << 0) +#define HSI2C_TRANS_ERROR_MASK (HSI2C_TIMEOUT_AUTO |\ + HSI2C_NO_DEV | HSI2C_NO_DEV_ACK |\ + HSI2C_TRANS_ABORT) +#define HSI2C_TRANS_FINISHED_MASK (HSI2C_TRANS_ERROR_MASK | HSI2C_TRANS_SUCCESS) + + +/* I2C_FIFO_STAT Register bits */ +#define HSI2C_RX_FIFO_EMPTY (1u << 24) +#define HSI2C_RX_FIFO_FULL (1u << 23) +#define HSI2C_TX_FIFO_EMPTY (1u << 8) +#define HSI2C_TX_FIFO_FULL (1u << 7) +#define HSI2C_RX_FIFO_LEVEL(x) (((x) >> 16) & 0x7f) +#define HSI2C_TX_FIFO_LEVEL(x) ((x) & 0x7f) + +#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) + +/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -45,6 +115,7 @@
#define I2C_TIMEOUT_MS 1000 /* 1 second */
+#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */
/* * For SPL boot some boards need i2c before SDRAM is initialised so force @@ -56,6 +127,26 @@ static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif
+/** + * 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) +{ + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + } + + debug("Undefined bus: %d\n", bus_idx); + return NULL; +} + #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) { @@ -105,6 +196,55 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return I2C_NOK_TOUT; }
+/* + * Wait for transfer completion. + * + * This function reads the interrupt status register waiting for the INT_I2C + * bit to be set, which indicates copletion of a transaction. + * + * @param i2c: pointer to the appropriate register bank + * + * @return: I2C_OK in case of successful completion, I2C_NOK_TIMEOUT in case + * the status bits do not get set in time, or an approrpiate error + * value in case of transfer errors. + */ +static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (i-- > 0) { + u32 int_status = readl(&i2c->usi_int_stat); + + if (int_status & HSI2C_INT_I2C_EN) { + u32 trans_status = readl(&i2c->usi_trans_status); + + /* Deassert pending interrupt. */ + writel(int_status, &i2c->usi_int_stat); + + if (trans_status & HSI2C_NO_DEV_ACK) { + debug("%s: no ACK from device\n", __func__); + return I2C_NACK; + } + if (trans_status & HSI2C_NO_DEV) { + debug("%s: no device\n", __func__); + return I2C_NOK; + } + if (trans_status & HSI2C_TRANS_ABORT) { + debug("%s: arbitration lost\n", __func__); + return I2C_NOK_LA; + } + if (trans_status & HSI2C_TIMEOUT_AUTO) { + debug("%s: device timed out\n", __func__); + return I2C_NOK_TOUT; + } + return I2C_OK; + } + udelay(1); + } + debug("%s: transaction timeout!\n", __func__); + return I2C_NOK_TOUT; +} + static void ReadWriteByte(struct s3c24x0_i2c *i2c) { writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); @@ -154,6 +294,104 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + ulong clkin = get_i2c_clk(); + unsigned int op_clk = i2c_bus->clock_frequency; + unsigned int i = 0, utemp0 = 0, utemp1 = 0; + unsigned int t_ftl_cycle; + + /* FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE + * uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * uTemp1 = (TSCLK_L + TSCLK_H + 2) + * uTemp2 = TSCLK_L + TSCLK_H + */ + t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7; + utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; + + /* CLK_DIV max is 256 */ + for (i = 0; i < 256; i++) { + utemp1 = utemp0 / (i + 1); + if ((utemp1 < 512) && (utemp1 > 4)) { + i2c_bus->clk_cycle = utemp1 - 2; + i2c_bus->clk_div = i; + return 0; + } + } + return -1; +} + +static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + unsigned int t_sr_release; + unsigned int n_clkdiv; + unsigned int t_start_su, t_start_hd; + unsigned int t_stop_su; + unsigned int t_data_su, t_data_hd; + unsigned int t_scl_l, t_scl_h; + u32 i2c_timing_s1; + u32 i2c_timing_s2; + u32 i2c_timing_s3; + u32 i2c_timing_sla; + + n_clkdiv = i2c_bus->clk_div; + t_scl_l = i2c_bus->clk_cycle / 2; + t_scl_h = i2c_bus->clk_cycle / 2; + t_start_su = t_scl_l; + t_start_hd = t_scl_l; + t_stop_su = t_scl_l; + t_data_su = t_scl_l / 2; + t_data_hd = t_scl_l / 2; + t_sr_release = i2c_bus->clk_cycle; + + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; + i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0; + i2c_timing_sla = t_data_hd << 0; + + writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl); + + /* Clear to enable Timeout */ + clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0); + + /* set AUTO mode */ + writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf); + + /* Enable completion conditions' reporting. */ + writel(HSI2C_INT_I2C_EN, &hsregs->usi_int_en); + + /* Enable FIFOs */ + writel(HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN, &hsregs->usi_fifo_ctl); + + /* Currently operating in Fast speed mode. */ + writel(i2c_timing_s1, &hsregs->usi_timing_fs1); + writel(i2c_timing_s2, &hsregs->usi_timing_fs2); + writel(i2c_timing_s3, &hsregs->usi_timing_fs3); + writel(i2c_timing_sla, &hsregs->usi_timing_sla); +} + +/* SW reset for the high speed bus */ +static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *i2c = i2c_bus->hsregs; + u32 i2c_ctl; + + /* Set and clear the bit for reset */ + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl |= HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl &= ~HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + /* Initialize the configure registers */ + hsi2c_ch_init(i2c_bus); +} + /* * MULTI BUS I2C support */ @@ -161,16 +399,21 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus;
i2c_bus = get_bus(bus); if (!i2c_bus) return -1; - } - g_current_bus = bus; - i2c = get_base_i2c(); - i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + 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; } @@ -254,6 +497,227 @@ void i2c_init(int speed, int slaveadd) }
/* + * Poll the appropriate bit of the fifo status register until the interface is + * ready to process the next byte or timeout expires. + * + * In addition to the FIFO status register this function also polls the + * interrupt status register to be able to detect unexpected transaction + * completion. + * + * When FIFO is ready to process the next byte, this function returns I2C_OK. + * If in course of polling the INT_I2C assertion is detected, the function + * returns I2C_NOK. If timeout happens before any of the above conditions is + * met - the function returns I2C_NOK_TOUT; + + * @param i2c: pointer to the appropriate i2c register bank. + * @param rx_transfer: set to True if the receive transaction is in progress. + * @return: as described above. + */ +static unsigned hsi2c_poll_fifo(struct exynos5_hsi2c *i2c, bool rx_transfer) +{ + u32 fifo_bit = rx_transfer ? HSI2C_RX_FIFO_EMPTY : HSI2C_TX_FIFO_FULL; + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_fifo_stat) & fifo_bit) { + if (readl(&i2c->usi_int_stat) & HSI2C_INT_I2C_EN) { + /* + * There is a chance that assertion of + * HSI2C_INT_I2C_EN and deassertion of + * HSI2C_RX_FIFO_EMPTY happen simultaneously. Let's + * give FIFO status priority and check it one more + * time before reporting interrupt. The interrupt will + * be reported next time this function is called. + */ + if (rx_transfer && + !(readl(&i2c->usi_fifo_stat) & fifo_bit)) + break; + return I2C_NOK; + } + if (!i--) { + debug("%s: FIFO polling timeout!\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +/* + * Preapre hsi2c transaction, either read or write. + * + * Set up transfer as described in section 27.5.1.2 'I2C Channel Auto Mode' of + * the 5420 UM. + * + * @param i2c: pointer to the appropriate i2c register bank. + * @param chip: slave address on the i2c bus (with read/write bit exlcuded) + * @param len: number of bytes expected to be sent or received + * @param rx_transfer: set to true for receive transactions + * @param: issue_stop: set to true if i2c stop condition should be generated + * after this transaction. + * @return: I2C_NOK_TOUT in case the bus remained busy for HSI2C_TIMEOUT_US, + * I2C_OK otherwise. + */ +static int hsi2c_prepare_transaction(struct exynos5_hsi2c *i2c, + u8 chip, + u16 len, + bool rx_transfer, + bool issue_stop) +{ + u32 conf; + + conf = len | HSI2C_MASTER_RUN; + + if (issue_stop) + conf |= HSI2C_STOP_AFTER_TRANS; + + /* Clear to enable Timeout */ + writel(readl(&i2c->usi_timeout) & ~HSI2C_TIMEOUT_EN, &i2c->usi_timeout); + + /* Set slave address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + if (rx_transfer) { + /* i2c master, read transaction */ + writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* read up to len bytes, stop after transaction is finished */ + writel(conf | HSI2C_READ_WRITE, &i2c->usi_auto_conf); + } else { + /* i2c master, write transaction */ + writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* write up to len bytes, stop after transaction is finished */ + writel(conf, &i2c->usi_auto_conf); + } + + /* Reset all pending interrupt status bits we care about, if any */ + writel(HSI2C_INT_I2C_EN, &i2c->usi_int_stat); + + return I2C_OK; +} + +/* + * Wait while i2c bus is settling down (mostly stop gets completed). + */ +static int hsi2c_wait_while_busy(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY) { + if (!i--) { + debug("%s: bus busy\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +static int hsi2c_write(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len, + bool issue_stop) +{ + int i, rv = 0; + + if (!(len + alen)) { + /* Writes of zero length not supported in auto mode. */ + debug("%s: zero length writes not supported\n", __func__); + return I2C_NOK; + } + + rv = hsi2c_prepare_transaction + (i2c, chip, len + alen, false, issue_stop); + if (rv != I2C_OK) + return rv; + + /* Move address, if any, and the data, if any, into the FIFO. */ + for (i = 0; i < alen; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: address write failed\n", __func__); + goto write_error; + } + writel(addr[i], &i2c->usi_txdata); + } + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: data write failed\n", __func__); + goto write_error; + } + writel(data[i], &i2c->usi_txdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + write_error: + if (issue_stop) { + int tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + } + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +static int hsi2c_read(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len) +{ + int i, rv, tmp_ret; + bool drop_data = false; + + if (!len) { + /* Reads of zero length not supported in auto mode. */ + debug("%s: zero length read adjusted\n", __func__); + drop_data = true; + len = 1; + } + + if (alen) { + /* Internal register adress needs to be written first. */ + rv = hsi2c_write(i2c, chip, addr, alen, NULL, 0, false); + if (rv != I2C_OK) + return rv; + } + + rv = hsi2c_prepare_transaction(i2c, chip, len, true, true); + + if (rv != I2C_OK) + return rv; + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, true); + if (rv != I2C_OK) + goto read_err; + if (drop_data) + continue; + data[i] = readl(&i2c->usi_rxdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + read_err: + tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +/* * cmd_type is 0 for write, 1 for read. * * addr_len can take any value from 0-255, it is only limited @@ -367,10 +831,13 @@ bailout:
int i2c_probe(uchar chip) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar buf[1]; + int ret;
- i2c = get_base_i2c(); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; buf[0] = 0;
/* @@ -378,12 +845,21 @@ 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(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; + if (i2c_bus->is_highspeed) { + ret = hsi2c_read(i2c_bus->hsregs, + chip, 0, 0, buf, 1); + } else { + ret = i2c_transfer(i2c_bus->regs, + I2C_READ, chip << 1, 0, 0, buf, 1); + } + + + return ret != I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; int ret;
@@ -415,11 +891,21 @@ 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 = get_base_i2c(); - ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len); - if (ret != 0) { - debug("I2c read: failed %d\n", ret); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len); + else + ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + debug("I2c read failed %d\n", ret); return 1; } return 0; @@ -427,8 +913,9 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; + int ret;
if (alen > 4) { debug("I2C write: addr len %d not supported\n", alen); @@ -457,58 +944,80 @@ 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 = get_base_i2c(); - return (i2c_transfer - (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, - len) != 0); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len, true); + else + ret = i2c_transfer(i2c_bus->regs, I2C_WRITE, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret != 0) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + return 1; + } else { + return 0; + } }
#ifdef CONFIG_OF_CONTROL -void board_i2c_init(const void *blob) +static void process_nodes(const void *blob, int node_list[], int count, + int is_highspeed) { + struct s3c24x0_i2c_bus *bus; int i; - int node_list[CONFIG_MAX_I2C_NUM]; - int count; - - 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->active = true; - bus->regs = (struct s3c24x0_i2c *) - fdtdec_get_addr(blob, node, "reg"); + bus->is_highspeed = is_highspeed; + + if (is_highspeed) + bus->hsregs = (struct exynos5_hsi2c *) + fdtdec_get_addr(blob, node, "reg"); + else + bus->regs = (struct s3c24x0_i2c *) + fdtdec_get_addr(blob, node, "reg"); + bus->id = pinmux_decode_periph_id(blob, node); + bus->clock_frequency = fdtdec_get_int(blob, node, + "clock-frequency", + CONFIG_SYS_I2C_SPEED); bus->node = node; bus->bus_num = i; exynos_pinmux_config(bus->id, 0); + + /* Mark position as used */ + node_list[i] = -1; } }
-/** - * 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) +void board_i2c_init(const void *blob) { - if (bus_idx < ARRAY_SIZE(i2c_bus)) { - struct s3c24x0_i2c_bus *bus; + int node_list[CONFIG_MAX_I2C_NUM]; + int count;
- bus = &i2c_bus[bus_idx]; - if (bus->active) - return bus; - } + /* First get the normal i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_S3C2440_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 0); + + /* Now look for high speed i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 1);
- debug("Undefined bus: %d\n", bus_idx); - return NULL; }
int i2c_get_bus_num_fdt(int node) @@ -526,7 +1035,7 @@ int i2c_get_bus_num_fdt(int node)
int i2c_reset_port_fdt(const void *blob, int node) { - struct s3c24x0_i2c_bus *i2c; + struct s3c24x0_i2c_bus *i2c_bus; int bus;
bus = i2c_get_bus_num_fdt(node); @@ -535,13 +1044,20 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
- i2c = get_bus(bus); - if (!i2c) { + i2c_bus = get_bus(bus); + if (!i2c_bus) { 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); + 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; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index 882af62..1ae73d2 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -15,11 +15,48 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c { + u32 usi_ctl; + u32 usi_fifo_ctl; + u32 usi_trailing_ctl; + u32 usi_clk_ctl; + u32 usi_clk_slot; + u32 spi_ctl; + u32 uart_ctl; + u32 res1; + u32 usi_int_en; + u32 usi_int_stat; + u32 usi_modem_stat; + u32 usi_error_stat; + u32 usi_fifo_stat; + u32 usi_txdata; + u32 usi_rxdata; + u32 res2; + u32 usi_conf; + u32 usi_auto_conf; + u32 usi_timeout; + u32 usi_manual_cmd; + u32 usi_trans_status; + u32 usi_timing_hs1; + u32 usi_timing_hs2; + u32 usi_timing_hs3; + u32 usi_timing_fs1; + u32 usi_timing_fs2; + u32 usi_timing_fs3; + u32 usi_timing_sla; + u32 i2c_addr; +}; + struct s3c24x0_i2c_bus { bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs; + struct exynos5_hsi2c *hsregs; + int is_highspeed; /* High speed type, rather than I2C */ + unsigned clock_frequency; int id; + unsigned clk_cycle; + unsigned clk_div; }; #endif /* _S3C24X0_I2C_H */

This enables CONFIG_SYS_I2C on Samsung, updating existing s3c24x0 i2c driver to support this.
Note: Not for merge, Just for review and suggestions.
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- drivers/i2c/Makefile | 2 +- drivers/i2c/s3c24x0_i2c.c | 156 +++++++++++++++++++++++++++++++-------------- 2 files changed, 108 insertions(+), 50 deletions(-)
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 37ccbd1..96448a6 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_S3C44B0_I2C) += s3c44b0_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 604d43d..89cb2d2 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -117,6 +117,8 @@
#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */
+DECLARE_GLOBAL_DATA_PTR; + /* * For SPL boot some boards need i2c before SDRAM is initialised so force * variables to live in SRAM @@ -126,6 +128,9 @@ static unsigned int g_current_bus __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif +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 @@ -133,20 +138,40 @@ static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] * @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_bus[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; +} + #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) { @@ -392,39 +417,7 @@ 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) { struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -493,9 +486,15 @@ 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_bus->regs, speed, slaveaddr); }
+static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) +{ + i2c_set_bus_speed(speed); +} /* * Poll the appropriate bit of the fifo status register until the interface is * ready to process the next byte or timeout expires. @@ -829,13 +828,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; @@ -857,7 +856,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]; @@ -891,7 +891,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;
@@ -911,7 +911,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]; @@ -944,7 +945,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;
@@ -1000,6 +1001,25 @@ static void process_nodes(const void *blob, int node_list[], int count, node_list[i] = -1; } } +void i2c_init_board() +{ + int node_list[CONFIG_MAX_I2C_NUM]; + const void *blob = gd->fdt_blob; + int count; + + /* First get the normal i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_S3C2440_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 0); + + /* Now look for high speed i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 1); + +}
void board_i2c_init(const void *blob) { @@ -1017,9 +1037,10 @@ void board_i2c_init(const void *blob) COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, CONFIG_MAX_I2C_NUM); process_nodes(blob, node_list, count, 1); - }
+#ifndef CONFIG_SYS_I2C +/* TODO: fix this as per comments from upstream */ int i2c_get_bus_num_fdt(int node) { int i; @@ -1062,5 +1083,42 @@ int i2c_reset_port_fdt(const void *blob, int node) return 0; } #endif +#endif
+/* + * Register soft i2c adapters + */ +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) +U_BOOT_I2C_ADAP_COMPLETE(s3c1, 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(s3c2, 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(s3c3, 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(s3c4, 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(s3c5, 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(s3c6, 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(s3c7, 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(s3c8, 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(s3c9, 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(s3c10, exynos_i2c_init, s3c_i2c_probe, + s3c_i2c_read, s3c_i2c_write, + s3c_i2c_set_bus_speed, 100000, 0, 10) #endif /* CONFIG_HARD_I2C */

Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This enables CONFIG_SYS_I2C on Samsung, updating existing s3c24x0 i2c driver to support this.
Note: Not for merge, Just for review and suggestions.
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
drivers/i2c/Makefile | 2 +- drivers/i2c/s3c24x0_i2c.c | 156 +++++++++++++++++++++++++++++++-------------- 2 files changed, 108 insertions(+), 50 deletions(-)
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 37ccbd1..96448a6 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
Please keep lists sorted.
COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 604d43d..89cb2d2 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -117,6 +117,8 @@
#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */
+DECLARE_GLOBAL_DATA_PTR;
- /*
- For SPL boot some boards need i2c before SDRAM is initialised so force
- variables to live in SRAM
@@ -126,6 +128,9 @@ static unsigned int g_current_bus __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif +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
@@ -133,20 +138,40 @@ static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
- @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_bus[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;
+}
- #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) {
@@ -392,39 +417,7 @@ 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) { struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -493,9 +486,15 @@ 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_bus->regs, speed, slaveaddr); }
+static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) +{
- i2c_set_bus_speed(speed);
+} /*
- Poll the appropriate bit of the fifo status register until the interface is
- ready to process the next byte or timeout expires.
@@ -829,13 +828,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;
@@ -857,7 +856,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,
{ struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4];uchar *buffer, int len)
@@ -891,7 +891,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;
@@ -911,7 +911,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,
{ struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4];uchar *buffer, int len)
@@ -944,7 +945,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;
@@ -1000,6 +1001,25 @@ static void process_nodes(const void *blob, int node_list[], int count, node_list[i] = -1; } } +void i2c_init_board() +{
- int node_list[CONFIG_MAX_I2C_NUM];
- const void *blob = gd->fdt_blob;
- int count;
- /* First get the normal i2c ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_S3C2440_I2C, node_list,
CONFIG_MAX_I2C_NUM);
- process_nodes(blob, node_list, count, 0);
- /* Now look for high speed i2c ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
CONFIG_MAX_I2C_NUM);
- process_nodes(blob, node_list, count, 1);
+}
void board_i2c_init(const void *blob) { @@ -1017,9 +1037,10 @@ void board_i2c_init(const void *blob) COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, CONFIG_MAX_I2C_NUM); process_nodes(blob, node_list, count, 1);
- }
+#ifndef CONFIG_SYS_I2C +/* TODO: fix this as per comments from upstream */
Why this? If we switch to the new i2c framework, please convert all boards, which using this driver ...
int i2c_get_bus_num_fdt(int node) { int i; @@ -1062,5 +1083,42 @@ int i2c_reset_port_fdt(const void *blob, int node) return 0; } #endif +#endif
+/*
- Register soft i2c adapters
- */
+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)
+U_BOOT_I2C_ADAP_COMPLETE(s3c1, 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(s3c2, 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(s3c3, 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(s3c4, 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(s3c5, 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(s3c6, 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(s3c7, 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(s3c8, 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(s3c9, 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(s3c10, exynos_i2c_init, s3c_i2c_probe,
s3c_i2c_read, s3c_i2c_write,
#endif /* CONFIG_HARD_I2C */s3c_i2c_set_bus_speed, 100000, 0, 10)
Beside of that, it looks good to me.
Thanks for your work!
bye, Heiko

Dear Naveen,
On 10/14/2013 08:06 AM, Heiko Schocher wrote:
Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This enables CONFIG_SYS_I2C on Samsung, updating existing s3c24x0 i2c driver to support this.
Note: Not for merge, Just for review and suggestions.
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
drivers/i2c/Makefile | 2 +- drivers/i2c/s3c24x0_i2c.c | 156 +++++++++++++++++++++++++++++++-------------- 2 files changed, 108 insertions(+), 50 deletions(-)
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 37ccbd1..96448a6 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
Please keep lists sorted.
COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 604d43d..89cb2d2 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -117,6 +117,8 @@
#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */
+DECLARE_GLOBAL_DATA_PTR;
- /*
- For SPL boot some boards need i2c before SDRAM is initialised so
force
- variables to live in SRAM
@@ -126,6 +128,9 @@ static unsigned int g_current_bus __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif +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
@@ -133,20 +138,40 @@ static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
- @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_bus[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;
+}
- #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) {
@@ -392,39 +417,7 @@ 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) { struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -493,9 +486,15 @@ 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_bus->regs, speed, slaveaddr); }
+static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) +{
- i2c_set_bus_speed(speed);
+} /*
- Poll the appropriate bit of the fifo status register until the
interface is
- ready to process the next byte or timeout expires.
@@ -829,13 +828,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;
@@ -857,7 +856,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,
{ struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4];uchar *buffer, int len)
@@ -891,7 +891,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;
@@ -911,7 +911,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,
{ struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4];uchar *buffer, int len)
@@ -944,7 +945,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;
@@ -1000,6 +1001,25 @@ static void process_nodes(const void *blob, int node_list[], int count, node_list[i] = -1; } } +void i2c_init_board() +{
- int node_list[CONFIG_MAX_I2C_NUM];
- const void *blob = gd->fdt_blob;
- int count;
- /* First get the normal i2c ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_S3C2440_I2C, node_list,
CONFIG_MAX_I2C_NUM);
- process_nodes(blob, node_list, count, 0);
- /* Now look for high speed i2c ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
CONFIG_MAX_I2C_NUM);
- process_nodes(blob, node_list, count, 1);
+}
void board_i2c_init(const void *blob) { @@ -1017,9 +1037,10 @@ void board_i2c_init(const void *blob) COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, CONFIG_MAX_I2C_NUM); process_nodes(blob, node_list, count, 1);
- }
+#ifndef CONFIG_SYS_I2C +/* TODO: fix this as per comments from upstream */
Why this? If we switch to the new i2c framework, please convert all boards, which using this driver ...
int i2c_get_bus_num_fdt(int node) { int i; @@ -1062,5 +1083,42 @@ int i2c_reset_port_fdt(const void *blob, int node) return 0; } #endif +#endif
+/*
- Register soft i2c adapters
- */
+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)
+U_BOOT_I2C_ADAP_COMPLETE(s3c1, 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(s3c2, 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(s3c3, 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(s3c4, 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(s3c5, 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(s3c6, 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(s3c7, 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(s3c8, 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(s3c9, 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(s3c10, exynos_i2c_init, s3c_i2c_probe,
s3c_i2c_read, s3c_i2c_write,
#endif /* CONFIG_HARD_I2C */s3c_i2c_set_bus_speed, 100000, 0, 10)
Beside of that, it looks good to me.
I have some patches based on this patch. Do you plan send updated version? It would be nice to switch that driver to the new framework.
Thanks for your work!
bye, Heiko
Best regards, Piotr Wilczek

Hello Piotr,
On 8 November 2013 13:15, Piotr Wilczek p.wilczek@samsung.com wrote:
Dear Naveen,
On 10/14/2013 08:06 AM, Heiko Schocher wrote:
Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This enables CONFIG_SYS_I2C on Samsung, updating existing s3c24x0 i2c driver to support this.
Note: Not for merge, Just for review and suggestions.
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
drivers/i2c/Makefile | 2 +- drivers/i2c/s3c24x0_i2c.c | 156 +++++++++++++++++++++++++++++++-------------- 2 files changed, 108 insertions(+), 50 deletions(-)
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 37ccbd1..96448a6 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
Please keep lists sorted.
COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 604d43d..89cb2d2 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -117,6 +117,8 @@
#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */
+DECLARE_GLOBAL_DATA_PTR;
- /*
- For SPL boot some boards need i2c before SDRAM is initialised so
force
- variables to live in SRAM
@@ -126,6 +128,9 @@ static unsigned int g_current_bus __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif +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
@@ -133,20 +138,40 @@ static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
- @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_bus[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;
+}
- #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) {
@@ -392,39 +417,7 @@ 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) { struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -493,9 +486,15 @@ 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_bus->regs, speed, slaveaddr); }
+static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) +{
- i2c_set_bus_speed(speed);
+} /*
- Poll the appropriate bit of the fifo status register until the
interface is
- ready to process the next byte or timeout expires.
@@ -829,13 +828,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;
@@ -857,7 +856,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,
{ struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4];uchar *buffer, int len)
@@ -891,7 +891,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;
@@ -911,7 +911,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,
{ struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4];uchar *buffer, int len)
@@ -944,7 +945,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;
@@ -1000,6 +1001,25 @@ static void process_nodes(const void *blob, int node_list[], int count, node_list[i] = -1; } } +void i2c_init_board() +{
- int node_list[CONFIG_MAX_I2C_NUM];
- const void *blob = gd->fdt_blob;
- int count;
- /* First get the normal i2c ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_S3C2440_I2C, node_list,
CONFIG_MAX_I2C_NUM);
- process_nodes(blob, node_list, count, 0);
- /* Now look for high speed i2c ports */
- count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
CONFIG_MAX_I2C_NUM);
- process_nodes(blob, node_list, count, 1);
+}
void board_i2c_init(const void *blob) { @@ -1017,9 +1037,10 @@ void board_i2c_init(const void *blob) COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, CONFIG_MAX_I2C_NUM); process_nodes(blob, node_list, count, 1);
- }
+#ifndef CONFIG_SYS_I2C +/* TODO: fix this as per comments from upstream */
Why this? If we switch to the new i2c framework, please convert all boards, which using this driver ...
int i2c_get_bus_num_fdt(int node) { int i; @@ -1062,5 +1083,42 @@ int i2c_reset_port_fdt(const void *blob, int node) return 0; } #endif +#endif
+/*
- Register soft i2c adapters
- */
+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)
+U_BOOT_I2C_ADAP_COMPLETE(s3c1, 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(s3c2, 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(s3c3, 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(s3c4, 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(s3c5, 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(s3c6, 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(s3c7, 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(s3c8, 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(s3c9, 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(s3c10, exynos_i2c_init, s3c_i2c_probe,
s3c_i2c_read, s3c_i2c_write,
#endif /* CONFIG_HARD_I2C */s3c_i2c_set_bus_speed, 100000, 0, 10)
Beside of that, it looks good to me.
I have some patches based on this patch. Do you plan send updated version? It would be nice to switch that driver to the new framework.
I don't, have the updated patch ready.
I had a problem with the bus id's being scrambled with the new i2c framework. Also, we need to update the new config in all the boards which are using this driver. I was in and out of that work.
If you have a better patch, feel free to update this patch as well.
Thanks for your work!
bye, Heiko
Best regards, Piotr Wilczek
U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

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

This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 222 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/README b/README index c97ff0a..c04e352 100644 --- a/README +++ b/README @@ -2076,6 +2076,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
+ - drivers/i2c/s3c24x0_i2c.c: + - activate this driver with CONFIG_SYS_I2C_S3C24X0 + - This driver adds i2c buses (11 for Exynos5250, Exynos5420 + 9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from Samsung) + with a fix speed from 100000 and the slave addr 0! + additional defines:
CONFIG_SYS_NUM_I2C_BUSES diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..6e719ec 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,15 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, 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); + if (i2c_set_bus_speed(speed)) + printf("i2c_init: failed to init bus %d for speed = %d\n", + adap->hwadapnr, speed); +} + /* * cmd_type is 0 for write, 1 for read. * @@ -1071,51 +1080,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /* * Register s3c24x0 i2c adapters */ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 0) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_1, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 1) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_2, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 2) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_3, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 3) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_4, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 4) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_5, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 5) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_6, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 6) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_7, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 7) +#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 8) +U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 9) +U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 10) +#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 8) +U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 9) +U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 10) +#elif defined(CONFIG_EXYNOS4) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 8 +#else +U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +#endif

Hello All,
On 25 November 2013 16:58, Naveen Krishna Chatradhi ch.naveen@samsung.com wrote:
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 222 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/README b/README index c97ff0a..c04e352 100644 --- a/README +++ b/README @@ -2076,6 +2076,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
- drivers/i2c/s3c24x0_i2c.c:
- activate this driver with CONFIG_SYS_I2C_S3C24X0
- This driver adds i2c buses (11 for Exynos5250, Exynos5420
9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from Samsung)
with a fix speed from 100000 and the slave addr 0!
additional defines: CONFIG_SYS_NUM_I2C_BUSES
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..6e719ec 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,15 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, 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);
if (i2c_set_bus_speed(speed))
printf("i2c_init: failed to init bus %d for speed = %d\n",
adap->hwadapnr, speed);
+}
/*
- cmd_type is 0 for write, 1 for read.
@@ -1071,51 +1080,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /*
- Register s3c24x0 i2c adapters
*/ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
0)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_1, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
1)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_2, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
2)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_3, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
3)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_4, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
4)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_5, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
5)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_6, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
6)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_7, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
7)
+#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS4) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8
+#else +U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+#endif
1.7.10.4
These changes go on top of the http://patchwork.ozlabs.org/patch/292706/ by Piotr These changes were discussed earlier at http://www.mail-archive.com/u-boot@lists.denx.de/msg126318.html
Tested Exynso5420 based SMDK5420 and build tested on ./MAKEALL -v samsung

Hello Naveen,
Sorry for the late reply ...
Am 25.11.2013 12:28, schrieb Naveen Krishna Ch:
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 222 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/README b/README index c97ff0a..c04e352 100644 --- a/README +++ b/README @@ -2076,6 +2076,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
- drivers/i2c/s3c24x0_i2c.c:
- activate this driver with CONFIG_SYS_I2C_S3C24X0
- This driver adds i2c buses (11 for Exynos5250, Exynos5420
9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from Samsung)
with a fix speed from 100000 and the slave addr 0!
additional defines:
CONFIG_SYS_NUM_I2C_BUSES
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..6e719ec 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,15 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, 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);
- if (i2c_set_bus_speed(speed))
printf("i2c_init: failed to init bus %d for speed = %d\n",
adap->hwadapnr, speed);
+}
- /*
- cmd_type is 0 for write, 1 for read.
@@ -1071,51 +1080,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /*
- Register s3c24x0 i2c adapters
*/ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
0)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_1, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
1)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_2, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
2)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_3, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
3)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_4, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
4)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_5, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
5)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_6, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
6)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_7, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
7)
+#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS4) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8
^ leads in a compile error for trats and trats2, could you please fix?
Hmm... could you reformat this very long list in something like this:
U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe, if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c1, s3c24x0_i2c_init, s3c24x0_i2c_probe, [...] U_BOOT_I2C_ADAP_COMPLETE(s3c8, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif if defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c9, s3c24x0_i2c_init, s3c24x0_i2c_probe, U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif
+#else +U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+#endif
bye, Heiko

Hello Heiko,
On 5 December 2013 16:56, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
Sorry for the late reply ...
Am 25.11.2013 12:28, schrieb Naveen Krishna Ch:
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 222 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/README b/README index c97ff0a..c04e352 100644 --- a/README +++ b/README @@ -2076,6 +2076,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
- drivers/i2c/s3c24x0_i2c.c:
- activate this driver with CONFIG_SYS_I2C_S3C24X0
- This driver adds i2c buses (11 for Exynos5250,
Exynos5420
9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from
Samsung)
with a fix speed from 100000 and the slave addr 0!
additional defines: CONFIG_SYS_NUM_I2C_BUSES
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..6e719ec 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,15 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, 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);
if (i2c_set_bus_speed(speed))
printf("i2c_init: failed to init bus %d for speed = %d\n",
adap->hwadapnr, speed);
+}
This init is not used for Exynos4 and lower series SoCs
- /*
- cmd_type is 0 for write, 1 for read.
@@ -1071,51 +1080,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /*
- Register s3c24x0 i2c adapters
*/ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
0)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_1, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
1)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_2, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
2)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_3, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
3)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_4, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
4)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_5, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
5)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_6, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
6)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_7, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
7)
+#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS4) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8
^
leads in a compile error for trats and trats2, could you please fix?
I ran "MAKEALL -v samsung" s3c24x0_i2c.c:724:13: warning: 'exynos_i2c_init' defined but not used [-Wunused-function] is the warning seen for trats and trats2 boards If you are talking about this one, will fix it in the next versio.
Hmm... could you reformat this very long list in something like this:
U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe, if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c1, s3c24x0_i2c_init, s3c24x0_i2c_probe, [...] U_BOOT_I2C_ADAP_COMPLETE(s3c8, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif if defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c9, s3c24x0_i2c_init, s3c24x0_i2c_probe, U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif
Basically, s3c24x0_i2c.c now support both HighSpeed I2C modules and Standard I2C Modules. They have different init functions. Exynos5250/5260 has 4 hsi2c channels hsi2c 0 ~ 3 and 7 i2c channels 4 ~ 10 Exynos5420 has 4 i2c channels i2c 0 ~ 3 and 7 hsi2c channels 4 ~ 10 Exynos4 has 9 i2c channels Hence, the long list. It would be helpful if anyone can suggest a way to reduce this list.
Is U_BOOT_I2C_ADAP_COMPLETE is the only (best) way to register to new i2c framework ?
+#else +U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+#endif
bye, Heiko
Thanks for the review.
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot

Hello Naveen,
Am 05.12.2013 13:21, schrieb Naveen Krishna Ch:
Hello Heiko,
On 5 December 2013 16:56, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Sorry for the late reply ...
Am 25.11.2013 12:28, schrieb Naveen Krishna Ch:
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 222 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/README b/README index c97ff0a..c04e352 100644 --- a/README +++ b/README @@ -2076,6 +2076,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
- drivers/i2c/s3c24x0_i2c.c:
- activate this driver with CONFIG_SYS_I2C_S3C24X0
- This driver adds i2c buses (11 for Exynos5250,
Exynos5420
9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from
Samsung)
with a fix speed from 100000 and the slave addr 0!
additional defines: CONFIG_SYS_NUM_I2C_BUSES
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..6e719ec 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,15 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, 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);
if (i2c_set_bus_speed(speed))
printf("i2c_init: failed to init bus %d for speed = %d\n",
adap->hwadapnr, speed);
+}
This init is not used for Exynos4 and lower series SoCs
- /*
- cmd_type is 0 for write, 1 for read.
@@ -1071,51 +1080,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /* * Register s3c24x0 i2c adapters */ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
0)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_1, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
1)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_2, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
2)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_3, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
3)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_4, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
4)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_5, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
5)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_6, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
6)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_7, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
7)
+#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS4) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8
^
leads in a compile error for trats and trats2, could you please fix?
I ran "MAKEALL -v samsung" s3c24x0_i2c.c:724:13: warning: 'exynos_i2c_init' defined but not used [-Wunused-function] is the warning seen for trats and trats2 boards If you are talking about this one, will fix it in the next versio.
No, there is a missing ")" at the end!
pollux:u-boot hs [master] $ ./MAKEALL trats Configuring for trats board... s3c24x0_i2c.c:1247:0: error: unterminated argument list invoking macro "U_BOOT_I2C_ADAP_COMPLETE" s3c24x0_i2c.c:1236:1: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c:1247:0: error: unterminated argument list invoking macro "U_BOOT_I2C_ADAP_COMPLETE" s3c24x0_i2c.c:1236:1: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input s3c24x0_i2c.c:724:13: warning: 'exynos_i2c_init' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make[1]: *** Warte auf noch nicht beendete Prozesse... make: *** [drivers/i2c/built-in.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
--------------------- SUMMARY ---------------------------- Boards compiled: 1 Boards with errors: 1 ( trats ) ---------------------------------------------------------- pollux:u-boot hs [master] $
pollux:u-boot hs [(kein Zweig, Neuaufbau begonnen bei master)] $ git bisect log git bisect start # bad: [f5f40408ce3b00637c652fdabfb6f3c4e0d09635] arm: omap: i2c: don't zero cnt in i2c_write git bisect bad f5f40408ce3b00637c652fdabfb6f3c4e0d09635 # good: [f44483b57c49282299da0e5c10073b909cdad979] Merge branch 'serial' of git://git.denx.de/u-boot-microblaze git bisect good f44483b57c49282299da0e5c10073b909cdad979 # bad: [4d06a7c5707f813f4bc7fd7a9d700606c63fa4de] i2c: fti2c010: cosmetic: coding style cleanup git bisect bad 4d06a7c5707f813f4bc7fd7a9d700606c63fa4de # good: [a6756bbdac43474193472b43309626e2c28d8100] driver:i2c:s3c24x0: fix clock init for hsi2c git bisect good a6756bbdac43474193472b43309626e2c28d8100 # bad: [c3b6bba20862ff6476c99aa6d3168f7097a5b4b2] i2c: samsung: register i2c busses for Exynso5420 and Exynos5250 git bisect bad c3b6bba20862ff6476c99aa6d3168f7097a5b4b2 # first bad commit: [c3b6bba20862ff6476c99aa6d3168f7097a5b4b2] i2c: samsung: register i2c busses for Exynso5420 and Exynos5250 pollux:u-boot hs [(kein Zweig, Neuaufbau begonnen bei master)] $
Hmm... could you reformat this very long list in something like this:
U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe, if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c1, s3c24x0_i2c_init, s3c24x0_i2c_probe, [...] U_BOOT_I2C_ADAP_COMPLETE(s3c8, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif if defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c9, s3c24x0_i2c_init, s3c24x0_i2c_probe, U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif
Basically, s3c24x0_i2c.c now support both HighSpeed I2C modules and Standard I2C Modules. They have different init functions. Exynos5250/5260 has 4 hsi2c channels hsi2c 0 ~ 3 and 7 i2c channels 4 ~ 10 Exynos5420 has 4 i2c channels i2c 0 ~ 3 and 7 hsi2c channels 4 ~ 10 Exynos4 has 9 i2c channels Hence, the long list. It would be helpful if anyone can suggest a way to reduce this list.
Ah, now I see it, thanks!
Maybe we can define one s3c24x0_i2c_init function, and call from there the SoC / adapater specific init func? So we can prevent this long list?
Is U_BOOT_I2C_ADAP_COMPLETE is the only (best) way to register to new i2c framework ?
Yes.
bye, Heiko

Hello Heiko,
On 5 December 2013 18:17, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
Am 05.12.2013 13:21, schrieb Naveen Krishna Ch:
Hello Heiko,
On 5 December 2013 16:56, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Sorry for the late reply ...
Am 25.11.2013 12:28, schrieb Naveen Krishna Ch:
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 222 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/README b/README index c97ff0a..c04e352 100644 --- a/README +++ b/README @@ -2076,6 +2076,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
- drivers/i2c/s3c24x0_i2c.c:
- activate this driver with CONFIG_SYS_I2C_S3C24X0
- This driver adds i2c buses (11 for Exynos5250,
Exynos5420
9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from
Samsung)
with a fix speed from 100000 and the slave addr 0!
additional defines: CONFIG_SYS_NUM_I2C_BUSES
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..6e719ec 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,15 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, 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);
if (i2c_set_bus_speed(speed))
printf("i2c_init: failed to init bus %d for speed =
%d\n",
adap->hwadapnr, speed);
+}
This init is not used for Exynos4 and lower series SoCs
- /*
- cmd_type is 0 for write, 1 for read.
@@ -1071,51 +1080,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /* * Register s3c24x0 i2c adapters */ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
0)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_1, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
1)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_2, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
2)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_3, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
3)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_4, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
4)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_5, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
5)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_6, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
6)
-U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_7, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE,
7)
+#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8)
+U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 9)
+U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 10)
+#elif defined(CONFIG_EXYNOS4) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
+U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 1)
+U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 2)
+U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 3)
+U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 4)
+U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 5)
+U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 6)
+U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 7)
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8
Is missing the closing braces. My local changes has it so i couldnt see the problem.
^
leads in a compile error for trats and trats2, could you please fix?
I ran "MAKEALL -v samsung" s3c24x0_i2c.c:724:13: warning: 'exynos_i2c_init' defined but not used [-Wunused-function] is the warning seen for trats and trats2 boards If you are talking about this one, will fix it in the next versio.
No, there is a missing ")" at the end!
pollux:u-boot hs [master] $ ./MAKEALL trats Configuring for trats board... s3c24x0_i2c.c:1247:0: error: unterminated argument list invoking macro "U_BOOT_I2C_ADAP_COMPLETE" s3c24x0_i2c.c:1236:1: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c:1247:0: error: unterminated argument list invoking macro "U_BOOT_I2C_ADAP_COMPLETE" s3c24x0_i2c.c:1236:1: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input
s3c24x0_i2c.c:724:13: warning: 'exynos_i2c_init' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make[1]: *** Warte auf noch nicht beendete Prozesse... make: *** [drivers/i2c/built-in.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
--------------------- SUMMARY ---------------------------- Boards compiled: 1 Boards with errors: 1 ( trats )
#pwclient git-am 292705 #pwclient git-am 293889 #pwclient git-am 292706 #./MAKEALL trats Shows me this errors. Thanks for the catch.
pollux:u-boot hs [master] $
pollux:u-boot hs [(kein Zweig, Neuaufbau begonnen bei master)] $ git bisect log git bisect start # bad: [f5f40408ce3b00637c652fdabfb6f3c4e0d09635] arm: omap: i2c: don't zero cnt in i2c_write git bisect bad f5f40408ce3b00637c652fdabfb6f3c4e0d09635 # good: [f44483b57c49282299da0e5c10073b909cdad979] Merge branch 'serial' of git://git.denx.de/u-boot-microblaze git bisect good f44483b57c49282299da0e5c10073b909cdad979 # bad: [4d06a7c5707f813f4bc7fd7a9d700606c63fa4de] i2c: fti2c010: cosmetic: coding style cleanup git bisect bad 4d06a7c5707f813f4bc7fd7a9d700606c63fa4de # good: [a6756bbdac43474193472b43309626e2c28d8100] driver:i2c:s3c24x0: fix clock init for hsi2c git bisect good a6756bbdac43474193472b43309626e2c28d8100 # bad: [c3b6bba20862ff6476c99aa6d3168f7097a5b4b2] i2c: samsung: register i2c busses for Exynso5420 and Exynos5250 git bisect bad c3b6bba20862ff6476c99aa6d3168f7097a5b4b2 # first bad commit: [c3b6bba20862ff6476c99aa6d3168f7097a5b4b2] i2c: samsung: register i2c busses for Exynso5420 and Exynos5250 pollux:u-boot hs [(kein Zweig, Neuaufbau begonnen bei master)] $
Hmm... could you reformat this very long list in something like this:
U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe, if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c1, s3c24x0_i2c_init, s3c24x0_i2c_probe, [...] U_BOOT_I2C_ADAP_COMPLETE(s3c8, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif if defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c9, s3c24x0_i2c_init, s3c24x0_i2c_probe, U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif
Even if we implement a common init function and reduce this list. The speeds would be fixed and the user need to set the speeds by calling i2c speed or the corresponding function.
Basically, s3c24x0_i2c.c now support both HighSpeed I2C modules and Standard I2C Modules. They have different init functions. Exynos5250/5260 has 4 hsi2c channels hsi2c 0 ~ 3 and 7 i2c channels 4 ~ 10 Exynos5420 has 4 i2c channels i2c 0 ~ 3 and 7 hsi2c channels 4 ~ 10 Exynos4 has 9 i2c channels Hence, the long list. It would be helpful if anyone can suggest a way to reduce this list.
Ah, now I see it, thanks!
Maybe we can define one s3c24x0_i2c_init function, and call from there the SoC / adapater specific init func? So we can prevent this long list?
I can think of something like this +static void samsung_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd) +{ + +#ifdef CONFIG_EXYNOS5 +#ifdef CONFIG_EXYNOS5420 + if(adap->hwadapnr > 3) + s3c24x0_i2c_init(adap, speed, slaveadd); + else + exynos_i2c_init(adap, speed, slaveadd); +#elif defined(CONFIG_EXYNOS5250) || defined(CONFIG_EXYNOS5260) + if(adap->hwadapnr > 3) + exynos_i2c_init(adap, speed, slaveadd); + else + s3c24x0_i2c_init(adap, speed, slaveadd); +#endif +#else + s3c24x0_i2c_init(adap, speed, slaveadd); +#endif +}
But, as mentioned earlier the speeds needs to be set from a seperate function for each board.
Is U_BOOT_I2C_ADAP_COMPLETE is the only (best) way to register to new i2c framework ?
Yes.
Is there any work going on to simplyfy U_BOOT_I2C_ADAP_COMPLETE ?
bye, Heiko
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

Hello Naveen,
Am 06.12.2013 06:47, schrieb Naveen Krishna Ch:
Hello Heiko,
On 5 December 2013 18:17, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 05.12.2013 13:21, schrieb Naveen Krishna Ch:
Hello Heiko,
On 5 December 2013 16:56, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Sorry for the late reply ...
Am 25.11.2013 12:28, schrieb Naveen Krishna Ch:
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 222 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 180 insertions(+), 48 deletions(-)
diff --git a/README b/README index c97ff0a..c04e352 100644 --- a/README +++ b/README @@ -2076,6 +2076,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
- drivers/i2c/s3c24x0_i2c.c:
- activate this driver with CONFIG_SYS_I2C_S3C24X0
- This driver adds i2c buses (11 for Exynos5250,
Exynos5420
9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from
Samsung)
with a fix speed from 100000 and the slave addr 0!
additional defines: CONFIG_SYS_NUM_I2C_BUSES
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..6e719ec 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,15 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, 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);
if (i2c_set_bus_speed(speed))
printf("i2c_init: failed to init bus %d for speed =
%d\n",
adap->hwadapnr, speed);
+}
This init is not used for Exynos4 and lower series SoCs
- /*
- cmd_type is 0 for write, 1 for read.
@@ -1071,51 +1080,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /* * Register s3c24x0 i2c adapters */ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe,
[...]
+U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe,
s3c24x0_i2c_read, s3c24x0_i2c_write,
s3c24x0_i2c_set_bus_speed,
CONFIG_SYS_I2C_S3C24X0_SPEED,
CONFIG_SYS_I2C_S3C24X0_SLAVE, 8
Is missing the closing braces. My local changes has it so i couldnt see the problem.
Ups?
leads in a compile error for trats and trats2, could you please fix?
I ran "MAKEALL -v samsung" s3c24x0_i2c.c:724:13: warning: 'exynos_i2c_init' defined but not used [-Wunused-function] is the warning seen for trats and trats2 boards If you are talking about this one, will fix it in the next versio.
No, there is a missing ")" at the end!
pollux:u-boot hs [master] $ ./MAKEALL trats Configuring for trats board... s3c24x0_i2c.c:1247:0: error: unterminated argument list invoking macro "U_BOOT_I2C_ADAP_COMPLETE" s3c24x0_i2c.c:1236:1: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c:1247:0: error: unterminated argument list invoking macro "U_BOOT_I2C_ADAP_COMPLETE" s3c24x0_i2c.c:1236:1: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input
s3c24x0_i2c.c:724:13: warning: 'exynos_i2c_init' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make[1]: *** Warte auf noch nicht beendete Prozesse... make: *** [drivers/i2c/built-in.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
--------------------- SUMMARY ---------------------------- Boards compiled: 1 Boards with errors: 1 ( trats )
#pwclient git-am 292705 #pwclient git-am 293889 #pwclient git-am 292706 #./MAKEALL trats Shows me this errors. Thanks for the catch.
Puuh...
pollux:u-boot hs [master] $
pollux:u-boot hs [(kein Zweig, Neuaufbau begonnen bei master)] $ git bisect log git bisect start # bad: [f5f40408ce3b00637c652fdabfb6f3c4e0d09635] arm: omap: i2c: don't zero cnt in i2c_write git bisect bad f5f40408ce3b00637c652fdabfb6f3c4e0d09635 # good: [f44483b57c49282299da0e5c10073b909cdad979] Merge branch 'serial' of git://git.denx.de/u-boot-microblaze git bisect good f44483b57c49282299da0e5c10073b909cdad979 # bad: [4d06a7c5707f813f4bc7fd7a9d700606c63fa4de] i2c: fti2c010: cosmetic: coding style cleanup git bisect bad 4d06a7c5707f813f4bc7fd7a9d700606c63fa4de # good: [a6756bbdac43474193472b43309626e2c28d8100] driver:i2c:s3c24x0: fix clock init for hsi2c git bisect good a6756bbdac43474193472b43309626e2c28d8100 # bad: [c3b6bba20862ff6476c99aa6d3168f7097a5b4b2] i2c: samsung: register i2c busses for Exynso5420 and Exynos5250 git bisect bad c3b6bba20862ff6476c99aa6d3168f7097a5b4b2 # first bad commit: [c3b6bba20862ff6476c99aa6d3168f7097a5b4b2] i2c: samsung: register i2c busses for Exynso5420 and Exynos5250 pollux:u-boot hs [(kein Zweig, Neuaufbau begonnen bei master)] $
Hmm... could you reformat this very long list in something like this:
U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe, if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c1, s3c24x0_i2c_init, s3c24x0_i2c_probe, [...] U_BOOT_I2C_ADAP_COMPLETE(s3c8, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif if defined(CONFIG_EXYNOS5420) || defined(CONFIG_EXYNOS5420) U_BOOT_I2C_ADAP_COMPLETE(s3c9, s3c24x0_i2c_init, s3c24x0_i2c_probe, U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe, #endif
Even if we implement a common init function and reduce this list. The speeds would be fixed and the user need to set the speeds by calling i2c speed or the corresponding function.
Ok, I see... so please just sent the compileerrorfree patch, thanks!
Basically, s3c24x0_i2c.c now support both HighSpeed I2C modules and Standard I2C Modules. They have different init functions. Exynos5250/5260 has 4 hsi2c channels hsi2c 0 ~ 3 and 7 i2c channels 4 ~ 10 Exynos5420 has 4 i2c channels i2c 0 ~ 3 and 7 hsi2c channels 4 ~ 10 Exynos4 has 9 i2c channels Hence, the long list. It would be helpful if anyone can suggest a way to reduce this list.
Ah, now I see it, thanks!
Maybe we can define one s3c24x0_i2c_init function, and call from there the SoC / adapater specific init func? So we can prevent this long list?
I can think of something like this +static void samsung_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd) +{
+#ifdef CONFIG_EXYNOS5 +#ifdef CONFIG_EXYNOS5420
if(adap->hwadapnr> 3)
s3c24x0_i2c_init(adap, speed, slaveadd);
else
exynos_i2c_init(adap, speed, slaveadd);
+#elif defined(CONFIG_EXYNOS5250) || defined(CONFIG_EXYNOS5260)
if(adap->hwadapnr> 3)
exynos_i2c_init(adap, speed, slaveadd);
else
s3c24x0_i2c_init(adap, speed, slaveadd);
+#endif +#else
s3c24x0_i2c_init(adap, speed, slaveadd);
+#endif +}
But, as mentioned earlier the speeds needs to be set from a seperate function for each board.
Is U_BOOT_I2C_ADAP_COMPLETE is the only (best) way to register to new i2c framework ?
Yes.
Is there any work going on to simplyfy U_BOOT_I2C_ADAP_COMPLETE ?
No, what do you thinking of? Simplify patches are always welcome!
bye, Heiko

From: Naveen Krishna Ch ch.naveen@samsung.com
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- Changes since v1: 1. Fix compiler error for trats board pointed by Heiko 2. Fix compiler warning for trats and trats2 boards
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 224 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 182 insertions(+), 48 deletions(-)
diff --git a/README b/README index 265e81e..3c233db 100644 --- a/README +++ b/README @@ -2125,6 +2125,12 @@ CBFS (Coreboot Filesystem) support - set CONFIG_SYS_I2C_ZYNQ_SPEED for speed setting - set CONFIG_SYS_I2C_ZYNQ_SLAVE for slave addr
+ - drivers/i2c/s3c24x0_i2c.c: + - activate this driver with CONFIG_SYS_I2C_S3C24X0 + - This driver adds i2c buses (11 for Exynos5250, Exynos5420 + 9 i2c buses for Exynos4 and 1 for S3C24X0 SoCs from Samsung) + with a fix speed from 100000 and the slave addr 0! + additional defines:
CONFIG_SYS_NUM_I2C_BUSES diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 1e9dba0..fd328f0 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -721,6 +721,17 @@ static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap, return 0; }
+#ifdef CONFIG_EXYNOS5 +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); + if (i2c_set_bus_speed(speed)) + printf("i2c_init: failed to init bus %d for speed = %d\n", + adap->hwadapnr, speed); +} +#endif + /* * cmd_type is 0 for write, 1 for read. * @@ -1071,51 +1082,168 @@ int i2c_reset_port_fdt(const void *blob, int node) /* * Register s3c24x0 i2c adapters */ -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_0, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 0) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_1, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 1) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_2, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 2) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_3, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 3) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_4, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 4) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_5, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 5) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_6, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 6) -U_BOOT_I2C_ADAP_COMPLETE(s3c24x0_7, s3c24x0_i2c_init, s3c24x0_i2c_probe, - s3c24x0_i2c_read, s3c24x0_i2c_write, - s3c24x0_i2c_set_bus_speed, - CONFIG_SYS_I2C_S3C24X0_SPEED, - CONFIG_SYS_I2C_S3C24X0_SLAVE, - 7) +#if defined(CONFIG_EXYNOS5420) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 8) +U_BOOT_I2C_ADAP_COMPLETE(i2c09, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 9) +U_BOOT_I2C_ADAP_COMPLETE(i2c10, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 10) +#elif defined(CONFIG_EXYNOS5250) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, exynos_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 8) +U_BOOT_I2C_ADAP_COMPLETE(i2c09, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 9) +U_BOOT_I2C_ADAP_COMPLETE(s3c10, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 10) +#elif defined(CONFIG_EXYNOS4) +U_BOOT_I2C_ADAP_COMPLETE(i2c00, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +U_BOOT_I2C_ADAP_COMPLETE(i2c01, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 1) +U_BOOT_I2C_ADAP_COMPLETE(i2c02, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 2) +U_BOOT_I2C_ADAP_COMPLETE(i2c03, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 3) +U_BOOT_I2C_ADAP_COMPLETE(i2c04, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 4) +U_BOOT_I2C_ADAP_COMPLETE(i2c05, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 5) +U_BOOT_I2C_ADAP_COMPLETE(i2c06, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 6) +U_BOOT_I2C_ADAP_COMPLETE(i2c07, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 7) +U_BOOT_I2C_ADAP_COMPLETE(i2c08, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 8) +#else +U_BOOT_I2C_ADAP_COMPLETE(s3c0, s3c24x0_i2c_init, s3c24x0_i2c_probe, + s3c24x0_i2c_read, s3c24x0_i2c_write, + s3c24x0_i2c_set_bus_speed, + CONFIG_SYS_I2C_S3C24X0_SPEED, + CONFIG_SYS_I2C_S3C24X0_SLAVE, 0) +#endif

Hello Naveen,
Am 06.12.2013 07:42, schrieb Naveen Krishna Ch:
From: Naveen Krishna Chch.naveen@samsung.com
This patch adds the U_BOOT_I2C_ADAP_COMPLETE defines for channels on Exynos5420 and Exynos5250 and also adds support for init function for hsi2c channels
Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
Changes since v1:
- Fix compiler error for trats board pointed by Heiko
- Fix compiler warning for trats and trats2 boards
README | 6 ++ drivers/i2c/s3c24x0_i2c.c | 224 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 182 insertions(+), 48 deletions(-)
Applied to u-boot-i2c.git, thanks!
bye, Heiko

Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This patchset fixes few bugs in the existing s3c24x0.c code (standard i2c) and add support for High-speed i2c bus controller available on Exynos5 SoCs from Samsung.
Exynos5250 channels [0 ~ 3] can configured for I2C contoller or new HSI2C controller channels [3 ~ 7] are standard I2C controller channels Exynos5420 channels [0 ~ 3] are standard I2C controller channels and channels [4 ~ 10] are High-speed controller channels
Patchset:
exynos: i2c: Fix i2c driver to handle NACKs properly Improvements and fixes from Vadim Bendebury for standard i2c calls
exynos: i2c: Change FDT bus setup code to enumerate ports correctly FDT bus setup code from Simon Glass
PATCH v5: i2c: s3c24xx: add hsi2c controller support High-speed controller register description and defines new i2c read/write, probe and set_bus calls.
This is been reviewed earlier at http://lists.denx.de/pipermail/u-boot/2013-May/153245.html Thanks for review and improvements from Vadim Bendebury.
Question: 4. RFC: samsung: i2c: Enable new CONFIG_SYS_I2C framework I've tried to implement the new I2C multi bus framework in u-boot tree, taking tegra-i2c.c as reference.
a). We have different number of channels on Exynos5250 and Exynos5420 (as explained above). How are we supposed to define the U_BOOT_I2C_ADAP_COMPLETE in such cases. Can i use #ifdef EXYNOS5420 or EXYNOS5250
From my side, Yes.
b). When i define 11 buses as in the case of Exynos5420, the "i2c bus" lists them SMDK5420 # i2c bus Bus 0: s3c0 Bus 1: s3c1 Bus 2: s3c10 Bus 3: s3c2 Bus 4: s3c3 Bus 5: s3c4 Bus 6: s3c5 Bus 7: s3c6 Bus 8: s3c7 Bus 9: s3c8 Bus 10: s3c9 or (If i change the name to hsi2c) SMDK5420 # i2c bus Bus 0: hsi2c10 Bus 1: hsi2c4 Bus 2: hsi2c5 Bus 3: hsi2c6 Bus 4: hsi2c7 Bus 5: hsi2c8 Bus 6: hsi2c9 Bus 7: s3c0 Bus 8: s3c1 Bus 9: s3c2 Bus 10: s3c3
Whats the expected behaviour. If the above result is correct, I need to changei the strings to get them in the correct order.
What, if you use two digits:
Bus 0: hsi2c01 Bus 1: hsi2c02 [...] Bus 7: s3c00 Bus 8: s3c01 [...]
?
Or with one digit:
Bus 0: hsi2c1 Bus 1: hsi2c2 [...] Bus 7: s3c0 Bus 8: s3c1 [...]
c). What's the alternative for the board_i2c_init(), i2c_get_bus_num_fdt(), i2c_reset_port_fdt(). "Functions to get the I2C bus number and reset I2C bus using FDT node"
I think, these functions are still needed.
Hmm.. that needs a general discussion, how to use fdt and i2c I think.
I would prefer a way (not really nowing, if it is possible for all configurations) where, if using fdt, the DT gets parsed and the availiable i2c buses gets created ... After that, "normal" i2c access with i2c_set_bus_num(), i2c_read/write should be possible ... this is currently not possible with the i2c framework, but should not be so hard to do. Except the restriction, that it would not work in SPL case, or before relocation for i2c buses announced through dt
Define CONFIG_SYS_I2C_MAX_HOPS -> CONFIG_SYS_I2C_DIRECT_BUS is not defined so i2c_bus[] is used in drivers/i2c/i2c_core.c. Define the fix i2c buses in the board config file with CONFIG_SYS_I2C_BUSES (if you have no fix buses, let this empty) and add a function in drivers/i2c/i2c_core.c, which adds new i2c buses to i2c_bus[] after the fix buses and call this new function, from where you interpret the fdt ...
int i2c_get_bus_num_fdt(int node) should be integrated to drivers/i2c/i2c_core.c
For what purpose is i2c_reset_port_fdt() ?
bye, Heiko

Helo Heiko,
Thanks for timely reply.
On 30 September 2013 13:35, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This patchset fixes few bugs in the existing s3c24x0.c code (standard i2c) and add support for High-speed i2c bus controller available on Exynos5 SoCs from Samsung.
Exynos5250 channels [0 ~ 3] can configured for I2C contoller or new HSI2C controller channels [3 ~ 7] are standard I2C controller channels Exynos5420 channels [0 ~ 3] are standard I2C controller channels and channels [4 ~ 10] are High-speed controller channels
Patchset:
exynos: i2c: Fix i2c driver to handle NACKs properly Improvements and fixes from Vadim Bendebury for standard i2c calls
exynos: i2c: Change FDT bus setup code to enumerate ports correctly FDT bus setup code from Simon Glass
PATCH v5: i2c: s3c24xx: add hsi2c controller support High-speed controller register description and defines new i2c
read/write, probe and set_bus calls.
This is been reviewed earlier at http://lists.denx.de/pipermail/u-boot/2013-May/153245.html Thanks for review and improvements from Vadim Bendebury.
Question: 4. RFC: samsung: i2c: Enable new CONFIG_SYS_I2C framework I've tried to implement the new I2C multi bus framework in u-boot tree, taking tegra-i2c.c as reference.
a). We have different number of channels on Exynos5250 and Exynos5420 (as explained above). How are we supposed to define the U_BOOT_I2C_ADAP_COMPLETE in such cases. Can i use #ifdef EXYNOS5420 or EXYNOS5250
From my side, Yes.
Ok, Will do accordingly. But, I would prefer a way of integrating it to FDT or passing as platform data (board files) instead of keeping it in the driver.
b). When i define 11 buses as in the case of Exynos5420, the "i2c bus" lists them SMDK5420 # i2c bus Bus 0: s3c0 Bus 1: s3c1 Bus 2: s3c10 Bus 3: s3c2 Bus 4: s3c3 Bus 5: s3c4 Bus 6: s3c5 Bus 7: s3c6 Bus 8: s3c7 Bus 9: s3c8 Bus 10: s3c9 or (If i change the name to hsi2c) SMDK5420 # i2c bus Bus 0: hsi2c10 Bus 1: hsi2c4 Bus 2: hsi2c5 Bus 3: hsi2c6 Bus 4: hsi2c7 Bus 5: hsi2c8 Bus 6: hsi2c9 Bus 7: s3c0 Bus 8: s3c1 Bus 9: s3c2 Bus 10: s3c3
Whats the expected behaviour. If the above result is correct, I need to changei the strings to get them in the correct order.
What, if you use two digits:
Bus 0: hsi2c01 Bus 1: hsi2c02 [...] Bus 7: s3c00 Bus 8: s3c01 [...]
?
Or with one digit:
Bus 0: hsi2c1 Bus 1: hsi2c2 [...]
Bus 7: s3c0 Bus 8: s3c1 [...]
In the Exynos5420 hardware channels are as below
channel: --0----1----2----3------4--------5---------6-------7--------8-------9-------10 controller: i2c, i2c, i2c, i2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c. But the "i2c bus" command is showing the bus number according to the "name" string comparison. Which seems wrong. Isn't it ??
c). What's the alternative for the board_i2c_init(), i2c_get_bus_num_fdt(), i2c_reset_port_fdt(). "Functions to get the I2C bus number and reset I2C bus using FDT node"
I think, these functions are still needed.
Hmm.. that needs a general discussion, how to use fdt and i2c I think.
I would prefer a way (not really nowing, if it is possible for all configurations) where, if using fdt, the DT gets parsed and the availiable i2c buses gets created ... After that, "normal" i2c access with i2c_set_bus_num(), i2c_read/write should be possible ... this is currently not possible with the i2c framework, but should not be so hard to do. Except the restriction, that it would not work in SPL case, or before relocation for i2c buses announced through dt
once i2c_init_board() is done board_i2c_init() is not quite needed using i2c_init_board we can avoid the relocation problem aswell.
by the definition of i2c_get_bus_num() in drivers/i2c/i2c_core.c
unsigned int i2c_get_bus_num(void) { return gd->cur_i2c_bus; }
we don't need a special function i2c_get_bus_num_fdt()
IMHO, i2c_reset_port_fdt() is the only function to be discussed
Define CONFIG_SYS_I2C_MAX_HOPS -> CONFIG_SYS_I2C_DIRECT_BUS is not defined so i2c_bus[] is used in drivers/i2c/i2c_core.c. Define the fix i2c buses in the board config file with CONFIG_SYS_I2C_BUSES (if you have no fix buses, let this empty) and add a function in drivers/i2c/i2c_core.c, which adds new i2c buses to i2c_bus[] after the fix buses and call this new function, from where you interpret the fdt ...
I din't quite understood this. Can you point me to some readme or Doc or discussion Please.
int i2c_get_bus_num_fdt(int node) should be integrated to drivers/i2c/i2c_core.c
For what purpose is i2c_reset_port_fdt() ?
bye, Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Thanks,

Hello Naveen,
Am 30.09.2013 12:03, schrieb Naveen Krishna Ch:
Helo Heiko,
Thanks for timely reply.
On 30 September 2013 13:35, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This patchset fixes few bugs in the existing s3c24x0.c code (standard i2c) and add support for High-speed i2c bus controller available on Exynos5 SoCs from Samsung.
Exynos5250 channels [0 ~ 3] can configured for I2C contoller or new HSI2C controller channels [3 ~ 7] are standard I2C controller channels Exynos5420 channels [0 ~ 3] are standard I2C controller channels and channels [4 ~ 10] are High-speed controller channels
Patchset:
exynos: i2c: Fix i2c driver to handle NACKs properly Improvements and fixes from Vadim Bendebury for standard i2c calls
exynos: i2c: Change FDT bus setup code to enumerate ports correctly FDT bus setup code from Simon Glass
PATCH v5: i2c: s3c24xx: add hsi2c controller support High-speed controller register description and defines new i2c
read/write, probe and set_bus calls.
This is been reviewed earlier at http://lists.denx.de/pipermail/u-boot/2013-May/153245.html Thanks for review and improvements from Vadim Bendebury.
Question: 4. RFC: samsung: i2c: Enable new CONFIG_SYS_I2C framework I've tried to implement the new I2C multi bus framework in u-boot tree, taking tegra-i2c.c as reference.
[...]
b). When i define 11 buses as in the case of Exynos5420, the "i2c bus" lists them SMDK5420 # i2c bus Bus 0: s3c0 Bus 1: s3c1 Bus 2: s3c10 Bus 3: s3c2 Bus 4: s3c3 Bus 5: s3c4 Bus 6: s3c5 Bus 7: s3c6 Bus 8: s3c7 Bus 9: s3c8 Bus 10: s3c9 or (If i change the name to hsi2c) SMDK5420 # i2c bus Bus 0: hsi2c10 Bus 1: hsi2c4 Bus 2: hsi2c5 Bus 3: hsi2c6 Bus 4: hsi2c7 Bus 5: hsi2c8 Bus 6: hsi2c9 Bus 7: s3c0 Bus 8: s3c1 Bus 9: s3c2 Bus 10: s3c3
Whats the expected behaviour. If the above result is correct, I need to changei the strings to get them in the correct order.
What, if you use two digits:
Bus 0: hsi2c01 Bus 1: hsi2c02 [...] Bus 7: s3c00 Bus 8: s3c01 [...]
?
Or with one digit:
Bus 0: hsi2c1 Bus 1: hsi2c2 [...]
Bus 7: s3c0 Bus 8: s3c1 [...]
In the Exynos5420 hardware channels are as below
channel: --0----1----2----3------4--------5---------6-------7--------8-------9-------10 controller: i2c, i2c, i2c, i2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c. But the "i2c bus" command is showing the bus number according to the "name" string comparison. Which seems wrong. Isn't it ??
Hmm.. you are right, seems that the compiler sorts them alphabetical ... So, two ways: - use another name, saying first a two digit for the channel ? - or, use CONFIG_SYS_NUM_I2C_BUSES, CONFIG_SYS_I2C_DIRECT_BUS and CONFIG_SYS_I2C_BUSES as described in the README (grep for CONFIG_SYS_I2C_BUSES in include/configs and you will find some examples ...) and you can define, which adapter is on which i2c_bus number ...
c). What's the alternative for the board_i2c_init(), i2c_get_bus_num_fdt(), i2c_reset_port_fdt(). "Functions to get the I2C bus number and reset I2C bus using FDT node"
I think, these functions are still needed.
Hmm.. that needs a general discussion, how to use fdt and i2c I think.
I would prefer a way (not really nowing, if it is possible for all configurations) where, if using fdt, the DT gets parsed and the availiable i2c buses gets created ... After that, "normal" i2c access with i2c_set_bus_num(), i2c_read/write should be possible ... this is currently not possible with the i2c framework, but should not be so hard to do. Except the restriction, that it would not work in SPL case, or before relocation for i2c buses announced through dt
once i2c_init_board() is done board_i2c_init() is not quite needed using i2c_init_board we can avoid the relocation problem aswell.
by the definition of i2c_get_bus_num() in drivers/i2c/i2c_core.c
unsigned int i2c_get_bus_num(void) { return gd->cur_i2c_bus; }
we don't need a special function i2c_get_bus_num_fdt()
Ah, ok!
IMHO, i2c_reset_port_fdt() is the only function to be discussed
And why is i2c_init() not good? Why must we have here a new function?
Define CONFIG_SYS_I2C_MAX_HOPS -> CONFIG_SYS_I2C_DIRECT_BUS is not defined so i2c_bus[] is used in drivers/i2c/i2c_core.c. Define the fix i2c buses in the board config file with CONFIG_SYS_I2C_BUSES (if you have no fix buses, let this empty) and add a function in drivers/i2c/i2c_core.c, which adds new i2c buses to i2c_bus[] after the fix buses and call this new function, from where you interpret the fdt ...
I din't quite understood this. Can you point me to some readme or Doc or discussion Please.
just the U-Boot README ... The above was just a fast idea, how it is possible to add i2c buses from the info in the fdt ...
Here some theoretical code, how it could look like:
in the board config file add:
#define CONFIG_SYS_I2C_DIRECT_BUS 1 #define CONFIG_SYS_I2C_MAX_HOPS 0 #define CONFIG_SYS_NUM_I2C_BUSES 10 /* maximum possible i2c buses used on the hw */ #define CONFIG_SYS_FIX_I2C_BUSES 1 /* just as an example, here with one fix i2c bus */ #define CONFIG_SYS_I2C_BUSES { {0}, /* adapter 0 is fix on i2c_bus number 0 */ }
in drivers/i2c/i2c_core.c:
static int i2c_fix_bus = CONFIG_SYS_FIX_I2C_BUSES;
/* add one i2c bus without muxes ... ToDo: how to add i2c buses with muxes */ static int i2c_add_one_bus(char *adapter_name) { struct i2c_bus_hose *tmp;
if (i2c_fix_bus >= CONFIG_SYS_NUM_I2C_BUSES) return -ENOMEM;
/* search adapter with name */ adap = i2c_search_adapter_name(name); /* Code this function */ if (adap < 0) return -ENODEV;
tmp = kalloc(sizeof(struct i2c_bus_hose)); tmp->adapter = adap; /* if found add it into i2c_bus */ memcpy(&i2c_bus[i2c_fix_bus], tmp, sizeof(struct i2c_bus_hose)); i2c_fix_bus++; }
And maybe here and there some adaptions for getting this running... Thinking of i2c_set_bus_num(), there must be now a check for i2c_fix_bus I think ...
Adapt the README ...
And then, from the place where you interpret the fdt, call if you have the information for one i2c bus, i2c_add_one_bus() ...
Not sure, if I overlooked here something ...
bye, Heiko

Hello Heiko,
On 1 October 2013 11:35, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
Am 30.09.2013 12:03, schrieb Naveen Krishna Ch:
Helo Heiko,
Thanks for timely reply.
On 30 September 2013 13:35, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This patchset fixes few bugs in the existing s3c24x0.c code (standard i2c) and add support for High-speed i2c bus controller available on Exynos5 SoCs from Samsung.
Exynos5250 channels [0 ~ 3] can configured for I2C contoller or new HSI2C controller channels [3 ~ 7] are standard I2C controller channels Exynos5420 channels [0 ~ 3] are standard I2C controller channels and channels [4 ~ 10] are High-speed controller channels
Patchset:
exynos: i2c: Fix i2c driver to handle NACKs properly Improvements and fixes from Vadim Bendebury for standard i2c calls
exynos: i2c: Change FDT bus setup code to enumerate ports correctly FDT bus setup code from Simon Glass
PATCH v5: i2c: s3c24xx: add hsi2c controller support High-speed controller register description and defines new i2c
read/write, probe and set_bus calls.
This is been reviewed earlier at http://lists.denx.de/pipermail/u-boot/2013-May/153245.html Thanks for review and improvements from Vadim Bendebury.
Question: 4. RFC: samsung: i2c: Enable new CONFIG_SYS_I2C framework I've tried to implement the new I2C multi bus framework in u-boot tree, taking tegra-i2c.c as reference.
[...]
b). When i define 11 buses as in the case of Exynos5420, the "i2c bus" lists them SMDK5420 # i2c bus Bus 0: s3c0 Bus 1: s3c1 Bus 2: s3c10 Bus 3: s3c2 Bus 4: s3c3 Bus 5: s3c4 Bus 6: s3c5 Bus 7: s3c6 Bus 8: s3c7 Bus 9: s3c8 Bus 10: s3c9 or (If i change the name to hsi2c) SMDK5420 # i2c bus Bus 0: hsi2c10 Bus 1: hsi2c4 Bus 2: hsi2c5 Bus 3: hsi2c6 Bus 4: hsi2c7 Bus 5: hsi2c8 Bus 6: hsi2c9 Bus 7: s3c0 Bus 8: s3c1 Bus 9: s3c2 Bus 10: s3c3
Whats the expected behaviour. If the above result is correct, I need to changei the strings to get them in the correct order.
What, if you use two digits:
Bus 0: hsi2c01 Bus 1: hsi2c02 [...] Bus 7: s3c00 Bus 8: s3c01 [...]
?
Or with one digit:
Bus 0: hsi2c1 Bus 1: hsi2c2 [...]
Bus 7: s3c0 Bus 8: s3c1 [...]
In the Exynos5420 hardware channels are as below
channel: --0----1----2----3------4--------5---------6-------7--------8-------9-------10 controller: i2c, i2c, i2c, i2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c. But the "i2c bus" command is showing the bus number according to the "name" string comparison. Which seems wrong. Isn't it ??
Hmm.. you are right, seems that the compiler sorts them alphabetical ... So, two ways:
- use another name, saying first a two digit for the channel ?
- or, use CONFIG_SYS_NUM_I2C_BUSES, CONFIG_SYS_I2C_DIRECT_BUS and CONFIG_SYS_I2C_BUSES as described in the README (grep for CONFIG_SYS_I2C_BUSES in include/configs and you will find some examples ...) and you can define, which adapter is on which i2c_bus number ...
Will try and implement it this way.
c). What's the alternative for the board_i2c_init(), i2c_get_bus_num_fdt(), i2c_reset_port_fdt(). "Functions to get the I2C bus number and reset I2C bus using FDT node"
I think, these functions are still needed.
Hmm.. that needs a general discussion, how to use fdt and i2c I think.
I would prefer a way (not really nowing, if it is possible for all configurations) where, if using fdt, the DT gets parsed and the availiable i2c buses gets created ... After that, "normal" i2c access with i2c_set_bus_num(), i2c_read/write should be possible ... this is currently not possible with the i2c framework, but should not be so hard to do. Except the restriction, that it would not work in SPL case, or before relocation for i2c buses announced through dt
once i2c_init_board() is done board_i2c_init() is not quite needed using i2c_init_board we can avoid the relocation problem aswell.
by the definition of i2c_get_bus_num() in drivers/i2c/i2c_core.c
unsigned int i2c_get_bus_num(void) { return gd->cur_i2c_bus; }
we don't need a special function i2c_get_bus_num_fdt()
Ah, ok!
IMHO, i2c_reset_port_fdt() is the only function to be discussed
And why is i2c_init() not good? Why must we have here a new function?
That's right, even if there is a need for i2c_reset_port_fdt(). it must be a i2c-core function instead of being in a driver.
Define CONFIG_SYS_I2C_MAX_HOPS -> CONFIG_SYS_I2C_DIRECT_BUS is not defined so i2c_bus[] is used in drivers/i2c/i2c_core.c. Define the fix i2c buses in the board config file with CONFIG_SYS_I2C_BUSES (if you have no fix buses, let this empty) and add a function in drivers/i2c/i2c_core.c, which adds new i2c buses to i2c_bus[] after the fix buses and call this new function, from where you interpret the fdt ...
I din't quite understood this. Can you point me to some readme or Doc or discussion Please.
just the U-Boot README ... The above was just a fast idea, how it is possible to add i2c buses from the info in the fdt ...
Here some theoretical code, how it could look like:
in the board config file add:
#define CONFIG_SYS_I2C_DIRECT_BUS 1 #define CONFIG_SYS_I2C_MAX_HOPS 0 #define CONFIG_SYS_NUM_I2C_BUSES 10 /* maximum possible i2c buses used on the hw */ #define CONFIG_SYS_FIX_I2C_BUSES 1 /* just as an example, here with one fix i2c bus */ #define CONFIG_SYS_I2C_BUSES { {0}, /* adapter 0 is fix on i2c_bus number 0 */ }
in drivers/i2c/i2c_core.c:
static int i2c_fix_bus = CONFIG_SYS_FIX_I2C_BUSES;
/* add one i2c bus without muxes ... ToDo: how to add i2c buses with muxes */ static int i2c_add_one_bus(char *adapter_name) { struct i2c_bus_hose *tmp;
if (i2c_fix_bus >= CONFIG_SYS_NUM_I2C_BUSES) return -ENOMEM; /* search adapter with name */ adap = i2c_search_adapter_name(name); /* Code this function */ if (adap < 0) return -ENODEV; tmp = kalloc(sizeof(struct i2c_bus_hose)); tmp->adapter = adap; /* if found add it into i2c_bus */ memcpy(&i2c_bus[i2c_fix_bus], tmp, sizeof(struct i2c_bus_hose)); i2c_fix_bus++;
}
Thanks for this explanation.
And maybe here and there some adaptions for getting this running... Thinking of i2c_set_bus_num(), there must be now a check for i2c_fix_bus I think ...
Adapt the README ...
And then, from the place where you interpret the fdt, call if you have the information for one i2c bus, i2c_add_one_bus() ...
Not sure, if I overlooked here something ...
Will try and do this. Mean while can we get the other 3 patches reviewed. Patch 1: http://patchwork.ozlabs.org/patch/278933/ Patch 2: http://patchwork.ozlabs.org/patch/278931/ Patch 3: http://patchwork.ozlabs.org/patch/278930/ They were tested without the change to the new i2c framework.
bye, Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

Hello Naveen,
Am 01.10.2013 08:19, schrieb Naveen Krishna Ch:
Hello Heiko,
On 1 October 2013 11:35, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 30.09.2013 12:03, schrieb Naveen Krishna Ch:
Helo Heiko,
Thanks for timely reply.
On 30 September 2013 13:35, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 30.09.2013 08:58, schrieb Naveen Krishna Chatradhi:
This patchset fixes few bugs in the existing s3c24x0.c code (standard i2c) and add support for High-speed i2c bus controller available on Exynos5 SoCs from Samsung.
Exynos5250 channels [0 ~ 3] can configured for I2C contoller or new HSI2C controller channels [3 ~ 7] are standard I2C controller channels Exynos5420 channels [0 ~ 3] are standard I2C controller channels and channels [4 ~ 10] are High-speed controller channels
Patchset:
exynos: i2c: Fix i2c driver to handle NACKs properly Improvements and fixes from Vadim Bendebury for standard i2c calls
exynos: i2c: Change FDT bus setup code to enumerate ports correctly FDT bus setup code from Simon Glass
PATCH v5: i2c: s3c24xx: add hsi2c controller support High-speed controller register description and defines new i2c
read/write, probe and set_bus calls.
This is been reviewed earlier at http://lists.denx.de/pipermail/u-boot/2013-May/153245.html Thanks for review and improvements from Vadim Bendebury.
Question: 4. RFC: samsung: i2c: Enable new CONFIG_SYS_I2C framework I've tried to implement the new I2C multi bus framework in u-boot tree, taking tegra-i2c.c as reference.
[...]
channel: --0----1----2----3------4--------5---------6-------7--------8-------9-------10 controller: i2c, i2c, i2c, i2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c, hsi2c. But the "i2c bus" command is showing the bus number according to the "name" string comparison. Which seems wrong. Isn't it ??
Hmm.. you are right, seems that the compiler sorts them alphabetical ... So, two ways:
- use another name, saying first a two digit for the channel ?
- or, use CONFIG_SYS_NUM_I2C_BUSES, CONFIG_SYS_I2C_DIRECT_BUS and CONFIG_SYS_I2C_BUSES as described in the README (grep for CONFIG_SYS_I2C_BUSES in include/configs and you will find some examples ...) and you can define, which adapter is on which i2c_bus number ...
Will try and implement it this way.
Ok.
c). What's the alternative for the board_i2c_init(), i2c_get_bus_num_fdt(), i2c_reset_port_fdt(). "Functions to get the I2C bus number and reset I2C bus using FDT node"
I think, these functions are still needed.
Hmm.. that needs a general discussion, how to use fdt and i2c I think.
I would prefer a way (not really nowing, if it is possible for all configurations) where, if using fdt, the DT gets parsed and the availiable i2c buses gets created ... After that, "normal" i2c access with i2c_set_bus_num(), i2c_read/write should be possible ... this is currently not possible with the i2c framework, but should not be so hard to do. Except the restriction, that it would not work in SPL case, or before relocation for i2c buses announced through dt
once i2c_init_board() is done board_i2c_init() is not quite needed using i2c_init_board we can avoid the relocation problem aswell.
by the definition of i2c_get_bus_num() in drivers/i2c/i2c_core.c
unsigned int i2c_get_bus_num(void) { return gd->cur_i2c_bus; }
we don't need a special function i2c_get_bus_num_fdt()
Ah, ok!
IMHO, i2c_reset_port_fdt() is the only function to be discussed
And why is i2c_init() not good? Why must we have here a new function?
That's right, even if there is a need for i2c_reset_port_fdt(). it must be a i2c-core function instead of being in a driver.
Define CONFIG_SYS_I2C_MAX_HOPS -> CONFIG_SYS_I2C_DIRECT_BUS is not defined so i2c_bus[] is used in drivers/i2c/i2c_core.c. Define the fix i2c buses in the board config file with CONFIG_SYS_I2C_BUSES (if you have no fix buses, let this empty) and add a function in drivers/i2c/i2c_core.c, which adds new i2c buses to i2c_bus[] after the fix buses and call this new function, from where you interpret the fdt ...
I din't quite understood this. Can you point me to some readme or Doc or discussion Please.
just the U-Boot README ... The above was just a fast idea, how it is possible to add i2c buses from the info in the fdt ...
Here some theoretical code, how it could look like:
[...]
Thanks for this explanation.
! It is just theoretical ... you must try it ;-)
And maybe here and there some adaptions for getting this running... Thinking of i2c_set_bus_num(), there must be now a check for i2c_fix_bus I think ...
Adapt the README ...
And then, from the place where you interpret the fdt, call if you have the information for one i2c bus, i2c_add_one_bus() ...
Not sure, if I overlooked here something ...
Will try and do this. Mean while can we get the other 3 patches reviewed. Patch 1: http://patchwork.ozlabs.org/patch/278933/
This patch seems good to me, added to u-boot-i2c.git as it seems it is a bugfix.
Patch 2: http://patchwork.ozlabs.org/patch/278931/ Patch 3: http://patchwork.ozlabs.org/patch/278930/
Think, they are OK, but they go after the next release to mainline, as we are close to the next release ...
They were tested without the change to the new i2c framework.
Thanks for your work!
bye, Heiko

The Exynos5 i2c driver does not handle NACKs properly. This change:
- fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
- eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Reviewed-by: Simon Glass sjg@google.com Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- Changes since v1: 1. Removed the compilation error mentioned by Heiko for VCMA9 board...
drivers/i2c/s3c24x0_i2c.c | 214 +++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 124 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index cd09c78..c65360d 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -43,7 +43,7 @@ #define I2C_START_STOP 0x20 /* START / STOP */ #define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
-#define I2C_TIMEOUT 1 /* 1 second */ +#define I2C_TIMEOUT_MS 1000 /* 1 second */
/* @@ -84,22 +84,26 @@ static void SetI2CSCL(int x) } #endif
+/* + * Wait til the byte transfer is completed. + * + * @param i2c- pointer to the appropriate i2c register bank. + * @return I2C_OK, if transmission was ACKED + * I2C_NACK, if transmission was NACKED + * I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS + */ + static int WaitForXfer(struct s3c24x0_i2c *i2c) { - int i; + ulong start_time = get_timer(0);
- i = I2C_TIMEOUT * 10000; - while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) { - udelay(100); - i--; - } + do { + if (readl(&i2c->iiccon) & I2CCON_IRPND) + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ? + I2C_NACK : I2C_OK; + } while (get_timer(start_time) < I2C_TIMEOUT_MS);
- return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; -} - -static int IsACK(struct s3c24x0_i2c *i2c) -{ - return !(readl(&i2c->iicstat) & I2CSTAT_NACK); + return I2C_NOK_TOUT; }
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -180,21 +184,27 @@ unsigned int i2c_get_bus_num(void)
void i2c_init(int speed, int slaveadd) { + int i; struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #endif - int i; + ulong start_time = get_timer(0);
/* By default i2c channel 0 is the current bus */ g_current_bus = 0; i2c = get_base_i2c();
- /* wait for some time to give previous transfer a chance to finish */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + /* + * In case the previous transfer is still going, wait to give it a + * chance to finish. + */ + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) { + printf("%s: I2C bus busy for %p\n", __func__, + &i2c->iicstat); + return; + } }
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -260,7 +270,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, unsigned char data[], unsigned short data_len) { - int i, result; + int i = 0, result; + ulong start_time = get_timer(0);
if (data == 0 || data_len == 0) { /*Don't support data transfer of no length or to address 0 */ @@ -268,128 +279,78 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, return I2C_NOK; }
- /* Check I2C bus idle */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) + return I2C_NOK_TOUT; }
- if (readl(&i2c->iicstat) & I2CSTAT_BSY) - return I2C_NOK_TOUT; - writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon); - result = I2C_OK;
- switch (cmd_type) { - case I2C_WRITE: - if (addr && addr_len) { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - } else { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } + /* Get the slave chip address going */ + writel(chip, &i2c->iicds); + if ((cmd_type == I2C_WRITE) || (addr && addr_len)) + writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + else + writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + + /* Wait for chip address to transmit. */ + result = WaitForXfer(i2c); + if (result != I2C_OK) + goto bailout; + + /* If register address needs to be transmitted - do it now. */ + if (addr && addr_len) { + while ((i < addr_len) && (result == I2C_OK)) { + writel(addr[i++], &i2c->iicds); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); } + i = 0; + if (result != I2C_OK) + goto bailout; + }
- if (result == I2C_OK) + switch (cmd_type) { + case I2C_WRITE: + while ((i < data_len) && (result == I2C_OK)) { + writel(data[i++], &i2c->iicds); + ReadWriteByte(i2c); result = WaitForXfer(i2c); - - /* send STOP */ - writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + } break;
case I2C_READ: if (addr && addr_len) { + /* + * Register address has been sent, now send slave chip + * address again to start the actual read transaction. + */ writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - result = WaitForXfer(i2c); - if (IsACK(i2c)) { - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i++; - } - - writel(chip, &i2c->iicds); - /* resend START */ - writel(I2C_MODE_MR | I2C_TXRX_ENA | - I2C_START_STOP, &i2c->iicstat); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) - & ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } - - } else { - writel(chip, &i2c->iicds); - /* send START */ + + /* Generate a re-START. */ writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, &i2c->iicstat); + ReadWriteByte(i2c); result = WaitForXfer(i2c);
- if (IsACK(i2c)) { - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) & - ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } + if (result != I2C_OK) + goto bailout; }
- /* send STOP */ - writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + while ((i < data_len) && (result == I2C_OK)) { + /* disable ACK for final READ */ + if (i == data_len - 1) + writel(readl(&i2c->iiccon) + & ~I2CCON_ACKGEN, + &i2c->iiccon); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); + data[i++] = readl(&i2c->iicds); + } + if (result == I2C_NACK) + result = I2C_OK; /* Normal terminated read. */ break;
default: @@ -398,6 +359,11 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, break; }
+bailout: + /* Send STOP. */ + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); + ReadWriteByte(i2c); + return result; }

Hello Naveen,
Am 03.10.2013 13:22, schrieb Naveen Krishna Chatradhi:
The Exynos5 i2c driver does not handle NACKs properly. This change:
fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendeburyvbendeb@chromium.org Reviewed-by: Simon Glasssjg@google.com Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
Changes since v1:
- Removed the compilation error mentioned by Heiko for VCMA9 board...
Hmm.. just tried your patchset and I get for the VCMA9 board:
http://patchwork.ozlabs.org/patch/280286/ http://patchwork.ozlabs.org/patch/280287/ http://patchwork.ozlabs.org/patch/280288/
Configuring for VCMA9 board... s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) s3c24x0_i2c.c:125:31: warning: 'i2c_bus' defined but not used [-Wunused-variable] s3c24x0_i2c.c:295:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make: *** [drivers/i2c/libi2c.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
Could you check this complete patchset, thanks!
bye, Heiko

On 14 October 2013 11:59, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
Am 03.10.2013 13:22, schrieb Naveen Krishna Chatradhi:
The Exynos5 i2c driver does not handle NACKs properly. This change:
fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendeburyvbendeb@chromium.org Reviewed-by: Simon Glasssjg@google.com Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
Changes since v1:
- Removed the compilation error mentioned by Heiko for VCMA9 board...
Hmm.. just tried your patchset and I get for the VCMA9 board:
http://patchwork.ozlabs.org/patch/280286/ http://patchwork.ozlabs.org/patch/280287/ http://patchwork.ozlabs.org/patch/280288/
Configuring for VCMA9 board... s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) s3c24x0_i2c.c:125:31: warning: 'i2c_bus' defined but not used [-Wunused-variable] s3c24x0_i2c.c:295:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make: *** [drivers/i2c/libi2c.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
Could you check this complete patchset, thanks!
Just check with "make VCMA9 -j4 > err" I see the errors. Heiko, Whats the best way to check the compilation errors for all boards related to Samsung.
Will resubmit the patchset.
bye, Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

Hello Naveen,
Am 15.10.2013 06:48, schrieb Naveen Krishna Ch:
On 14 October 2013 11:59, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 03.10.2013 13:22, schrieb Naveen Krishna Chatradhi:
The Exynos5 i2c driver does not handle NACKs properly. This change:
fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendeburyvbendeb@chromium.org Reviewed-by: Simon Glasssjg@google.com Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
Changes since v1:
- Removed the compilation error mentioned by Heiko for VCMA9 board...
Hmm.. just tried your patchset and I get for the VCMA9 board:
http://patchwork.ozlabs.org/patch/280286/ http://patchwork.ozlabs.org/patch/280287/ http://patchwork.ozlabs.org/patch/280288/
Configuring for VCMA9 board... s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) s3c24x0_i2c.c:125:31: warning: 'i2c_bus' defined but not used [-Wunused-variable] s3c24x0_i2c.c:295:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make: *** [drivers/i2c/libi2c.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
Could you check this complete patchset, thanks!
Just check with "make VCMA9 -j4> err" I see the errors. Heiko, Whats the best way to check the compilation errors for all boards related to Samsung.
in U-Boot tree:
all s3c24x0 boards: ./MAKEALL -s s3c24x0
(prefered check) all arm boards: ./MAKEALL arm
Will resubmit the patchset.
Thanks!
bye, Heiko

Hi Heiko,
Hello Naveen,
Am 15.10.2013 06:48, schrieb Naveen Krishna Ch:
On 14 October 2013 11:59, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 03.10.2013 13:22, schrieb Naveen Krishna Chatradhi:
The Exynos5 i2c driver does not handle NACKs properly. This change:
- fixes the NACK processing problem (do not continue transaction
if address cycle was NACKed)
- eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendeburyvbendeb@chromium.org Reviewed-by: Simon Glasssjg@google.com Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
Changes since v1:
- Removed the compilation error mentioned by Heiko for VCMA9
board...
Hmm.. just tried your patchset and I get for the VCMA9 board:
http://patchwork.ozlabs.org/patch/280286/ http://patchwork.ozlabs.org/patch/280287/ http://patchwork.ozlabs.org/patch/280288/
Configuring for VCMA9 board... s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) arm-linux-gnueabi-size: './u-boot': No such file s3c24x0_i2c.c:125:39: error: 'CONFIG_MAX_I2C_NUM' undeclared here (not in a function) s3c24x0_i2c.c:125:31: warning: 'i2c_bus' defined but not used [-Wunused-variable] s3c24x0_i2c.c:295:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] make[1]: *** [s3c24x0_i2c.o] Fehler 1 make: *** [drivers/i2c/libi2c.o] Fehler 2 make: *** Warte auf noch nicht beendete Prozesse...
Could you check this complete patchset, thanks!
Just check with "make VCMA9 -j4> err" I see the errors. Heiko, Whats the best way to check the compilation errors for all boards related to Samsung.
in U-Boot tree:
all s3c24x0 boards: ./MAKEALL -s s3c24x0
Also you can try:
./MAKEALL -v samsung
(prefered check) all arm boards: ./MAKEALL arm
Will resubmit the patchset.
Thanks!
bye, Heiko

The Exynos5 i2c driver does not handle NACKs properly. This change:
- fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
- eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Reviewed-by: Simon Glass sjg@google.com Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- Changes since v1: Fixed complilation warning in function i2c_init()
Changes since v2: None
Changes since v3: None; ran # ./MAKEALL -v samsung
drivers/i2c/s3c24x0_i2c.c | 214 +++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 124 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index cd09c78..c65360d 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -43,7 +43,7 @@ #define I2C_START_STOP 0x20 /* START / STOP */ #define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
-#define I2C_TIMEOUT 1 /* 1 second */ +#define I2C_TIMEOUT_MS 1000 /* 1 second */
/* @@ -84,22 +84,26 @@ static void SetI2CSCL(int x) } #endif
+/* + * Wait til the byte transfer is completed. + * + * @param i2c- pointer to the appropriate i2c register bank. + * @return I2C_OK, if transmission was ACKED + * I2C_NACK, if transmission was NACKED + * I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS + */ + static int WaitForXfer(struct s3c24x0_i2c *i2c) { - int i; + ulong start_time = get_timer(0);
- i = I2C_TIMEOUT * 10000; - while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) { - udelay(100); - i--; - } + do { + if (readl(&i2c->iiccon) & I2CCON_IRPND) + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ? + I2C_NACK : I2C_OK; + } while (get_timer(start_time) < I2C_TIMEOUT_MS);
- return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; -} - -static int IsACK(struct s3c24x0_i2c *i2c) -{ - return !(readl(&i2c->iicstat) & I2CSTAT_NACK); + return I2C_NOK_TOUT; }
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -180,21 +184,27 @@ unsigned int i2c_get_bus_num(void)
void i2c_init(int speed, int slaveadd) { + int i; struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #endif - int i; + ulong start_time = get_timer(0);
/* By default i2c channel 0 is the current bus */ g_current_bus = 0; i2c = get_base_i2c();
- /* wait for some time to give previous transfer a chance to finish */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + /* + * In case the previous transfer is still going, wait to give it a + * chance to finish. + */ + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) { + printf("%s: I2C bus busy for %p\n", __func__, + &i2c->iicstat); + return; + } }
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -260,7 +270,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, unsigned char data[], unsigned short data_len) { - int i, result; + int i = 0, result; + ulong start_time = get_timer(0);
if (data == 0 || data_len == 0) { /*Don't support data transfer of no length or to address 0 */ @@ -268,128 +279,78 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, return I2C_NOK; }
- /* Check I2C bus idle */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) + return I2C_NOK_TOUT; }
- if (readl(&i2c->iicstat) & I2CSTAT_BSY) - return I2C_NOK_TOUT; - writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon); - result = I2C_OK;
- switch (cmd_type) { - case I2C_WRITE: - if (addr && addr_len) { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - } else { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } + /* Get the slave chip address going */ + writel(chip, &i2c->iicds); + if ((cmd_type == I2C_WRITE) || (addr && addr_len)) + writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + else + writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + + /* Wait for chip address to transmit. */ + result = WaitForXfer(i2c); + if (result != I2C_OK) + goto bailout; + + /* If register address needs to be transmitted - do it now. */ + if (addr && addr_len) { + while ((i < addr_len) && (result == I2C_OK)) { + writel(addr[i++], &i2c->iicds); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); } + i = 0; + if (result != I2C_OK) + goto bailout; + }
- if (result == I2C_OK) + switch (cmd_type) { + case I2C_WRITE: + while ((i < data_len) && (result == I2C_OK)) { + writel(data[i++], &i2c->iicds); + ReadWriteByte(i2c); result = WaitForXfer(i2c); - - /* send STOP */ - writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + } break;
case I2C_READ: if (addr && addr_len) { + /* + * Register address has been sent, now send slave chip + * address again to start the actual read transaction. + */ writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - result = WaitForXfer(i2c); - if (IsACK(i2c)) { - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i++; - } - - writel(chip, &i2c->iicds); - /* resend START */ - writel(I2C_MODE_MR | I2C_TXRX_ENA | - I2C_START_STOP, &i2c->iicstat); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) - & ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } - - } else { - writel(chip, &i2c->iicds); - /* send START */ + + /* Generate a re-START. */ writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, &i2c->iicstat); + ReadWriteByte(i2c); result = WaitForXfer(i2c);
- if (IsACK(i2c)) { - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) & - ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } + if (result != I2C_OK) + goto bailout; }
- /* send STOP */ - writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + while ((i < data_len) && (result == I2C_OK)) { + /* disable ACK for final READ */ + if (i == data_len - 1) + writel(readl(&i2c->iiccon) + & ~I2CCON_ACKGEN, + &i2c->iiccon); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); + data[i++] = readl(&i2c->iicds); + } + if (result == I2C_NACK) + result = I2C_OK; /* Normal terminated read. */ break;
default: @@ -398,6 +359,11 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, break; }
+bailout: + /* Send STOP. */ + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); + ReadWriteByte(i2c); + return result; }

Hello Naveen,
Am 15.10.2013 12:31, schrieb Naveen Krishna Ch:
The Exynos5 i2c driver does not handle NACKs properly. This change:
fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendeburyvbendeb@chromium.org Reviewed-by: Simon Glasssjg@google.com Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com
Changes since v1: Fixed complilation warning in function i2c_init()
Changes since v2: None
Changes since v3: None; ran # ./MAKEALL -v samsung
drivers/i2c/s3c24x0_i2c.c | 214 +++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 124 deletions(-)
Applied to u-boot-i2c.git
Thanks!
bye, Heiko

The Exynos5 i2c driver does not handle NACKs properly. This change:
- fixes the NACK processing problem (do not continue transaction if address cycle was NACKed)
- eliminates a fair amount of duplicate code
Signed-off-by: Vadim Bendebury vbendeb@chromium.org Reviewed-by: Simon Glass sjg@google.com Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- Changes since v1: Fixed complilation warning in function i2c_init()
Changes since v2: None
drivers/i2c/s3c24x0_i2c.c | 214 +++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 124 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index cd09c78..c65360d 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -43,7 +43,7 @@ #define I2C_START_STOP 0x20 /* START / STOP */ #define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
-#define I2C_TIMEOUT 1 /* 1 second */ +#define I2C_TIMEOUT_MS 1000 /* 1 second */
/* @@ -84,22 +84,26 @@ static void SetI2CSCL(int x) } #endif
+/* + * Wait til the byte transfer is completed. + * + * @param i2c- pointer to the appropriate i2c register bank. + * @return I2C_OK, if transmission was ACKED + * I2C_NACK, if transmission was NACKED + * I2C_NOK_TIMEOUT, if transaction did not complete in I2C_TIMEOUT_MS + */ + static int WaitForXfer(struct s3c24x0_i2c *i2c) { - int i; + ulong start_time = get_timer(0);
- i = I2C_TIMEOUT * 10000; - while (!(readl(&i2c->iiccon) & I2CCON_IRPND) && (i > 0)) { - udelay(100); - i--; - } + do { + if (readl(&i2c->iiccon) & I2CCON_IRPND) + return (readl(&i2c->iicstat) & I2CSTAT_NACK) ? + I2C_NACK : I2C_OK; + } while (get_timer(start_time) < I2C_TIMEOUT_MS);
- return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; -} - -static int IsACK(struct s3c24x0_i2c *i2c) -{ - return !(readl(&i2c->iicstat) & I2CSTAT_NACK); + return I2C_NOK_TOUT; }
static void ReadWriteByte(struct s3c24x0_i2c *i2c) @@ -180,21 +184,27 @@ unsigned int i2c_get_bus_num(void)
void i2c_init(int speed, int slaveadd) { + int i; struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #endif - int i; + ulong start_time = get_timer(0);
/* By default i2c channel 0 is the current bus */ g_current_bus = 0; i2c = get_base_i2c();
- /* wait for some time to give previous transfer a chance to finish */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + /* + * In case the previous transfer is still going, wait to give it a + * chance to finish. + */ + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) { + printf("%s: I2C bus busy for %p\n", __func__, + &i2c->iicstat); + return; + } }
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) @@ -260,7 +270,8 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, unsigned char data[], unsigned short data_len) { - int i, result; + int i = 0, result; + ulong start_time = get_timer(0);
if (data == 0 || data_len == 0) { /*Don't support data transfer of no length or to address 0 */ @@ -268,128 +279,78 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, return I2C_NOK; }
- /* Check I2C bus idle */ - i = I2C_TIMEOUT * 1000; - while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) { - udelay(1000); - i--; + while (readl(&i2c->iicstat) & I2CSTAT_BSY) { + if (get_timer(start_time) > I2C_TIMEOUT_MS) + return I2C_NOK_TOUT; }
- if (readl(&i2c->iicstat) & I2CSTAT_BSY) - return I2C_NOK_TOUT; - writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon); - result = I2C_OK;
- switch (cmd_type) { - case I2C_WRITE: - if (addr && addr_len) { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } - } else { - writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - result = WaitForXfer(i2c); - writel(data[i], &i2c->iicds); - ReadWriteByte(i2c); - i++; - } + /* Get the slave chip address going */ + writel(chip, &i2c->iicds); + if ((cmd_type == I2C_WRITE) || (addr && addr_len)) + writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + else + writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, + &i2c->iicstat); + + /* Wait for chip address to transmit. */ + result = WaitForXfer(i2c); + if (result != I2C_OK) + goto bailout; + + /* If register address needs to be transmitted - do it now. */ + if (addr && addr_len) { + while ((i < addr_len) && (result == I2C_OK)) { + writel(addr[i++], &i2c->iicds); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); } + i = 0; + if (result != I2C_OK) + goto bailout; + }
- if (result == I2C_OK) + switch (cmd_type) { + case I2C_WRITE: + while ((i < data_len) && (result == I2C_OK)) { + writel(data[i++], &i2c->iicds); + ReadWriteByte(i2c); result = WaitForXfer(i2c); - - /* send STOP */ - writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + } break;
case I2C_READ: if (addr && addr_len) { + /* + * Register address has been sent, now send slave chip + * address again to start the actual read transaction. + */ writel(chip, &i2c->iicds); - /* send START */ - writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP, - &i2c->iicstat); - result = WaitForXfer(i2c); - if (IsACK(i2c)) { - i = 0; - while ((i < addr_len) && (result == I2C_OK)) { - writel(addr[i], &i2c->iicds); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i++; - } - - writel(chip, &i2c->iicds); - /* resend START */ - writel(I2C_MODE_MR | I2C_TXRX_ENA | - I2C_START_STOP, &i2c->iicstat); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) - & ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } - - } else { - writel(chip, &i2c->iicds); - /* send START */ + + /* Generate a re-START. */ writel(I2C_MODE_MR | I2C_TXRX_ENA | I2C_START_STOP, &i2c->iicstat); + ReadWriteByte(i2c); result = WaitForXfer(i2c);
- if (IsACK(i2c)) { - i = 0; - while ((i < data_len) && (result == I2C_OK)) { - /* disable ACK for final READ */ - if (i == data_len - 1) - writel(readl(&i2c->iiccon) & - ~I2CCON_ACKGEN, - &i2c->iiccon); - ReadWriteByte(i2c); - result = WaitForXfer(i2c); - data[i] = readl(&i2c->iicds); - i++; - } - } else { - result = I2C_NACK; - } + if (result != I2C_OK) + goto bailout; }
- /* send STOP */ - writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); - ReadWriteByte(i2c); + while ((i < data_len) && (result == I2C_OK)) { + /* disable ACK for final READ */ + if (i == data_len - 1) + writel(readl(&i2c->iiccon) + & ~I2CCON_ACKGEN, + &i2c->iiccon); + ReadWriteByte(i2c); + result = WaitForXfer(i2c); + data[i++] = readl(&i2c->iicds); + } + if (result == I2C_NACK) + result = I2C_OK; /* Normal terminated read. */ break;
default: @@ -398,6 +359,11 @@ static int i2c_transfer(struct s3c24x0_i2c *i2c, break; }
+bailout: + /* Send STOP. */ + writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat); + ReadWriteByte(i2c); + return result; }

From: Simon Glass sjg@chromium.org
At present the i2c ports are enumerated in a strange way - the fdtdec_find_aliases_for_id() function is used, but then the ID returned is ignored and the ports are renumbered. The effect is the same provided that the device tree has the ports in the same order, or uses aliases, and has no gaps, but it is not correct.
Adjust the code to use the function as intended. This will allows device tree aliases to change the device order if required.
As a result, the i2c_busses variable is dropped. We can't be sure that there are no 'holes' in the list of buses, so must check the whole array.
Note: it seems that non-FDT operation is now broken in this drive and will need to be reinstated for upstream.
Signed-off-by: Simon Glass sjg@chromium.org Reviewed-on: https://gerrit.chromium.org/gerrit/59369 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com --- Changes since v1: Nonei
Changes since v2: None drivers/i2c/s3c24x0_i2c.c | 25 ++++++++++++++++++------- drivers/i2c/s3c24x0_i2c.h | 1 + 2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index c65360d..0e6f241 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -52,7 +52,6 @@ */ static unsigned int g_current_bus __attribute__((section(".data"))); #ifdef CONFIG_OF_CONTROL -static int i2c_busses __attribute__((section(".data"))); static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); #endif @@ -164,8 +163,8 @@ int i2c_set_bus_num(unsigned int bus) { struct s3c24x0_i2c *i2c;
- if ((bus < 0) || (bus >= CONFIG_MAX_I2C_NUM)) { - debug("Bad bus: %d\n", bus); + i2c_bus = get_bus(bus); + if (!i2c_bus) return -1; }
@@ -483,19 +482,31 @@ void board_i2c_init(const void *blob) if (node <= 0) continue; bus = &i2c_bus[i]; + bus->active = true; 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++; + bus->bus_num = i; exynos_pinmux_config(bus->id, 0); } }
+/** + * 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) { - if (bus_idx < i2c_busses) - return &i2c_bus[bus_idx]; + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + }
debug("Undefined bus: %d\n", bus_idx); return NULL; @@ -505,7 +516,7 @@ int i2c_get_bus_num_fdt(int node) { int i;
- for (i = 0; i < i2c_busses; i++) { + for (i = 0; i < ARRAY_SIZE(i2c_bus); i++) { if (node == i2c_bus[i].node) return i; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index b4a337a..882af62 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -16,6 +16,7 @@ struct s3c24x0_i2c { };
struct s3c24x0_i2c_bus { + bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs;

Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com --- Changes since v5: Fix compilation errors (undeclared CONFIG_MAX_I2C_NUM) for VCMA9 boards
drivers/i2c/s3c24x0_i2c.c | 623 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 37 +++ 2 files changed, 610 insertions(+), 50 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 0e6f241..71f3637 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -34,6 +34,76 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */ + +/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31) + +/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4) + +/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff) + +/* I2C_INT_EN Register bits */ +#define HSI2C_TX_UNDERRUN_EN (1u << 2) +#define HSI2C_TX_OVERRUN_EN (1u << 3) +#define HSI2C_RX_UNDERRUN_EN (1u << 4) +#define HSI2C_RX_OVERRUN_EN (1u << 5) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9) + +#define HSI2C_INT_ERROR_MASK (HSI2C_TX_UNDERRUN_EN |\ + HSI2C_TX_OVERRUN_EN |\ + HSI2C_RX_UNDERRUN_EN |\ + HSI2C_RX_OVERRUN_EN |\ + HSI2C_INT_TRAILING_EN) + +/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29) + +/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31) + +/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31) + +/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_TIMEOUT_AUTO (1u << 4) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_SUCCESS (1u << 0) +#define HSI2C_TRANS_ERROR_MASK (HSI2C_TIMEOUT_AUTO |\ + HSI2C_NO_DEV | HSI2C_NO_DEV_ACK |\ + HSI2C_TRANS_ABORT) +#define HSI2C_TRANS_FINISHED_MASK (HSI2C_TRANS_ERROR_MASK | HSI2C_TRANS_SUCCESS) + + +/* I2C_FIFO_STAT Register bits */ +#define HSI2C_RX_FIFO_EMPTY (1u << 24) +#define HSI2C_RX_FIFO_FULL (1u << 23) +#define HSI2C_TX_FIFO_EMPTY (1u << 8) +#define HSI2C_TX_FIFO_FULL (1u << 7) +#define HSI2C_RX_FIFO_LEVEL(x) (((x) >> 16) & 0x7f) +#define HSI2C_TX_FIFO_LEVEL(x) ((x) & 0x7f) + +#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) + +/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -45,16 +115,41 @@
#define I2C_TIMEOUT_MS 1000 /* 1 second */
+#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */ + + +/* To support VCMA9 boards and other who dont define max_i2c_num */ +#ifndef CONFIG_MAX_I2C_NUM +#define CONFIG_MAX_I2C_NUM 1 +#endif
/* * 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"))); -#ifdef CONFIG_OF_CONTROL static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); -#endif + +/** + * 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) +{ + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + } + + debug("Undefined bus: %d\n", bus_idx); + return NULL; +}
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) @@ -105,6 +200,55 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return I2C_NOK_TOUT; }
+/* + * Wait for transfer completion. + * + * This function reads the interrupt status register waiting for the INT_I2C + * bit to be set, which indicates copletion of a transaction. + * + * @param i2c: pointer to the appropriate register bank + * + * @return: I2C_OK in case of successful completion, I2C_NOK_TIMEOUT in case + * the status bits do not get set in time, or an approrpiate error + * value in case of transfer errors. + */ +static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (i-- > 0) { + u32 int_status = readl(&i2c->usi_int_stat); + + if (int_status & HSI2C_INT_I2C_EN) { + u32 trans_status = readl(&i2c->usi_trans_status); + + /* Deassert pending interrupt. */ + writel(int_status, &i2c->usi_int_stat); + + if (trans_status & HSI2C_NO_DEV_ACK) { + debug("%s: no ACK from device\n", __func__); + return I2C_NACK; + } + if (trans_status & HSI2C_NO_DEV) { + debug("%s: no device\n", __func__); + return I2C_NOK; + } + if (trans_status & HSI2C_TRANS_ABORT) { + debug("%s: arbitration lost\n", __func__); + return I2C_NOK_LA; + } + if (trans_status & HSI2C_TIMEOUT_AUTO) { + debug("%s: device timed out\n", __func__); + return I2C_NOK_TOUT; + } + return I2C_OK; + } + udelay(1); + } + debug("%s: transaction timeout!\n", __func__); + return I2C_NOK_TOUT; +} + static void ReadWriteByte(struct s3c24x0_i2c *i2c) { writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); @@ -154,6 +298,107 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + ulong clkin; + unsigned int op_clk = i2c_bus->clock_frequency; + unsigned int i = 0, utemp0 = 0, utemp1 = 0; + unsigned int t_ftl_cycle; + +#if defined CONFIG_EXYNOS5 + clkin = get_i2c_clk(); +#endif + /* FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE + * uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * uTemp1 = (TSCLK_L + TSCLK_H + 2) + * uTemp2 = TSCLK_L + TSCLK_H + */ + t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7; + utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; + + /* CLK_DIV max is 256 */ + for (i = 0; i < 256; i++) { + utemp1 = utemp0 / (i + 1); + if ((utemp1 < 512) && (utemp1 > 4)) { + i2c_bus->clk_cycle = utemp1 - 2; + i2c_bus->clk_div = i; + return 0; + } + } + return -1; +} + +static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + unsigned int t_sr_release; + unsigned int n_clkdiv; + unsigned int t_start_su, t_start_hd; + unsigned int t_stop_su; + unsigned int t_data_su, t_data_hd; + unsigned int t_scl_l, t_scl_h; + u32 i2c_timing_s1; + u32 i2c_timing_s2; + u32 i2c_timing_s3; + u32 i2c_timing_sla; + + n_clkdiv = i2c_bus->clk_div; + t_scl_l = i2c_bus->clk_cycle / 2; + t_scl_h = i2c_bus->clk_cycle / 2; + t_start_su = t_scl_l; + t_start_hd = t_scl_l; + t_stop_su = t_scl_l; + t_data_su = t_scl_l / 2; + t_data_hd = t_scl_l / 2; + t_sr_release = i2c_bus->clk_cycle; + + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; + i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0; + i2c_timing_sla = t_data_hd << 0; + + writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl); + + /* Clear to enable Timeout */ + clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0); + + /* set AUTO mode */ + writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf); + + /* Enable completion conditions' reporting. */ + writel(HSI2C_INT_I2C_EN, &hsregs->usi_int_en); + + /* Enable FIFOs */ + writel(HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN, &hsregs->usi_fifo_ctl); + + /* Currently operating in Fast speed mode. */ + writel(i2c_timing_s1, &hsregs->usi_timing_fs1); + writel(i2c_timing_s2, &hsregs->usi_timing_fs2); + writel(i2c_timing_s3, &hsregs->usi_timing_fs3); + writel(i2c_timing_sla, &hsregs->usi_timing_sla); +} + +/* SW reset for the high speed bus */ +static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *i2c = i2c_bus->hsregs; + u32 i2c_ctl; + + /* Set and clear the bit for reset */ + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl |= HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl &= ~HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + /* Initialize the configure registers */ + hsi2c_ch_init(i2c_bus); +} + /* * MULTI BUS I2C support */ @@ -161,16 +406,21 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus;
i2c_bus = get_bus(bus); if (!i2c_bus) return -1; - } - g_current_bus = bus; - i2c = get_base_i2c(); - i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + 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; } @@ -255,6 +505,227 @@ void i2c_init(int speed, int slaveadd) }
/* + * Poll the appropriate bit of the fifo status register until the interface is + * ready to process the next byte or timeout expires. + * + * In addition to the FIFO status register this function also polls the + * interrupt status register to be able to detect unexpected transaction + * completion. + * + * When FIFO is ready to process the next byte, this function returns I2C_OK. + * If in course of polling the INT_I2C assertion is detected, the function + * returns I2C_NOK. If timeout happens before any of the above conditions is + * met - the function returns I2C_NOK_TOUT; + + * @param i2c: pointer to the appropriate i2c register bank. + * @param rx_transfer: set to True if the receive transaction is in progress. + * @return: as described above. + */ +static unsigned hsi2c_poll_fifo(struct exynos5_hsi2c *i2c, bool rx_transfer) +{ + u32 fifo_bit = rx_transfer ? HSI2C_RX_FIFO_EMPTY : HSI2C_TX_FIFO_FULL; + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_fifo_stat) & fifo_bit) { + if (readl(&i2c->usi_int_stat) & HSI2C_INT_I2C_EN) { + /* + * There is a chance that assertion of + * HSI2C_INT_I2C_EN and deassertion of + * HSI2C_RX_FIFO_EMPTY happen simultaneously. Let's + * give FIFO status priority and check it one more + * time before reporting interrupt. The interrupt will + * be reported next time this function is called. + */ + if (rx_transfer && + !(readl(&i2c->usi_fifo_stat) & fifo_bit)) + break; + return I2C_NOK; + } + if (!i--) { + debug("%s: FIFO polling timeout!\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +/* + * Preapre hsi2c transaction, either read or write. + * + * Set up transfer as described in section 27.5.1.2 'I2C Channel Auto Mode' of + * the 5420 UM. + * + * @param i2c: pointer to the appropriate i2c register bank. + * @param chip: slave address on the i2c bus (with read/write bit exlcuded) + * @param len: number of bytes expected to be sent or received + * @param rx_transfer: set to true for receive transactions + * @param: issue_stop: set to true if i2c stop condition should be generated + * after this transaction. + * @return: I2C_NOK_TOUT in case the bus remained busy for HSI2C_TIMEOUT_US, + * I2C_OK otherwise. + */ +static int hsi2c_prepare_transaction(struct exynos5_hsi2c *i2c, + u8 chip, + u16 len, + bool rx_transfer, + bool issue_stop) +{ + u32 conf; + + conf = len | HSI2C_MASTER_RUN; + + if (issue_stop) + conf |= HSI2C_STOP_AFTER_TRANS; + + /* Clear to enable Timeout */ + writel(readl(&i2c->usi_timeout) & ~HSI2C_TIMEOUT_EN, &i2c->usi_timeout); + + /* Set slave address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + if (rx_transfer) { + /* i2c master, read transaction */ + writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* read up to len bytes, stop after transaction is finished */ + writel(conf | HSI2C_READ_WRITE, &i2c->usi_auto_conf); + } else { + /* i2c master, write transaction */ + writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* write up to len bytes, stop after transaction is finished */ + writel(conf, &i2c->usi_auto_conf); + } + + /* Reset all pending interrupt status bits we care about, if any */ + writel(HSI2C_INT_I2C_EN, &i2c->usi_int_stat); + + return I2C_OK; +} + +/* + * Wait while i2c bus is settling down (mostly stop gets completed). + */ +static int hsi2c_wait_while_busy(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY) { + if (!i--) { + debug("%s: bus busy\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +static int hsi2c_write(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len, + bool issue_stop) +{ + int i, rv = 0; + + if (!(len + alen)) { + /* Writes of zero length not supported in auto mode. */ + debug("%s: zero length writes not supported\n", __func__); + return I2C_NOK; + } + + rv = hsi2c_prepare_transaction + (i2c, chip, len + alen, false, issue_stop); + if (rv != I2C_OK) + return rv; + + /* Move address, if any, and the data, if any, into the FIFO. */ + for (i = 0; i < alen; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: address write failed\n", __func__); + goto write_error; + } + writel(addr[i], &i2c->usi_txdata); + } + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: data write failed\n", __func__); + goto write_error; + } + writel(data[i], &i2c->usi_txdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + write_error: + if (issue_stop) { + int tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + } + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +static int hsi2c_read(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len) +{ + int i, rv, tmp_ret; + bool drop_data = false; + + if (!len) { + /* Reads of zero length not supported in auto mode. */ + debug("%s: zero length read adjusted\n", __func__); + drop_data = true; + len = 1; + } + + if (alen) { + /* Internal register adress needs to be written first. */ + rv = hsi2c_write(i2c, chip, addr, alen, NULL, 0, false); + if (rv != I2C_OK) + return rv; + } + + rv = hsi2c_prepare_transaction(i2c, chip, len, true, true); + + if (rv != I2C_OK) + return rv; + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, true); + if (rv != I2C_OK) + goto read_err; + if (drop_data) + continue; + data[i] = readl(&i2c->usi_rxdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + read_err: + tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +/* * cmd_type is 0 for write, 1 for read. * * addr_len can take any value from 0-255, it is only limited @@ -368,10 +839,13 @@ bailout:
int i2c_probe(uchar chip) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar buf[1]; + int ret;
- i2c = get_base_i2c(); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; buf[0] = 0;
/* @@ -379,12 +853,21 @@ 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(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; + if (i2c_bus->is_highspeed) { + ret = hsi2c_read(i2c_bus->hsregs, + chip, 0, 0, buf, 1); + } else { + ret = i2c_transfer(i2c_bus->regs, + I2C_READ, chip << 1, 0, 0, buf, 1); + } + + + return ret != I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; int ret;
@@ -416,11 +899,21 @@ 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 = get_base_i2c(); - ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len); - if (ret != 0) { - debug("I2c read: failed %d\n", ret); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len); + else + ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + debug("I2c read failed %d\n", ret); return 1; } return 0; @@ -428,8 +921,9 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; + int ret;
if (alen > 4) { debug("I2C write: addr len %d not supported\n", alen); @@ -458,58 +952,80 @@ 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 = get_base_i2c(); - return (i2c_transfer - (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, - len) != 0); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len, true); + else + ret = i2c_transfer(i2c_bus->regs, I2C_WRITE, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret != 0) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + return 1; + } else { + return 0; + } }
#ifdef CONFIG_OF_CONTROL -void board_i2c_init(const void *blob) +static void process_nodes(const void *blob, int node_list[], int count, + int is_highspeed) { + struct s3c24x0_i2c_bus *bus; int i; - int node_list[CONFIG_MAX_I2C_NUM]; - int count; - - 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->active = true; - bus->regs = (struct s3c24x0_i2c *) - fdtdec_get_addr(blob, node, "reg"); + bus->is_highspeed = is_highspeed; + + if (is_highspeed) + bus->hsregs = (struct exynos5_hsi2c *) + fdtdec_get_addr(blob, node, "reg"); + else + bus->regs = (struct s3c24x0_i2c *) + fdtdec_get_addr(blob, node, "reg"); + bus->id = pinmux_decode_periph_id(blob, node); + bus->clock_frequency = fdtdec_get_int(blob, node, + "clock-frequency", + CONFIG_SYS_I2C_SPEED); bus->node = node; bus->bus_num = i; exynos_pinmux_config(bus->id, 0); + + /* Mark position as used */ + node_list[i] = -1; } }
-/** - * 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) +void board_i2c_init(const void *blob) { - if (bus_idx < ARRAY_SIZE(i2c_bus)) { - struct s3c24x0_i2c_bus *bus; + int node_list[CONFIG_MAX_I2C_NUM]; + int count;
- bus = &i2c_bus[bus_idx]; - if (bus->active) - return bus; - } + /* First get the normal i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_S3C2440_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 0); + + /* Now look for high speed i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 1);
- debug("Undefined bus: %d\n", bus_idx); - return NULL; }
int i2c_get_bus_num_fdt(int node) @@ -527,7 +1043,7 @@ int i2c_get_bus_num_fdt(int node)
int i2c_reset_port_fdt(const void *blob, int node) { - struct s3c24x0_i2c_bus *i2c; + struct s3c24x0_i2c_bus *i2c_bus; int bus;
bus = i2c_get_bus_num_fdt(node); @@ -536,13 +1052,20 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
- i2c = get_bus(bus); - if (!i2c) { + i2c_bus = get_bus(bus); + if (!i2c_bus) { 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); + 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; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index 882af62..1ae73d2 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -15,11 +15,48 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c { + u32 usi_ctl; + u32 usi_fifo_ctl; + u32 usi_trailing_ctl; + u32 usi_clk_ctl; + u32 usi_clk_slot; + u32 spi_ctl; + u32 uart_ctl; + u32 res1; + u32 usi_int_en; + u32 usi_int_stat; + u32 usi_modem_stat; + u32 usi_error_stat; + u32 usi_fifo_stat; + u32 usi_txdata; + u32 usi_rxdata; + u32 res2; + u32 usi_conf; + u32 usi_auto_conf; + u32 usi_timeout; + u32 usi_manual_cmd; + u32 usi_trans_status; + u32 usi_timing_hs1; + u32 usi_timing_hs2; + u32 usi_timing_hs3; + u32 usi_timing_fs1; + u32 usi_timing_fs2; + u32 usi_timing_fs3; + u32 usi_timing_sla; + u32 i2c_addr; +}; + struct s3c24x0_i2c_bus { bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs; + struct exynos5_hsi2c *hsregs; + int is_highspeed; /* High speed type, rather than I2C */ + unsigned clock_frequency; int id; + unsigned clk_cycle; + unsigned clk_div; }; #endif /* _S3C24X0_I2C_H */

Hello Naveen,
Am 15.10.2013 08:07, schrieb Naveen Krishna Chatradhi:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com
Changes since v5: Fix compilation errors (undeclared CONFIG_MAX_I2C_NUM) for VCMA9 boards
:-(
I get based on current u-boot-i2c.git and your 3 patches applied:
[hs@pollux u-boot]$ ./MAKEALL -s s3c24x0 Configuring for mini2440 board... text data bss dec hex filename 131692 2918 23272 157882 268ba ./u-boot Configuring for VCMA9 board... text data bss dec hex filename 505577 14742 319892 840211 cd213 ./u-boot s3c24x0_i2c.c:301:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] Configuring for smdk2410 board... text data bss dec hex filename 478329 13402 319888 811619 c6263 ./u-boot
bye, Heiko

On 15 October 2013 12:10, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
Am 15.10.2013 08:07, schrieb Naveen Krishna Chatradhi:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com
Changes since v5: Fix compilation errors (undeclared CONFIG_MAX_I2C_NUM) for VCMA9 boards
:-(
I get based on current u-boot-i2c.git and your 3 patches applied:
[hs@pollux u-boot]$ ./MAKEALL -s s3c24x0 Configuring for mini2440 board... text data bss dec hex filename 131692 2918 23272 157882 268ba ./u-boot Configuring for VCMA9 board... text data bss dec hex filename 505577 14742 319892 840211 cd213 ./u-boot s3c24x0_i2c.c:301:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] Configuring for smdk2410 board... text data bss dec hex filename 478329 13402 319888 811619 c6263 ./u-boot
This warning is because the CONFIG_I2C_MULTI_BUS was not defined and this check will be removed once this driver moves to the new I2C frame work.
I thought warnings are OK, unless its obviously seriously.
bye, Heiko
Should i be removing that warning as well ? Thanks for your time and assistance.
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

Hello Naveen,
Am 15.10.2013 11:34, schrieb Naveen Krishna Ch:
On 15 October 2013 12:10, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 15.10.2013 08:07, schrieb Naveen Krishna Chatradhi:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com
Changes since v5: Fix compilation errors (undeclared CONFIG_MAX_I2C_NUM) for VCMA9 boards
:-(
I get based on current u-boot-i2c.git and your 3 patches applied:
[hs@pollux u-boot]$ ./MAKEALL -s s3c24x0 Configuring for mini2440 board... text data bss dec hex filename 131692 2918 23272 157882 268ba ./u-boot Configuring for VCMA9 board... text data bss dec hex filename 505577 14742 319892 840211 cd213 ./u-boot s3c24x0_i2c.c:301:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] Configuring for smdk2410 board... text data bss dec hex filename 478329 13402 319888 811619 c6263 ./u-boot
This warning is because the CONFIG_I2C_MULTI_BUS was not defined and this check will be removed once this driver moves to the new I2C frame work.
I thought warnings are OK, unless its obviously seriously.
bye, Heiko
Should i be removing that warning as well ? Thanks for your time and assistance.
Yes, please!
bye, Heiko

On 15 October 2013 15:09, Heiko Schocher hs@denx.de wrote:
Hello Naveen,
Am 15.10.2013 11:34, schrieb Naveen Krishna Ch:
On 15 October 2013 12:10, Heiko Schocherhs@denx.de wrote:
Hello Naveen,
Am 15.10.2013 08:07, schrieb Naveen Krishna Chatradhi:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: R. Chandrasekarrc.sekar@samsung.com
Changes since v5: Fix compilation errors (undeclared CONFIG_MAX_I2C_NUM) for VCMA9 boards
:-(
I get based on current u-boot-i2c.git and your 3 patches applied:
[hs@pollux u-boot]$ ./MAKEALL -s s3c24x0 Configuring for mini2440 board... text data bss dec hex filename 131692 2918 23272 157882 268ba ./u-boot Configuring for VCMA9 board... text data bss dec hex filename 505577 14742 319892 840211 cd213 ./u-boot s3c24x0_i2c.c:301:12: warning: 'hsi2c_get_clk_details' defined but not used [-Wunused-function] Configuring for smdk2410 board... text data bss dec hex filename 478329 13402 319888 811619 c6263 ./u-boot
This warning is because the CONFIG_I2C_MULTI_BUS was not defined and this check will be removed once this driver moves to the new I2C frame work.
I thought warnings are OK, unless its obviously seriously.
bye, Heiko
Should i be removing that warning as well ? Thanks for your time and assistance.
Yes, please!
Okey, I will add the same check around the function definition as well. This check will be removed this driver moves to the new I2C framework.
Thanks, Naveen
bye, Heiko
-- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: R. Chandrasekar rc.sekar@samsung.com --- drivers/i2c/s3c24x0_i2c.c | 617 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 37 +++ 2 files changed, 604 insertions(+), 50 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 0e6f241..b2b0eef 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -34,6 +34,76 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */ + +/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31) + +/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4) + +/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff) + +/* I2C_INT_EN Register bits */ +#define HSI2C_TX_UNDERRUN_EN (1u << 2) +#define HSI2C_TX_OVERRUN_EN (1u << 3) +#define HSI2C_RX_UNDERRUN_EN (1u << 4) +#define HSI2C_RX_OVERRUN_EN (1u << 5) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9) + +#define HSI2C_INT_ERROR_MASK (HSI2C_TX_UNDERRUN_EN |\ + HSI2C_TX_OVERRUN_EN |\ + HSI2C_RX_UNDERRUN_EN |\ + HSI2C_RX_OVERRUN_EN |\ + HSI2C_INT_TRAILING_EN) + +/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29) + +/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31) + +/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31) + +/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_TIMEOUT_AUTO (1u << 4) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_SUCCESS (1u << 0) +#define HSI2C_TRANS_ERROR_MASK (HSI2C_TIMEOUT_AUTO |\ + HSI2C_NO_DEV | HSI2C_NO_DEV_ACK |\ + HSI2C_TRANS_ABORT) +#define HSI2C_TRANS_FINISHED_MASK (HSI2C_TRANS_ERROR_MASK | HSI2C_TRANS_SUCCESS) + + +/* I2C_FIFO_STAT Register bits */ +#define HSI2C_RX_FIFO_EMPTY (1u << 24) +#define HSI2C_RX_FIFO_FULL (1u << 23) +#define HSI2C_TX_FIFO_EMPTY (1u << 8) +#define HSI2C_TX_FIFO_FULL (1u << 7) +#define HSI2C_RX_FIFO_LEVEL(x) (((x) >> 16) & 0x7f) +#define HSI2C_TX_FIFO_LEVEL(x) ((x) & 0x7f) + +#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) + +/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -45,16 +115,35 @@
#define I2C_TIMEOUT_MS 1000 /* 1 second */
+#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */
/* * 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"))); -#ifdef CONFIG_OF_CONTROL static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); -#endif + +/** + * 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) +{ + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + } + + debug("Undefined bus: %d\n", bus_idx); + return NULL; +}
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) @@ -105,6 +194,55 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return I2C_NOK_TOUT; }
+/* + * Wait for transfer completion. + * + * This function reads the interrupt status register waiting for the INT_I2C + * bit to be set, which indicates copletion of a transaction. + * + * @param i2c: pointer to the appropriate register bank + * + * @return: I2C_OK in case of successful completion, I2C_NOK_TIMEOUT in case + * the status bits do not get set in time, or an approrpiate error + * value in case of transfer errors. + */ +static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (i-- > 0) { + u32 int_status = readl(&i2c->usi_int_stat); + + if (int_status & HSI2C_INT_I2C_EN) { + u32 trans_status = readl(&i2c->usi_trans_status); + + /* Deassert pending interrupt. */ + writel(int_status, &i2c->usi_int_stat); + + if (trans_status & HSI2C_NO_DEV_ACK) { + debug("%s: no ACK from device\n", __func__); + return I2C_NACK; + } + if (trans_status & HSI2C_NO_DEV) { + debug("%s: no device\n", __func__); + return I2C_NOK; + } + if (trans_status & HSI2C_TRANS_ABORT) { + debug("%s: arbitration lost\n", __func__); + return I2C_NOK_LA; + } + if (trans_status & HSI2C_TIMEOUT_AUTO) { + debug("%s: device timed out\n", __func__); + return I2C_NOK_TOUT; + } + return I2C_OK; + } + udelay(1); + } + debug("%s: transaction timeout!\n", __func__); + return I2C_NOK_TOUT; +} + static void ReadWriteByte(struct s3c24x0_i2c *i2c) { writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); @@ -154,6 +292,107 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + ulong clkin; + unsigned int op_clk = i2c_bus->clock_frequency; + unsigned int i = 0, utemp0 = 0, utemp1 = 0; + unsigned int t_ftl_cycle; + +#if defined CONFIG_EXYNOS5 + clkin = get_i2c_clk(); +#endif + /* FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE + * uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * uTemp1 = (TSCLK_L + TSCLK_H + 2) + * uTemp2 = TSCLK_L + TSCLK_H + */ + t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7; + utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; + + /* CLK_DIV max is 256 */ + for (i = 0; i < 256; i++) { + utemp1 = utemp0 / (i + 1); + if ((utemp1 < 512) && (utemp1 > 4)) { + i2c_bus->clk_cycle = utemp1 - 2; + i2c_bus->clk_div = i; + return 0; + } + } + return -1; +} + +static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + unsigned int t_sr_release; + unsigned int n_clkdiv; + unsigned int t_start_su, t_start_hd; + unsigned int t_stop_su; + unsigned int t_data_su, t_data_hd; + unsigned int t_scl_l, t_scl_h; + u32 i2c_timing_s1; + u32 i2c_timing_s2; + u32 i2c_timing_s3; + u32 i2c_timing_sla; + + n_clkdiv = i2c_bus->clk_div; + t_scl_l = i2c_bus->clk_cycle / 2; + t_scl_h = i2c_bus->clk_cycle / 2; + t_start_su = t_scl_l; + t_start_hd = t_scl_l; + t_stop_su = t_scl_l; + t_data_su = t_scl_l / 2; + t_data_hd = t_scl_l / 2; + t_sr_release = i2c_bus->clk_cycle; + + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; + i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0; + i2c_timing_sla = t_data_hd << 0; + + writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl); + + /* Clear to enable Timeout */ + clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0); + + /* set AUTO mode */ + writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf); + + /* Enable completion conditions' reporting. */ + writel(HSI2C_INT_I2C_EN, &hsregs->usi_int_en); + + /* Enable FIFOs */ + writel(HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN, &hsregs->usi_fifo_ctl); + + /* Currently operating in Fast speed mode. */ + writel(i2c_timing_s1, &hsregs->usi_timing_fs1); + writel(i2c_timing_s2, &hsregs->usi_timing_fs2); + writel(i2c_timing_s3, &hsregs->usi_timing_fs3); + writel(i2c_timing_sla, &hsregs->usi_timing_sla); +} + +/* SW reset for the high speed bus */ +static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *i2c = i2c_bus->hsregs; + u32 i2c_ctl; + + /* Set and clear the bit for reset */ + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl |= HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl &= ~HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + /* Initialize the configure registers */ + hsi2c_ch_init(i2c_bus); +} + /* * MULTI BUS I2C support */ @@ -161,16 +400,21 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus;
i2c_bus = get_bus(bus); if (!i2c_bus) return -1; - } - g_current_bus = bus; - i2c = get_base_i2c(); - i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + 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; } @@ -255,6 +499,227 @@ void i2c_init(int speed, int slaveadd) }
/* + * Poll the appropriate bit of the fifo status register until the interface is + * ready to process the next byte or timeout expires. + * + * In addition to the FIFO status register this function also polls the + * interrupt status register to be able to detect unexpected transaction + * completion. + * + * When FIFO is ready to process the next byte, this function returns I2C_OK. + * If in course of polling the INT_I2C assertion is detected, the function + * returns I2C_NOK. If timeout happens before any of the above conditions is + * met - the function returns I2C_NOK_TOUT; + + * @param i2c: pointer to the appropriate i2c register bank. + * @param rx_transfer: set to True if the receive transaction is in progress. + * @return: as described above. + */ +static unsigned hsi2c_poll_fifo(struct exynos5_hsi2c *i2c, bool rx_transfer) +{ + u32 fifo_bit = rx_transfer ? HSI2C_RX_FIFO_EMPTY : HSI2C_TX_FIFO_FULL; + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_fifo_stat) & fifo_bit) { + if (readl(&i2c->usi_int_stat) & HSI2C_INT_I2C_EN) { + /* + * There is a chance that assertion of + * HSI2C_INT_I2C_EN and deassertion of + * HSI2C_RX_FIFO_EMPTY happen simultaneously. Let's + * give FIFO status priority and check it one more + * time before reporting interrupt. The interrupt will + * be reported next time this function is called. + */ + if (rx_transfer && + !(readl(&i2c->usi_fifo_stat) & fifo_bit)) + break; + return I2C_NOK; + } + if (!i--) { + debug("%s: FIFO polling timeout!\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +/* + * Preapre hsi2c transaction, either read or write. + * + * Set up transfer as described in section 27.5.1.2 'I2C Channel Auto Mode' of + * the 5420 UM. + * + * @param i2c: pointer to the appropriate i2c register bank. + * @param chip: slave address on the i2c bus (with read/write bit exlcuded) + * @param len: number of bytes expected to be sent or received + * @param rx_transfer: set to true for receive transactions + * @param: issue_stop: set to true if i2c stop condition should be generated + * after this transaction. + * @return: I2C_NOK_TOUT in case the bus remained busy for HSI2C_TIMEOUT_US, + * I2C_OK otherwise. + */ +static int hsi2c_prepare_transaction(struct exynos5_hsi2c *i2c, + u8 chip, + u16 len, + bool rx_transfer, + bool issue_stop) +{ + u32 conf; + + conf = len | HSI2C_MASTER_RUN; + + if (issue_stop) + conf |= HSI2C_STOP_AFTER_TRANS; + + /* Clear to enable Timeout */ + writel(readl(&i2c->usi_timeout) & ~HSI2C_TIMEOUT_EN, &i2c->usi_timeout); + + /* Set slave address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + if (rx_transfer) { + /* i2c master, read transaction */ + writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* read up to len bytes, stop after transaction is finished */ + writel(conf | HSI2C_READ_WRITE, &i2c->usi_auto_conf); + } else { + /* i2c master, write transaction */ + writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* write up to len bytes, stop after transaction is finished */ + writel(conf, &i2c->usi_auto_conf); + } + + /* Reset all pending interrupt status bits we care about, if any */ + writel(HSI2C_INT_I2C_EN, &i2c->usi_int_stat); + + return I2C_OK; +} + +/* + * Wait while i2c bus is settling down (mostly stop gets completed). + */ +static int hsi2c_wait_while_busy(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY) { + if (!i--) { + debug("%s: bus busy\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +static int hsi2c_write(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len, + bool issue_stop) +{ + int i, rv = 0; + + if (!(len + alen)) { + /* Writes of zero length not supported in auto mode. */ + debug("%s: zero length writes not supported\n", __func__); + return I2C_NOK; + } + + rv = hsi2c_prepare_transaction + (i2c, chip, len + alen, false, issue_stop); + if (rv != I2C_OK) + return rv; + + /* Move address, if any, and the data, if any, into the FIFO. */ + for (i = 0; i < alen; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: address write failed\n", __func__); + goto write_error; + } + writel(addr[i], &i2c->usi_txdata); + } + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: data write failed\n", __func__); + goto write_error; + } + writel(data[i], &i2c->usi_txdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + write_error: + if (issue_stop) { + int tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + } + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +static int hsi2c_read(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len) +{ + int i, rv, tmp_ret; + bool drop_data = false; + + if (!len) { + /* Reads of zero length not supported in auto mode. */ + debug("%s: zero length read adjusted\n", __func__); + drop_data = true; + len = 1; + } + + if (alen) { + /* Internal register adress needs to be written first. */ + rv = hsi2c_write(i2c, chip, addr, alen, NULL, 0, false); + if (rv != I2C_OK) + return rv; + } + + rv = hsi2c_prepare_transaction(i2c, chip, len, true, true); + + if (rv != I2C_OK) + return rv; + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, true); + if (rv != I2C_OK) + goto read_err; + if (drop_data) + continue; + data[i] = readl(&i2c->usi_rxdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + read_err: + tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +/* * cmd_type is 0 for write, 1 for read. * * addr_len can take any value from 0-255, it is only limited @@ -368,10 +833,13 @@ bailout:
int i2c_probe(uchar chip) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar buf[1]; + int ret;
- i2c = get_base_i2c(); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; buf[0] = 0;
/* @@ -379,12 +847,21 @@ 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(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; + if (i2c_bus->is_highspeed) { + ret = hsi2c_read(i2c_bus->hsregs, + chip, 0, 0, buf, 1); + } else { + ret = i2c_transfer(i2c_bus->regs, + I2C_READ, chip << 1, 0, 0, buf, 1); + } + + + return ret != I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; int ret;
@@ -416,11 +893,21 @@ 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 = get_base_i2c(); - ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len); - if (ret != 0) { - debug("I2c read: failed %d\n", ret); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len); + else + ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + debug("I2c read failed %d\n", ret); return 1; } return 0; @@ -428,8 +915,9 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; + int ret;
if (alen > 4) { debug("I2C write: addr len %d not supported\n", alen); @@ -458,58 +946,80 @@ 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 = get_base_i2c(); - return (i2c_transfer - (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, - len) != 0); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len, true); + else + ret = i2c_transfer(i2c_bus->regs, I2C_WRITE, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret != 0) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + return 1; + } else { + return 0; + } }
#ifdef CONFIG_OF_CONTROL -void board_i2c_init(const void *blob) +static void process_nodes(const void *blob, int node_list[], int count, + int is_highspeed) { + struct s3c24x0_i2c_bus *bus; int i; - int node_list[CONFIG_MAX_I2C_NUM]; - int count; - - 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->active = true; - bus->regs = (struct s3c24x0_i2c *) - fdtdec_get_addr(blob, node, "reg"); + bus->is_highspeed = is_highspeed; + + if (is_highspeed) + bus->hsregs = (struct exynos5_hsi2c *) + fdtdec_get_addr(blob, node, "reg"); + else + bus->regs = (struct s3c24x0_i2c *) + fdtdec_get_addr(blob, node, "reg"); + bus->id = pinmux_decode_periph_id(blob, node); + bus->clock_frequency = fdtdec_get_int(blob, node, + "clock-frequency", + CONFIG_SYS_I2C_SPEED); bus->node = node; bus->bus_num = i; exynos_pinmux_config(bus->id, 0); + + /* Mark position as used */ + node_list[i] = -1; } }
-/** - * 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) +void board_i2c_init(const void *blob) { - if (bus_idx < ARRAY_SIZE(i2c_bus)) { - struct s3c24x0_i2c_bus *bus; + int node_list[CONFIG_MAX_I2C_NUM]; + int count;
- bus = &i2c_bus[bus_idx]; - if (bus->active) - return bus; - } + /* First get the normal i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_S3C2440_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 0); + + /* Now look for high speed i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 1);
- debug("Undefined bus: %d\n", bus_idx); - return NULL; }
int i2c_get_bus_num_fdt(int node) @@ -527,7 +1037,7 @@ int i2c_get_bus_num_fdt(int node)
int i2c_reset_port_fdt(const void *blob, int node) { - struct s3c24x0_i2c_bus *i2c; + struct s3c24x0_i2c_bus *i2c_bus; int bus;
bus = i2c_get_bus_num_fdt(node); @@ -536,13 +1046,20 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
- i2c = get_bus(bus); - if (!i2c) { + i2c_bus = get_bus(bus); + if (!i2c_bus) { 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); + 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; } diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index 882af62..1ae73d2 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -15,11 +15,48 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c { + u32 usi_ctl; + u32 usi_fifo_ctl; + u32 usi_trailing_ctl; + u32 usi_clk_ctl; + u32 usi_clk_slot; + u32 spi_ctl; + u32 uart_ctl; + u32 res1; + u32 usi_int_en; + u32 usi_int_stat; + u32 usi_modem_stat; + u32 usi_error_stat; + u32 usi_fifo_stat; + u32 usi_txdata; + u32 usi_rxdata; + u32 res2; + u32 usi_conf; + u32 usi_auto_conf; + u32 usi_timeout; + u32 usi_manual_cmd; + u32 usi_trans_status; + u32 usi_timing_hs1; + u32 usi_timing_hs2; + u32 usi_timing_hs3; + u32 usi_timing_fs1; + u32 usi_timing_fs2; + u32 usi_timing_fs3; + u32 usi_timing_sla; + u32 i2c_addr; +}; + struct s3c24x0_i2c_bus { bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs; + struct exynos5_hsi2c *hsregs; + int is_highspeed; /* High speed type, rather than I2C */ + unsigned clock_frequency; int id; + unsigned clk_cycle; + unsigned clk_div; }; #endif /* _S3C24X0_I2C_H */

Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhi ch.naveen@samsung.com Signed-off-by: Vadim Bendebury vbendeb@chromium.org Signed-off-by: R. Chandrasekar rc.sekar@samsung.com --- Changes since v5: Fix compilation errors (undeclared CONFIG_MAX_I2C_NUM) for VCMA9 boards
Changes since v6: Fixed compilation warning unused variable and function
nav@naveen-linux:~/mainline/u-boot$ ./MAKEALL -v samsung Configuring for smdk2410 board... text data bss dec hex filename 477714 13402 319932 811048 c6028 ./u-boot /usr/local/arm/arm-2011.09/bin/arm-none-eabi-ld: warning: /usr/local/arm/arm-2011.09/bin/../lib/gcc/arm-none-eabi/4.6.1/libgcc.a(bpabi.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail /usr/local/arm/arm-2011.09/bin/arm-none-eabi-ld: warning: /usr/local/arm/arm-2011.09/bin/../lib/gcc/arm-none-eabi/4.6.1/libgcc.a(_divdi3.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail /usr/local/arm/arm-2011.09/bin/arm-none-eabi-ld: warning: /usr/local/arm/arm-2011.09/bin/../lib/gcc/arm-none-eabi/4.6.1/libgcc.a(_udivdi3.o) uses variable-size enums yet the output is to use 32-bit enums; use of enum values across objects may fail Configuring for arndale board... text data bss dec hex filename 251693 9078 297652 558423 88557 ./u-boot 4836 932 0 5768 1688 ./spl/u-boot-spl Configuring for origen board... text data bss dec hex filename 155517 6812 205660 367989 59d75 ./u-boot 2240 104 0 2344 928 ./spl/u-boot-spl Configuring for smdk5250 board... text data bss dec hex filename 340647 11594 299144 651385 9f079 ./u-boot 4944 932 0 5876 16f4 ./spl/u-boot-spl Configuring for snow board... text data bss dec hex filename 340647 11594 299144 651385 9f079 ./u-boot 4944 932 0 5876 16f4 ./spl/u-boot-spl Configuring for smdkv310 board... text data bss dec hex filename 184214 6978 217880 409072 63df0 ./u-boot 2256 104 0 2360 938 ./spl/u-boot-spl Configuring for trats board... text data bss dec hex filename 268088 89204 8595500 8952792 889bd8 ./u-boot Configuring for trats2 board... text data bss dec hex filename 229750 89120 206796 525666 80562 ./u-boot Configuring for s5pc210_universal board... text data bss dec hex filename 197983 89012 205840 492835 78523 ./u-boot Configuring for s5p_goni board... text data bss dec hex filename 162574 7580 8960 179114 2bbaa ./u-boot Configuring for smdkc100 board... text data bss dec hex filename 183577 7866 217992 409435 63f5b ./u-boot
--------------------- SUMMARY ---------------------------- Boards compiled: 11 Boards with warnings but no errors: 1 ( smdk2410 ) ----------------------------------------------------------
smdk2410 fails before and after these patches, any idea what could be the reason.
Thanks, Naveen drivers/i2c/s3c24x0_i2c.c | 630 +++++++++++++++++++++++++++++++++++++++++---- drivers/i2c/s3c24x0_i2c.h | 37 +++ 2 files changed, 616 insertions(+), 51 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 0e6f241..f77a9d1 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -34,6 +34,76 @@ #define I2C_NOK_LA 3 /* Lost arbitration */ #define I2C_NOK_TOUT 4 /* time out */
+/* HSI2C specific register description */ + +/* I2C_CTL Register bits */ +#define HSI2C_FUNC_MODE_I2C (1u << 0) +#define HSI2C_MASTER (1u << 3) +#define HSI2C_RXCHON (1u << 6) /* Write/Send */ +#define HSI2C_TXCHON (1u << 7) /* Read/Receive */ +#define HSI2C_SW_RST (1u << 31) + +/* I2C_FIFO_CTL Register bits */ +#define HSI2C_RXFIFO_EN (1u << 0) +#define HSI2C_TXFIFO_EN (1u << 1) +#define HSI2C_TXFIFO_TRIGGER_LEVEL (0x20 << 16) +#define HSI2C_RXFIFO_TRIGGER_LEVEL (0x20 << 4) + +/* I2C_TRAILING_CTL Register bits */ +#define HSI2C_TRAILING_COUNT (0xff) + +/* I2C_INT_EN Register bits */ +#define HSI2C_TX_UNDERRUN_EN (1u << 2) +#define HSI2C_TX_OVERRUN_EN (1u << 3) +#define HSI2C_RX_UNDERRUN_EN (1u << 4) +#define HSI2C_RX_OVERRUN_EN (1u << 5) +#define HSI2C_INT_TRAILING_EN (1u << 6) +#define HSI2C_INT_I2C_EN (1u << 9) + +#define HSI2C_INT_ERROR_MASK (HSI2C_TX_UNDERRUN_EN |\ + HSI2C_TX_OVERRUN_EN |\ + HSI2C_RX_UNDERRUN_EN |\ + HSI2C_RX_OVERRUN_EN |\ + HSI2C_INT_TRAILING_EN) + +/* I2C_CONF Register bits */ +#define HSI2C_AUTO_MODE (1u << 31) +#define HSI2C_10BIT_ADDR_MODE (1u << 30) +#define HSI2C_HS_MODE (1u << 29) + +/* I2C_AUTO_CONF Register bits */ +#define HSI2C_READ_WRITE (1u << 16) +#define HSI2C_STOP_AFTER_TRANS (1u << 17) +#define HSI2C_MASTER_RUN (1u << 31) + +/* I2C_TIMEOUT Register bits */ +#define HSI2C_TIMEOUT_EN (1u << 31) + +/* I2C_TRANS_STATUS register bits */ +#define HSI2C_MASTER_BUSY (1u << 17) +#define HSI2C_SLAVE_BUSY (1u << 16) +#define HSI2C_TIMEOUT_AUTO (1u << 4) +#define HSI2C_NO_DEV (1u << 3) +#define HSI2C_NO_DEV_ACK (1u << 2) +#define HSI2C_TRANS_ABORT (1u << 1) +#define HSI2C_TRANS_SUCCESS (1u << 0) +#define HSI2C_TRANS_ERROR_MASK (HSI2C_TIMEOUT_AUTO |\ + HSI2C_NO_DEV | HSI2C_NO_DEV_ACK |\ + HSI2C_TRANS_ABORT) +#define HSI2C_TRANS_FINISHED_MASK (HSI2C_TRANS_ERROR_MASK | HSI2C_TRANS_SUCCESS) + + +/* I2C_FIFO_STAT Register bits */ +#define HSI2C_RX_FIFO_EMPTY (1u << 24) +#define HSI2C_RX_FIFO_FULL (1u << 23) +#define HSI2C_TX_FIFO_EMPTY (1u << 8) +#define HSI2C_TX_FIFO_FULL (1u << 7) +#define HSI2C_RX_FIFO_LEVEL(x) (((x) >> 16) & 0x7f) +#define HSI2C_TX_FIFO_LEVEL(x) ((x) & 0x7f) + +#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) + +/* S3C I2C Controller bits */ #define I2CSTAT_BSY 0x20 /* Busy bit */ #define I2CSTAT_NACK 0x01 /* Nack bit */ #define I2CCON_ACKGEN 0x80 /* Acknowledge generation */ @@ -45,16 +115,41 @@
#define I2C_TIMEOUT_MS 1000 /* 1 second */
+#define HSI2C_TIMEOUT_US 100000 /* 100 ms, finer granularity */ + + +/* To support VCMA9 boards and other who dont define max_i2c_num */ +#ifndef CONFIG_MAX_I2C_NUM +#define CONFIG_MAX_I2C_NUM 1 +#endif
/* * 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"))); -#ifdef CONFIG_OF_CONTROL static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] __attribute__((section(".data"))); -#endif + +/** + * 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) +{ + if (bus_idx < ARRAY_SIZE(i2c_bus)) { + struct s3c24x0_i2c_bus *bus; + + bus = &i2c_bus[bus_idx]; + if (bus->active) + return bus; + } + + debug("Undefined bus: %d\n", bus_idx); + return NULL; +}
#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) @@ -105,6 +200,55 @@ static int WaitForXfer(struct s3c24x0_i2c *i2c) return I2C_NOK_TOUT; }
+/* + * Wait for transfer completion. + * + * This function reads the interrupt status register waiting for the INT_I2C + * bit to be set, which indicates copletion of a transaction. + * + * @param i2c: pointer to the appropriate register bank + * + * @return: I2C_OK in case of successful completion, I2C_NOK_TIMEOUT in case + * the status bits do not get set in time, or an approrpiate error + * value in case of transfer errors. + */ +static int hsi2c_wait_for_trx(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (i-- > 0) { + u32 int_status = readl(&i2c->usi_int_stat); + + if (int_status & HSI2C_INT_I2C_EN) { + u32 trans_status = readl(&i2c->usi_trans_status); + + /* Deassert pending interrupt. */ + writel(int_status, &i2c->usi_int_stat); + + if (trans_status & HSI2C_NO_DEV_ACK) { + debug("%s: no ACK from device\n", __func__); + return I2C_NACK; + } + if (trans_status & HSI2C_NO_DEV) { + debug("%s: no device\n", __func__); + return I2C_NOK; + } + if (trans_status & HSI2C_TRANS_ABORT) { + debug("%s: arbitration lost\n", __func__); + return I2C_NOK_LA; + } + if (trans_status & HSI2C_TIMEOUT_AUTO) { + debug("%s: device timed out\n", __func__); + return I2C_NOK_TOUT; + } + return I2C_OK; + } + udelay(1); + } + debug("%s: transaction timeout!\n", __func__); + return I2C_NOK_TOUT; +} + static void ReadWriteByte(struct s3c24x0_i2c *i2c) { writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon); @@ -154,6 +298,109 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat); }
+#ifdef CONFIG_I2C_MULTI_BUS +static int hsi2c_get_clk_details(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + ulong clkin; + unsigned int op_clk = i2c_bus->clock_frequency; + unsigned int i = 0, utemp0 = 0, utemp1 = 0; + unsigned int t_ftl_cycle; + +#if defined CONFIG_EXYNOS5 + clkin = get_i2c_clk(); +#endif + /* FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE + * uTemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * uTemp1 = (TSCLK_L + TSCLK_H + 2) + * uTemp2 = TSCLK_L + TSCLK_H + */ + t_ftl_cycle = (readl(&hsregs->usi_conf) >> 16) & 0x7; + utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; + + /* CLK_DIV max is 256 */ + for (i = 0; i < 256; i++) { + utemp1 = utemp0 / (i + 1); + if ((utemp1 < 512) && (utemp1 > 4)) { + i2c_bus->clk_cycle = utemp1 - 2; + i2c_bus->clk_div = i; + return 0; + } + } + return -1; +} +#endif + +static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *hsregs = i2c_bus->hsregs; + unsigned int t_sr_release; + unsigned int n_clkdiv; + unsigned int t_start_su, t_start_hd; + unsigned int t_stop_su; + unsigned int t_data_su, t_data_hd; + unsigned int t_scl_l, t_scl_h; + u32 i2c_timing_s1; + u32 i2c_timing_s2; + u32 i2c_timing_s3; + u32 i2c_timing_sla; + + n_clkdiv = i2c_bus->clk_div; + t_scl_l = i2c_bus->clk_cycle / 2; + t_scl_h = i2c_bus->clk_cycle / 2; + t_start_su = t_scl_l; + t_start_hd = t_scl_l; + t_stop_su = t_scl_l; + t_data_su = t_scl_l / 2; + t_data_hd = t_scl_l / 2; + t_sr_release = i2c_bus->clk_cycle; + + i2c_timing_s1 = t_start_su << 24 | t_start_hd << 16 | t_stop_su << 8; + i2c_timing_s2 = t_data_su << 24 | t_scl_l << 8 | t_scl_h << 0; + i2c_timing_s3 = n_clkdiv << 16 | t_sr_release << 0; + i2c_timing_sla = t_data_hd << 0; + + writel(HSI2C_TRAILING_COUNT, &hsregs->usi_trailing_ctl); + + /* Clear to enable Timeout */ + clrsetbits_le32(&hsregs->usi_timeout, HSI2C_TIMEOUT_EN, 0); + + /* set AUTO mode */ + writel(readl(&hsregs->usi_conf) | HSI2C_AUTO_MODE, &hsregs->usi_conf); + + /* Enable completion conditions' reporting. */ + writel(HSI2C_INT_I2C_EN, &hsregs->usi_int_en); + + /* Enable FIFOs */ + writel(HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN, &hsregs->usi_fifo_ctl); + + /* Currently operating in Fast speed mode. */ + writel(i2c_timing_s1, &hsregs->usi_timing_fs1); + writel(i2c_timing_s2, &hsregs->usi_timing_fs2); + writel(i2c_timing_s3, &hsregs->usi_timing_fs3); + writel(i2c_timing_sla, &hsregs->usi_timing_sla); +} + +/* SW reset for the high speed bus */ +static void exynos5_i2c_reset(struct s3c24x0_i2c_bus *i2c_bus) +{ + struct exynos5_hsi2c *i2c = i2c_bus->hsregs; + u32 i2c_ctl; + + /* Set and clear the bit for reset */ + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl |= HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + i2c_ctl = readl(&i2c->usi_ctl); + i2c_ctl &= ~HSI2C_SW_RST; + writel(i2c_ctl, &i2c->usi_ctl); + + /* Initialize the configure registers */ + hsi2c_ch_init(i2c_bus); +} + /* * MULTI BUS I2C support */ @@ -161,16 +408,21 @@ static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) #ifdef CONFIG_I2C_MULTI_BUS int i2c_set_bus_num(unsigned int bus) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus;
i2c_bus = get_bus(bus); if (!i2c_bus) return -1; - } - g_current_bus = bus; - i2c = get_base_i2c(); - i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + 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; } @@ -183,7 +435,6 @@ unsigned int i2c_get_bus_num(void)
void i2c_init(int speed, int slaveadd) { - int i; struct s3c24x0_i2c *i2c; #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -207,6 +458,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); @@ -255,6 +508,227 @@ void i2c_init(int speed, int slaveadd) }
/* + * Poll the appropriate bit of the fifo status register until the interface is + * ready to process the next byte or timeout expires. + * + * In addition to the FIFO status register this function also polls the + * interrupt status register to be able to detect unexpected transaction + * completion. + * + * When FIFO is ready to process the next byte, this function returns I2C_OK. + * If in course of polling the INT_I2C assertion is detected, the function + * returns I2C_NOK. If timeout happens before any of the above conditions is + * met - the function returns I2C_NOK_TOUT; + + * @param i2c: pointer to the appropriate i2c register bank. + * @param rx_transfer: set to True if the receive transaction is in progress. + * @return: as described above. + */ +static unsigned hsi2c_poll_fifo(struct exynos5_hsi2c *i2c, bool rx_transfer) +{ + u32 fifo_bit = rx_transfer ? HSI2C_RX_FIFO_EMPTY : HSI2C_TX_FIFO_FULL; + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_fifo_stat) & fifo_bit) { + if (readl(&i2c->usi_int_stat) & HSI2C_INT_I2C_EN) { + /* + * There is a chance that assertion of + * HSI2C_INT_I2C_EN and deassertion of + * HSI2C_RX_FIFO_EMPTY happen simultaneously. Let's + * give FIFO status priority and check it one more + * time before reporting interrupt. The interrupt will + * be reported next time this function is called. + */ + if (rx_transfer && + !(readl(&i2c->usi_fifo_stat) & fifo_bit)) + break; + return I2C_NOK; + } + if (!i--) { + debug("%s: FIFO polling timeout!\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +/* + * Preapre hsi2c transaction, either read or write. + * + * Set up transfer as described in section 27.5.1.2 'I2C Channel Auto Mode' of + * the 5420 UM. + * + * @param i2c: pointer to the appropriate i2c register bank. + * @param chip: slave address on the i2c bus (with read/write bit exlcuded) + * @param len: number of bytes expected to be sent or received + * @param rx_transfer: set to true for receive transactions + * @param: issue_stop: set to true if i2c stop condition should be generated + * after this transaction. + * @return: I2C_NOK_TOUT in case the bus remained busy for HSI2C_TIMEOUT_US, + * I2C_OK otherwise. + */ +static int hsi2c_prepare_transaction(struct exynos5_hsi2c *i2c, + u8 chip, + u16 len, + bool rx_transfer, + bool issue_stop) +{ + u32 conf; + + conf = len | HSI2C_MASTER_RUN; + + if (issue_stop) + conf |= HSI2C_STOP_AFTER_TRANS; + + /* Clear to enable Timeout */ + writel(readl(&i2c->usi_timeout) & ~HSI2C_TIMEOUT_EN, &i2c->usi_timeout); + + /* Set slave address */ + writel(HSI2C_SLV_ADDR_MAS(chip), &i2c->i2c_addr); + + if (rx_transfer) { + /* i2c master, read transaction */ + writel((HSI2C_RXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* read up to len bytes, stop after transaction is finished */ + writel(conf | HSI2C_READ_WRITE, &i2c->usi_auto_conf); + } else { + /* i2c master, write transaction */ + writel((HSI2C_TXCHON | HSI2C_FUNC_MODE_I2C | HSI2C_MASTER), + &i2c->usi_ctl); + + /* write up to len bytes, stop after transaction is finished */ + writel(conf, &i2c->usi_auto_conf); + } + + /* Reset all pending interrupt status bits we care about, if any */ + writel(HSI2C_INT_I2C_EN, &i2c->usi_int_stat); + + return I2C_OK; +} + +/* + * Wait while i2c bus is settling down (mostly stop gets completed). + */ +static int hsi2c_wait_while_busy(struct exynos5_hsi2c *i2c) +{ + int i = HSI2C_TIMEOUT_US; + + while (readl(&i2c->usi_trans_status) & HSI2C_MASTER_BUSY) { + if (!i--) { + debug("%s: bus busy\n", __func__); + return I2C_NOK_TOUT; + } + udelay(1); + } + return I2C_OK; +} + +static int hsi2c_write(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len, + bool issue_stop) +{ + int i, rv = 0; + + if (!(len + alen)) { + /* Writes of zero length not supported in auto mode. */ + debug("%s: zero length writes not supported\n", __func__); + return I2C_NOK; + } + + rv = hsi2c_prepare_transaction + (i2c, chip, len + alen, false, issue_stop); + if (rv != I2C_OK) + return rv; + + /* Move address, if any, and the data, if any, into the FIFO. */ + for (i = 0; i < alen; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: address write failed\n", __func__); + goto write_error; + } + writel(addr[i], &i2c->usi_txdata); + } + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, false); + if (rv != I2C_OK) { + debug("%s: data write failed\n", __func__); + goto write_error; + } + writel(data[i], &i2c->usi_txdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + write_error: + if (issue_stop) { + int tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + } + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +static int hsi2c_read(struct exynos5_hsi2c *i2c, + unsigned char chip, + unsigned char addr[], + unsigned char alen, + unsigned char data[], + unsigned short len) +{ + int i, rv, tmp_ret; + bool drop_data = false; + + if (!len) { + /* Reads of zero length not supported in auto mode. */ + debug("%s: zero length read adjusted\n", __func__); + drop_data = true; + len = 1; + } + + if (alen) { + /* Internal register adress needs to be written first. */ + rv = hsi2c_write(i2c, chip, addr, alen, NULL, 0, false); + if (rv != I2C_OK) + return rv; + } + + rv = hsi2c_prepare_transaction(i2c, chip, len, true, true); + + if (rv != I2C_OK) + return rv; + + for (i = 0; i < len; i++) { + rv = hsi2c_poll_fifo(i2c, true); + if (rv != I2C_OK) + goto read_err; + if (drop_data) + continue; + data[i] = readl(&i2c->usi_rxdata); + } + + rv = hsi2c_wait_for_trx(i2c); + + read_err: + tmp_ret = hsi2c_wait_while_busy(i2c); + if (rv == I2C_OK) + rv = tmp_ret; + + writel(HSI2C_FUNC_MODE_I2C, &i2c->usi_ctl); /* done */ + return rv; +} + +/* * cmd_type is 0 for write, 1 for read. * * addr_len can take any value from 0-255, it is only limited @@ -368,10 +842,13 @@ bailout:
int i2c_probe(uchar chip) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar buf[1]; + int ret;
- i2c = get_base_i2c(); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; buf[0] = 0;
/* @@ -379,12 +856,21 @@ 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(i2c, I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK; + if (i2c_bus->is_highspeed) { + ret = hsi2c_read(i2c_bus->hsregs, + chip, 0, 0, buf, 1); + } else { + ret = i2c_transfer(i2c_bus->regs, + I2C_READ, chip << 1, 0, 0, buf, 1); + } + + + return ret != I2C_OK; }
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; int ret;
@@ -416,11 +902,21 @@ 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 = get_base_i2c(); - ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen, - buffer, len); - if (ret != 0) { - debug("I2c read: failed %d\n", ret); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len); + else + ret = i2c_transfer(i2c_bus->regs, I2C_READ, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + debug("I2c read failed %d\n", ret); return 1; } return 0; @@ -428,8 +924,9 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) { - struct s3c24x0_i2c *i2c; + struct s3c24x0_i2c_bus *i2c_bus; uchar xaddr[4]; + int ret;
if (alen > 4) { debug("I2C write: addr len %d not supported\n", alen); @@ -458,58 +955,80 @@ 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 = get_base_i2c(); - return (i2c_transfer - (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, - len) != 0); + i2c_bus = get_bus(g_current_bus); + if (!i2c_bus) + return -1; + + if (i2c_bus->is_highspeed) + ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen], + alen, buffer, len, true); + else + ret = i2c_transfer(i2c_bus->regs, I2C_WRITE, chip << 1, + &xaddr[4 - alen], alen, buffer, len); + + if (ret != 0) { + if (i2c_bus->is_highspeed) + exynos5_i2c_reset(i2c_bus); + return 1; + } else { + return 0; + } }
#ifdef CONFIG_OF_CONTROL -void board_i2c_init(const void *blob) +static void process_nodes(const void *blob, int node_list[], int count, + int is_highspeed) { + struct s3c24x0_i2c_bus *bus; int i; - int node_list[CONFIG_MAX_I2C_NUM]; - int count; - - 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->active = true; - bus->regs = (struct s3c24x0_i2c *) - fdtdec_get_addr(blob, node, "reg"); + bus->is_highspeed = is_highspeed; + + if (is_highspeed) + bus->hsregs = (struct exynos5_hsi2c *) + fdtdec_get_addr(blob, node, "reg"); + else + bus->regs = (struct s3c24x0_i2c *) + fdtdec_get_addr(blob, node, "reg"); + bus->id = pinmux_decode_periph_id(blob, node); + bus->clock_frequency = fdtdec_get_int(blob, node, + "clock-frequency", + CONFIG_SYS_I2C_SPEED); bus->node = node; bus->bus_num = i; exynos_pinmux_config(bus->id, 0); + + /* Mark position as used */ + node_list[i] = -1; } }
-/** - * 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) +void board_i2c_init(const void *blob) { - if (bus_idx < ARRAY_SIZE(i2c_bus)) { - struct s3c24x0_i2c_bus *bus; + int node_list[CONFIG_MAX_I2C_NUM]; + int count;
- bus = &i2c_bus[bus_idx]; - if (bus->active) - return bus; - } + /* First get the normal i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_S3C2440_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 0); + + /* Now look for high speed i2c ports */ + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_EXYNOS5_I2C, node_list, + CONFIG_MAX_I2C_NUM); + process_nodes(blob, node_list, count, 1);
- debug("Undefined bus: %d\n", bus_idx); - return NULL; }
int i2c_get_bus_num_fdt(int node) @@ -525,9 +1044,10 @@ int i2c_get_bus_num_fdt(int node) return -1; }
+#ifdef CONFIG_I2C_MULTI_BUS int i2c_reset_port_fdt(const void *blob, int node) { - struct s3c24x0_i2c_bus *i2c; + struct s3c24x0_i2c_bus *i2c_bus; int bus;
bus = i2c_get_bus_num_fdt(node); @@ -536,16 +1056,24 @@ int i2c_reset_port_fdt(const void *blob, int node) return -1; }
- i2c = get_bus(bus); - if (!i2c) { + i2c_bus = get_bus(bus); + if (!i2c_bus) { 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); + 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; } #endif +#endif
#endif /* CONFIG_HARD_I2C */ diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index 882af62..1ae73d2 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -15,11 +15,48 @@ struct s3c24x0_i2c { u32 iiclc; };
+struct exynos5_hsi2c { + u32 usi_ctl; + u32 usi_fifo_ctl; + u32 usi_trailing_ctl; + u32 usi_clk_ctl; + u32 usi_clk_slot; + u32 spi_ctl; + u32 uart_ctl; + u32 res1; + u32 usi_int_en; + u32 usi_int_stat; + u32 usi_modem_stat; + u32 usi_error_stat; + u32 usi_fifo_stat; + u32 usi_txdata; + u32 usi_rxdata; + u32 res2; + u32 usi_conf; + u32 usi_auto_conf; + u32 usi_timeout; + u32 usi_manual_cmd; + u32 usi_trans_status; + u32 usi_timing_hs1; + u32 usi_timing_hs2; + u32 usi_timing_hs3; + u32 usi_timing_fs1; + u32 usi_timing_fs2; + u32 usi_timing_fs3; + u32 usi_timing_sla; + u32 i2c_addr; +}; + struct s3c24x0_i2c_bus { bool active; /* port is active and available */ int node; /* device tree node */ int bus_num; /* i2c bus number */ struct s3c24x0_i2c *regs; + struct exynos5_hsi2c *hsregs; + int is_highspeed; /* High speed type, rather than I2C */ + unsigned clock_frequency; int id; + unsigned clk_cycle; + unsigned clk_div; }; #endif /* _S3C24X0_I2C_H */

Hello Naveen,
Am 15.10.2013 12:32, schrieb Naveen Krishna Ch:
Add support for hsi2c controller available on exynos5420.
Note: driver currently supports only fast speed mode 100kbps
Change-Id: I02555b1dc8f4ac21c50aa5158179768563c92f43 Signed-off-by: Naveen Krishna Chatradhich.naveen@samsung.com Signed-off-by: Vadim Bendeburyvbendeb@chromium.org Signed-off-by: R. Chandrasekarrc.sekar@samsung.com
Applied to u-boot-i2c.git
Thanks!
bye, Heiko
participants (9)
-
Heiko Schocher
-
Lukasz Majewski
-
Minkyu Kang
-
Naveen Krishna Ch
-
Naveen Krishna Chatradhi
-
Naveen Krishna Chatradhi
-
Piotr Wilczek
-
Simon Glass
-
Tom Rini