diff mbox

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

Message ID 1365212277-21733-1-git-send-email-naveenkrishna.ch@gmail.com
State Accepted
Delegated to: Heiko Schocher
Headers show

Commit Message

naveen krishna chatradhi April 6, 2013, 1:37 a.m. UTC
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(-)

Comments

naveen krishna chatradhi April 13, 2013, 4:42 a.m. UTC | #1
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:
>
> 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 */
> --
> 1.7.9.5
Hello all i got it review by Simon and Vadim.
Any updates on this driver please
>



--
Shine bright,
(: Nav :)
Heiko Schocher April 15, 2013, 5:48 a.m. UTC | #2
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 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(-)
[...]
>> --
>> 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 Schocher<hs@denx.de>
Acked-by: Heiko Schocher <hs@denx.de>

bye,
Heiko
Tom Rini April 15, 2013, 12:48 p.m. UTC | #3
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 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(-)
> [...]
> >>--
> >>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.
naveen krishna chatradhi April 26, 2013, 3:08 a.m. UTC | #4
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 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(-)
>
> [...]
>
>>> --
>>> 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 Schocher<hs@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 :)
Minkyu Kang April 29, 2013, 6:36 a.m. UTC | #5
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 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(-)
>>
>> [...]
>>
>>>> --
>>>> 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 Schocher<hs@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.
Heiko Schocher April 30, 2013, 4:14 a.m. UTC | #6
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 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(-)
>>
>> [...]
>>
>>>> --
>>>> 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 Schocher<hs@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
naveen krishna chatradhi May 1, 2013, 7:04 p.m. UTC | #7
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 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(-)
>>>
>>> [...]
>>>
>>>>> --
>>>>> 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 Schocher<hs@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 :)
Heiko Schocher May 2, 2013, 10:06 a.m. UTC | #8
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 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(-)
>>>>
>>>> [...]
>>>>
>>>>>> --
>>>>>> 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 Schocher<hs@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 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
naveen krishna chatradhi May 2, 2013, 5:52 p.m. UTC | #9
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 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(-)
>>>>>
>>>>> [...]
>>>>>
>>>>>>> --
>>>>>>> 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 Schocher<hs@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 :)
diff mbox

Patch

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 */