[6/8,V4] I2C: Modify the I2C driver for EXYNOS5

Message ID 1340091032-26560-7-git-send-email-rajeshwari.s@samsung.com
State New
Headers show

Commit Message

Rajeshwari Shinde June 19, 2012, 7:30 a.m.
This patch modifies the S3C I2C driver to suppport EXYNOS5.
The cahnges made to driver are as follows:
        - I2C base address is passed as a parameter to many
        functions to avoid multiple #ifdef
        - I2C init for Exynos5 is made as different function.
        - Channel initialisation is moved to a commom funation
        as it is required by both the i2c_init.
        - Separate functions written to get I2C base address,
        peripheral id for pinmux support.
        - Hardcoding for I2CCON_ACKGEN removed.
        - Replaced printf with debug.
        - Checkpatch issues resolved.

Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
Signed-off-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
Acked-by: Simon Glass <sjg@chromium.org>
---
Changes in V2:
        - Removed #define for I2C cahnnels from hearder file except for I2C0.
        - Incorporated review comments from Simon Glass.
Changes in V3:
        - Incorporated review comments from Joonyoung Shim.
        - Reduced the number of #ifdef by modifying get_i2c_base function.
        - Removed duplicate code.
Changes in V4:
	- Resolved build error for s3c2410.
 drivers/i2c/s3c24x0_i2c.c |  239 +++++++++++++++++++++++++++++++--------------
 drivers/i2c/s3c24x0_i2c.h |    3 +
 2 files changed, 168 insertions(+), 74 deletions(-)

Comments

Joonyoung Shim June 19, 2012, 7:50 a.m. | #1
Hi,

I add some comments at the below.

And current SMDK5250 uses Exynos5250 EVT0 base codes,
but i know the kernel supports only Exynos5250 EVT1.

So, let's remove Exynos5250 EVT0 codes and add EVT1 codes at the u-boot also.
Could you follow up it?

Thanks.

2012/6/19 Rajeshwari Shinde <rajeshwari.s@samsung.com>:
> This patch modifies the S3C I2C driver to suppport EXYNOS5.
> The cahnges made to driver are as follows:
>        - I2C base address is passed as a parameter to many
>        functions to avoid multiple #ifdef
>        - I2C init for Exynos5 is made as different function.
>        - Channel initialisation is moved to a commom funation
>        as it is required by both the i2c_init.
>        - Separate functions written to get I2C base address,
>        peripheral id for pinmux support.
>        - Hardcoding for I2CCON_ACKGEN removed.
>        - Replaced printf with debug.
>        - Checkpatch issues resolved.
>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> Signed-off-by: Doug Anderson <dianders@chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
> Acked-by: Simon Glass <sjg@chromium.org>
> ---
> Changes in V2:
>        - Removed #define for I2C cahnnels from hearder file except for I2C0.
>        - Incorporated review comments from Simon Glass.
> Changes in V3:
>        - Incorporated review comments from Joonyoung Shim.
>        - Reduced the number of #ifdef by modifying get_i2c_base function.
>        - Removed duplicate code.
> Changes in V4:
>        - Resolved build error for s3c2410.
>  drivers/i2c/s3c24x0_i2c.c |  239 +++++++++++++++++++++++++++++++--------------
>  drivers/i2c/s3c24x0_i2c.h |    3 +
>  2 files changed, 168 insertions(+), 74 deletions(-)
>
> diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
> index ba6f39b..0b31cd1 100644
> --- a/drivers/i2c/s3c24x0_i2c.c
> +++ b/drivers/i2c/s3c24x0_i2c.c
> @@ -27,10 +27,17 @@
>  */
>
>  #include <common.h>
> +#ifdef CONFIG_EXYNOS5
> +#include <asm/arch/clk.h>
> +#include <asm/arch/cpu.h>
> +#include <asm/arch/gpio.h>
> +#include <asm/arch/pinmux.h>
> +#else
>  #include <asm/arch/s3c24x0_cpu.h>
> -
> +#endif
>  #include <asm/io.h>
>  #include <i2c.h>
> +#include "s3c24x0_i2c.h"
>
>  #ifdef CONFIG_HARD_I2C
>
> @@ -45,6 +52,7 @@
>
>  #define I2CSTAT_BSY    0x20    /* Busy bit */
>  #define I2CSTAT_NACK   0x01    /* Nack bit */
> +#define I2CCON_ACKGEN  0x80    /* Acknowledge generation */
>  #define I2CCON_IRPND   0x10    /* Interrupt pending bit */
>  #define I2C_MODE_MT    0xC0    /* Master Transmit Mode */
>  #define I2C_MODE_MR    0x80    /* Master Receive Mode */
> @@ -53,6 +61,32 @@
>
>  #define I2C_TIMEOUT 1          /* 1 second */
>
> +static unsigned int g_current_bus;     /* Stores Current I2C Bus */
> +
> +#ifdef CONFIG_EXYNOS5
> +/* We should not rely on any particular ordering of these IDs */
> +static enum periph_id periph_for_dev[] = {
> +       PERIPH_ID_I2C0,
> +       PERIPH_ID_I2C1,
> +       PERIPH_ID_I2C2,
> +       PERIPH_ID_I2C3,
> +       PERIPH_ID_I2C4,
> +       PERIPH_ID_I2C5,
> +       PERIPH_ID_I2C6,
> +       PERIPH_ID_I2C7,
> +};
> +
> +static enum periph_id i2c_get_periph_id(unsigned dev_index)
> +{
> +       if (dev_index < ARRAY_SIZE(periph_for_dev))
> +               return periph_for_dev[dev_index];
> +
> +       debug("%s: invalid bus %d", __func__, dev_index);
> +
> +       return PERIPH_ID_NONE;
> +}
> +
> +#else
>  static int GetI2CSDA(void)
>  {
>        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
> @@ -77,16 +111,17 @@ static void SetI2CSCL(int x)
>        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
>
>  #ifdef CONFIG_S3C2410
> -       writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
> +       writel((readl(&gpio->gpedat) & ~0x4000) |
> +                                       (x & 1) << 14, &gpio->gpedat);
>  #endif
>  #ifdef CONFIG_S3C2400
>        writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
>  #endif
>  }
> +#endif
>
> -static int WaitForXfer(void)
> +static int WaitForXfer(struct s3c24x0_i2c *i2c)
>  {
> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
>        int i;
>
>        i = I2C_TIMEOUT * 10000;
> @@ -98,27 +133,93 @@ static int WaitForXfer(void)
>        return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
>  }
>
> -static int IsACK(void)
> +static int IsACK(struct s3c24x0_i2c *i2c)
>  {
> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
> -
>        return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
>  }
>
> -static void ReadWriteByte(void)
> +static void ReadWriteByte(struct s3c24x0_i2c *i2c)
>  {
> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
> -
>        writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
>  }
>
> +static struct s3c24x0_i2c *get_base_i2c(int bus_idx)
> +{
> +#ifdef CONFIG_EXYNOS5
> +       struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)samsung_get_base_i2c();
> +       return &i2c[bus_idx];
> +#else
> +       return s3c24x0_get_base_i2c();
> +#endif
> +}
> +
> +static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
> +{
> +       ulong freq, pres = 16, div;
> +#ifdef CONFIG_EXYNOS5
> +       freq = get_i2c_clk();
> +#else
> +       freq = get_PCLK();
> +#endif
> +       /* calculate prescaler and divisor values */
> +       if ((freq / pres / (16 + 1)) > speed)
> +               /* set prescaler to 512 */
> +               pres = 512;
> +
> +       div = 0;
> +       while ((freq / pres / (div + 1)) > speed)
> +               div++;
> +
> +       /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
> +       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
> +
> +       /* init to SLAVE REVEIVE and set slaveaddr */
> +       writel(0, &i2c->iicstat);
> +       writel(slaveadd, &i2c->iicadd);
> +       /* program Master Transmit (and implicit STOP) */
> +       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
> +}
> +
> +static void i2c_bus_init(struct s3c24x0_i2c *i2c, unsigned int bus)
> +{
> +       int periph_id = i2c_get_periph_id(bus);
> +
> +       exynos_pinmux_config(periph_id, 0);

This will cause compile errors at the s3c24xx.
Also the i2c_bus_init() doesn't be used at the s3c24xx.

> +
> +       i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
> +}
> +
> +#ifdef CONFIG_EXYNOS5
>  void i2c_init(int speed, int slaveadd)
>  {
> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
> +       struct s3c24x0_i2c *i2c;
> +       int i;
> +
> +       /* By default i2c channel 0 is the current bus */
> +       g_current_bus = I2C0;
> +
> +       i2c = get_base_i2c(g_current_bus);
> +
> +       i2c_bus_init(i2c, g_current_bus);
> +
> +       /* 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--;
> +       }
> +}

I think you can make i2c_init() to one function using #ifdef in function.

> +
> +#else
> +void i2c_init(int speed, int slaveadd)
> +{
> +       struct s3c24x0_i2c *i2c = get_base_i2c();

Without parameter?

>        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
> -       ulong freq, pres = 16, div;
>        int i;
>
> +       /* By default i2c channel 0 is the current bus */
> +       g_current_bus = I2C0;
> +
>        /* wait for some time to give previous transfer a chance to finish */
>
>        i = I2C_TIMEOUT * 1000;
> @@ -171,27 +272,9 @@ void i2c_init(int speed, int slaveadd)
>  #endif
>        }
>
> -       /* calculate prescaler and divisor values */
> -       freq = get_PCLK();
> -       if ((freq / pres / (16 + 1)) > speed)
> -               /* set prescaler to 512 */
> -               pres = 512;
> -
> -       div = 0;
> -       while ((freq / pres / (div + 1)) > speed)
> -               div++;
> -
> -       /* set prescaler, divisor according to freq, also set
> -        * ACKGEN, IRQ */
> -       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
> -
> -       /* init to SLAVE REVEIVE and set slaveaddr */
> -       writel(0, &i2c->iicstat);
> -       writel(slaveadd, &i2c->iicadd);
> -       /* program Master Transmit (and implicit STOP) */
> -       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
> -
> +       i2c_ch_init(i2c, speed, slaveadd);
>  }
> +#endif
>
>  /*
>  * cmd_type is 0 for write, 1 for read.
> @@ -200,19 +283,19 @@ void i2c_init(int speed, int slaveadd)
>  * by the char, we could make it larger if needed. If it is
>  * 0 we skip the address write cycle.
>  */
> -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)
> +static int i2c_transfer(struct s3c24x0_i2c *i2c,
> +                       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 = s3c24x0_get_base_i2c();
>        int i, result;
>
>        if (data == 0 || data_len == 0) {
>                /*Don't support data transfer of no length or to address 0 */
> -               printf("i2c_transfer: bad call\n");
> +               debug("i2c_transfer: bad call\n");
>                return I2C_NOK;
>        }
>
> @@ -226,7 +309,7 @@ int i2c_transfer(unsigned char cmd_type,
>        if (readl(&i2c->iicstat) & I2CSTAT_BSY)
>                return I2C_NOK_TOUT;
>
> -       writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
> +       writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
>        result = I2C_OK;
>
>        switch (cmd_type) {
> @@ -238,16 +321,16 @@ int i2c_transfer(unsigned char cmd_type,
>                               &i2c->iicstat);
>                        i = 0;
>                        while ((i < addr_len) && (result == I2C_OK)) {
> -                               result = WaitForXfer();
> +                               result = WaitForXfer(i2c);
>                                writel(addr[i], &i2c->iicds);
> -                               ReadWriteByte();
> +                               ReadWriteByte(i2c);
>                                i++;
>                        }
>                        i = 0;
>                        while ((i < data_len) && (result == I2C_OK)) {
> -                               result = WaitForXfer();
> +                               result = WaitForXfer(i2c);
>                                writel(data[i], &i2c->iicds);
> -                               ReadWriteByte();
> +                               ReadWriteByte(i2c);
>                                i++;
>                        }
>                } else {
> @@ -257,19 +340,19 @@ int i2c_transfer(unsigned char cmd_type,
>                               &i2c->iicstat);
>                        i = 0;
>                        while ((i < data_len) && (result = I2C_OK)) {
> -                               result = WaitForXfer();
> +                               result = WaitForXfer(i2c);
>                                writel(data[i], &i2c->iicds);
> -                               ReadWriteByte();
> +                               ReadWriteByte(i2c);
>                                i++;
>                        }
>                }
>
>                if (result == I2C_OK)
> -                       result = WaitForXfer();
> +                       result = WaitForXfer(i2c);
>
>                /* send STOP */
>                writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
> -               ReadWriteByte();
> +               ReadWriteByte(i2c);
>                break;
>
>        case I2C_READ:
> @@ -279,13 +362,13 @@ int i2c_transfer(unsigned char cmd_type,
>                        /* send START */
>                        writel(readl(&i2c->iicstat) | I2C_START_STOP,
>                               &i2c->iicstat);
> -                       result = WaitForXfer();
> -                       if (IsACK()) {
> +                       result = WaitForXfer(i2c);
> +                       if (IsACK(i2c)) {
>                                i = 0;
>                                while ((i < addr_len) && (result == I2C_OK)) {
>                                        writel(addr[i], &i2c->iicds);
> -                                       ReadWriteByte();
> -                                       result = WaitForXfer();
> +                                       ReadWriteByte(i2c);
> +                                       result = WaitForXfer(i2c);
>                                        i++;
>                                }
>
> @@ -293,16 +376,17 @@ int i2c_transfer(unsigned char cmd_type,
>                                /* resend START */
>                                writel(I2C_MODE_MR | I2C_TXRX_ENA |
>                                       I2C_START_STOP, &i2c->iicstat);
> -                               ReadWriteByte();
> -                               result = WaitForXfer();
> +                       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)
> -                                                      & ~0x80, &i2c->iiccon);
> -                                       ReadWriteByte();
> -                                       result = WaitForXfer();
> +                                                       & ~I2CCON_ACKGEN,
> +                                                       &i2c->iiccon);
> +                               ReadWriteByte(i2c);
> +                               result = WaitForXfer(i2c);
>                                        data[i] = readl(&i2c->iicds);
>                                        i++;
>                                }
> @@ -316,17 +400,18 @@ int i2c_transfer(unsigned char cmd_type,
>                        /* send START */
>                        writel(readl(&i2c->iicstat) | I2C_START_STOP,
>                               &i2c->iicstat);
> -                       result = WaitForXfer();
> +                       result = WaitForXfer(i2c);
>
> -                       if (IsACK()) {
> +                       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) &
> -                                                      ~0x80, &i2c->iiccon);
> -                                       ReadWriteByte();
> -                                       result = WaitForXfer();
> +                                                       ~I2CCON_ACKGEN,
> +                                                       &i2c->iiccon);
> +                                       ReadWriteByte(i2c);
> +                                       result = WaitForXfer(i2c);
>                                        data[i] = readl(&i2c->iicds);
>                                        i++;
>                                }
> @@ -337,22 +422,24 @@ int i2c_transfer(unsigned char cmd_type,
>
>                /* send STOP */
>                writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
> -               ReadWriteByte();
> +               ReadWriteByte(i2c);
>                break;
>
>        default:
> -               printf("i2c_transfer: bad call\n");
> +               debug("i2c_transfer: bad call\n");
>                result = I2C_NOK;
>                break;
>        }
>
> -       return (result);
> +       return result;
>  }
>
>  int i2c_probe(uchar chip)
>  {
> +       struct s3c24x0_i2c *i2c;
>        uchar buf[1];
>
> +       i2c = get_base_i2c(g_current_bus);
>        buf[0] = 0;
>
>        /*
> @@ -360,16 +447,17 @@ 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_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
> +       return i2c_transfer(i2c, 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;
>
>        if (alen > 4) {
> -               printf("I2C read: addr len %d not supported\n", alen);
> +               debug("I2C read: addr len %d not supported\n", alen);
>                return 1;
>        }
>
> @@ -396,10 +484,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
>                chip |= ((addr >> (alen * 8)) &
>                         CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
>  #endif
> -       if ((ret =
> -            i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
> -                         buffer, len)) != 0) {
> -               printf("I2c read: failed %d\n", ret);
> +       i2c = get_base_i2c(g_current_bus);
> +       ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
> +                       buffer, len);
> +       if (ret != 0) {
> +               debug("I2c read: failed %d\n", ret);
>                return 1;
>        }
>        return 0;
> @@ -407,10 +496,11 @@ 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) {
> -               printf("I2C write: addr len %d not supported\n", alen);
> +               debug("I2C write: addr len %d not supported\n", alen);
>                return 1;
>        }
>
> @@ -436,8 +526,9 @@ 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(g_current_bus);
>        return (i2c_transfer
> -               (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
> +               (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
>                 len) != 0);
>  }
>  #endif /* CONFIG_HARD_I2C */
> diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h
> index d357a0a..57aafb1 100644
> --- a/drivers/i2c/s3c24x0_i2c.h
> +++ b/drivers/i2c/s3c24x0_i2c.h
> @@ -23,6 +23,9 @@
>  #ifndef _S3C24X0_I2C_H
>  #define _S3C24X0_I2C_H
>
> +/* I2C channels exynos5 has 8 i2c channel */
> +#define I2C0           0
> +
>  struct s3c24x0_i2c {
>        u32     iiccon;
>        u32     iicstat;
> --
> 1.7.4.4
>
Rajeshwari Birje June 19, 2012, 10:57 a.m. | #2
Hi Joonyoung Shim,

On Tue, Jun 19, 2012 at 1:20 PM, Joonyoung Shim <dofmind@gmail.com> wrote:
> Hi,
>
> I add some comments at the below.
>
-- ok
> And current SMDK5250 uses Exynos5250 EVT0 base codes,
> but i know the kernel supports only Exynos5250 EVT1.
>
> So, let's remove Exynos5250 EVT0 codes and add EVT1 codes at the u-boot also.
> Could you follow up it?
>
-- Yes currently we are working on that
> Thanks.
>
> 2012/6/19 Rajeshwari Shinde <rajeshwari.s@samsung.com>:
>> This patch modifies the S3C I2C driver to suppport EXYNOS5.
>> The cahnges made to driver are as follows:
>>        - I2C base address is passed as a parameter to many
>>        functions to avoid multiple #ifdef
>>        - I2C init for Exynos5 is made as different function.
>>        - Channel initialisation is moved to a commom funation
>>        as it is required by both the i2c_init.
>>        - Separate functions written to get I2C base address,
>>        peripheral id for pinmux support.
>>        - Hardcoding for I2CCON_ACKGEN removed.
>>        - Replaced printf with debug.
>>        - Checkpatch issues resolved.
>>
>> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
>> Signed-off-by: Doug Anderson <dianders@chromium.org>
>> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>> Acked-by: Simon Glass <sjg@chromium.org>
>> ---
>> Changes in V2:
>>        - Removed #define for I2C cahnnels from hearder file except for I2C0.
>>        - Incorporated review comments from Simon Glass.
>> Changes in V3:
>>        - Incorporated review comments from Joonyoung Shim.
>>        - Reduced the number of #ifdef by modifying get_i2c_base function.
>>        - Removed duplicate code.
>> Changes in V4:
>>        - Resolved build error for s3c2410.
>>  drivers/i2c/s3c24x0_i2c.c |  239 +++++++++++++++++++++++++++++++--------------
>>  drivers/i2c/s3c24x0_i2c.h |    3 +
>>  2 files changed, 168 insertions(+), 74 deletions(-)
>>
>> diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
>> index ba6f39b..0b31cd1 100644
>> --- a/drivers/i2c/s3c24x0_i2c.c
>> +++ b/drivers/i2c/s3c24x0_i2c.c
>> @@ -27,10 +27,17 @@
>>  */
>>
>>  #include <common.h>
>> +#ifdef CONFIG_EXYNOS5
>> +#include <asm/arch/clk.h>
>> +#include <asm/arch/cpu.h>
>> +#include <asm/arch/gpio.h>
>> +#include <asm/arch/pinmux.h>
>> +#else
>>  #include <asm/arch/s3c24x0_cpu.h>
>> -
>> +#endif
>>  #include <asm/io.h>
>>  #include <i2c.h>
>> +#include "s3c24x0_i2c.h"
>>
>>  #ifdef CONFIG_HARD_I2C
>>
>> @@ -45,6 +52,7 @@
>>
>>  #define I2CSTAT_BSY    0x20    /* Busy bit */
>>  #define I2CSTAT_NACK   0x01    /* Nack bit */
>> +#define I2CCON_ACKGEN  0x80    /* Acknowledge generation */
>>  #define I2CCON_IRPND   0x10    /* Interrupt pending bit */
>>  #define I2C_MODE_MT    0xC0    /* Master Transmit Mode */
>>  #define I2C_MODE_MR    0x80    /* Master Receive Mode */
>> @@ -53,6 +61,32 @@
>>
>>  #define I2C_TIMEOUT 1          /* 1 second */
>>
>> +static unsigned int g_current_bus;     /* Stores Current I2C Bus */
>> +
>> +#ifdef CONFIG_EXYNOS5
>> +/* We should not rely on any particular ordering of these IDs */
>> +static enum periph_id periph_for_dev[] = {
>> +       PERIPH_ID_I2C0,
>> +       PERIPH_ID_I2C1,
>> +       PERIPH_ID_I2C2,
>> +       PERIPH_ID_I2C3,
>> +       PERIPH_ID_I2C4,
>> +       PERIPH_ID_I2C5,
>> +       PERIPH_ID_I2C6,
>> +       PERIPH_ID_I2C7,
>> +};
>> +
>> +static enum periph_id i2c_get_periph_id(unsigned dev_index)
>> +{
>> +       if (dev_index < ARRAY_SIZE(periph_for_dev))
>> +               return periph_for_dev[dev_index];
>> +
>> +       debug("%s: invalid bus %d", __func__, dev_index);
>> +
>> +       return PERIPH_ID_NONE;
>> +}
>> +
>> +#else
>>  static int GetI2CSDA(void)
>>  {
>>        struct s3c?--24x0_gpio *gpio = s3c24x0_get_base_gpio();
>> @@ -77,16 +111,17 @@ static void SetI2CSCL(int x)
>>        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
>>
>>  #ifdef CONFIG_S3C2410
>> -       writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
>> +       writel((readl(&gpio->gpedat) & ~0x4000) |
>> +                                       (x & 1) << 14, &gpio->gpedat);
>>  #endif
>>  #ifdef CONFIG_S3C2400
>>        writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
>>  #endif
>>  }
>> +#endif
>>
>> -static int WaitForXfer(void)
>> +static int WaitForXfer(struct s3c24x0_i2c *i2c)
>>  {
>> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
>>        int i;
>>
>>        i = I2C_TIMEOUT * 10000;
>> @@ -98,27 +133,93 @@ static int WaitForXfer(void)
>>        return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
>>  }
>>
>> -static int IsACK(void)
>> +static int IsACK(struct s3c24x0_i2c *i2c)
>>  {
>> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
>> -
>>        return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
>>  }
>>
>> -static void ReadWriteByte(void)
>> +static void ReadWriteByte(struct s3c24x0_i2c *i2c)
>>  {
>> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
>> -
>>        writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
>>  }
>>
>> +static struct s3c24x0_i2c *get_base_i2c(int bus_idx)
>> +{
>> +#ifdef CONFIG_EXYNOS5
>> +       struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)samsung_get_base_i2c();
>> +       return &i2c[bus_idx];
>> +#else
>> +       return s3c24x0_get_base_i2c();
>> +#endif
>> +}
>> +
>> +static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
>> +{
>> +       ulong freq, pres = 16, div;
>> +#ifdef CONFIG_EXYNOS5
>> +       freq = get_i2c_clk();
>> +#else
>> +       freq = get_PCLK();
>> +#endif
>> +       /* calculate prescaler and divisor values */
>> +       if ((freq / pres / (16 + 1)) > speed)
>> +               /* set prescaler to 512 */
>> +               pres = 512;
>> +
>> +       div = 0;
>> +       while ((freq / pres / (div + 1)) > speed)
>> +               div++;
>> +
>> +       /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
>> +       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
>> +
>> +       /* init to SLAVE REVEIVE and set slaveaddr */
>> +       writel(0, &i2c->iicstat);
>> +       writel(slaveadd, &i2c->iicadd);
>> +       /* program Master Transmit (and implicit STOP) */
>> +       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
>> +}
>> +
>> +static void i2c_bus_init(struct s3c24x0_i2c *i2c, unsigned int bus)
>> +{
>> +       int periph_id = i2c_get_periph_id(bus);
>> +
>> +       exynos_pinmux_config(periph_id, 0);
>
> This will cause compile errors at the s3c24xx.
> Also the i2c_bus_init() doesn't be used at the s3c24xx.
>
-- yes will correct this.

>> +
>> +       i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
>> +}
>> +
>> +#ifdef CONFIG_EXYNOS5
>>  void i2c_init(int speed, int slaveadd)
>>  {
>> -       struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
>> +       struct s3c24x0_i2c *i2c;
>> +       int i;
>> +
>> +       /* By default i2c channel 0 is the current bus */
>> +       g_current_bus = I2C0;
>> +
>> +       i2c = get_base_i2c(g_current_bus);
>> +
>> +       i2c_bus_init(i2c, g_current_bus);
>> +
>> +       /* 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--;
>> +       }
>> +}
>
> I think you can make i2c_init() to one function using #ifdef in function.
-- Will do this
>
>> +
>> +#else
>> +void i2c_init(int speed, int slaveadd)
>> +{
>> +       struct s3c24x0_i2c *i2c = get_base_i2c();
>
> Without parameter?
-- Will correct this.
>
>>        struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
>> -       ulong freq, pres = 16, div;
>>        int i;
>>
>> +       /* By default i2c channel 0 is the current bus */
>> +       g_current_bus = I2C0;
>> +
>>        /* wait for some time to give previous transfer a chance to finish */
>>
>>        i = I2C_TIMEOUT * 1000;
>> @@ -171,27 +272,9 @@ void i2c_init(int speed, int slaveadd)
>>  #endif
>>        }
>>
>> -       /* calculate prescaler and divisor values */
>> -       freq = get_PCLK();
>> -       if ((freq / pres / (16 + 1)) > speed)
>> -               /* set prescaler to 512 */
>> -               pres = 512;
>> -
>> -       div = 0;
>> -       while ((freq / pres / (div + 1)) > speed)
>> -               div++;
>> -
>> -       /* set prescaler, divisor according to freq, also set
>> -        * ACKGEN, IRQ */
>> -       writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
>> -
>> -       /* init to SLAVE REVEIVE and set slaveaddr */
>> -       writel(0, &i2c->iicstat);
>> -       writel(slaveadd, &i2c->iicadd);
>> -       /* program Master Transmit (and implicit STOP) */
>> -       writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
>> -
>> +       i2c_ch_init(i2c, speed, slaveadd);
>>  }
>> +#endif
>>
>>  /*
>>  * cmd_type is 0 for write, 1 for read.
>> @@ -200,19 +283,19 @@ void i2c_init(int speed, int slaveadd)
>>  * by the char, we could make it larger if needed. If it is
>>  * 0 we skip the address write cycle.
>>  */
>> -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)
>> +static int i2c_transfer(struct s3c24x0_i2c *i2c,
>> +                       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 = s3c24x0_get_base_i2c();
>>        int i, result;
>>
>>        if (data == 0 || data_len == 0) {
>>                /*Don't support data transfer of no length or to address 0 */
>> -               printf("i2c_transfer: bad call\n");
>> +               debug("i2c_transfer: bad call\n");
>>                return I2C_NOK;
>>        }
>>
>> @@ -226,7 +309,7 @@ int i2c_transfer(unsigned char cmd_type,
>>        if (readl(&i2c->iicstat) & I2CSTAT_BSY)
>>                return I2C_NOK_TOUT;
>>
>> -       writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
>> +       writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
>>        result = I2C_OK;
>>
>>        switch (cmd_type) {
>> @@ -238,16 +321,16 @@ int i2c_transfer(unsigned char cmd_type,
>>                               &i2c->iicstat);
>>                        i = 0;
>>                        while ((i < addr_len) && (result == I2C_OK)) {
>> -                               result = WaitForXfer();
>> +                               result = WaitForXfer(i2c);
>>                                writel(addr[i], &i2c->iicds);
>> -                               ReadWriteByte();
>> +                               ReadWriteByte(i2c);
>>                                i++;
>>                        }
>>                        i = 0;
>>                        while ((i < data_len) && (result == I2C_OK)) {
>> -                               result = WaitForXfer();
>> +                               result = WaitForXfer(i2c);
>>                                writel(data[i], &i2c->iicds);
>> -                               ReadWriteByte();
>> +                               ReadWriteByte(i2c);
>>                                i++;
>>                        }
>>                } else {
>> @@ -257,19 +340,19 @@ int i2c_transfer(unsigned char cmd_type,
>>                               &i2c->iicstat);
>>                        i = 0;
>>                        while ((i < data_len) && (result = I2C_OK)) {
>> -                               result = WaitForXfer();
>> +                               result = WaitForXfer(i2c);
>>                                writel(data[i], &i2c->iicds);
>> -                               ReadWriteByte();
>> +                               ReadWriteByte(i2c);
>>                                i++;
>>                        }
>>                }
>>
>>                if (result == I2C_OK)
>> -                       result = WaitForXfer();
>> +                       result = WaitForXfer(i2c);
>>
>>                /* send STOP */
>>                writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
>> -               ReadWriteByte();
>> +               ReadWriteByte(i2c);
>>                break;
>>
>>        case I2C_READ:
>> @@ -279,13 +362,13 @@ int i2c_transfer(unsigned char cmd_type,
>>                        /* send START */
>>                        writel(readl(&i2c->iicstat) | I2C_START_STOP,
>>                               &i2c->iicstat);
>> -                       result = WaitForXfer();
>> -                       if (IsACK()) {
>> +                       result = WaitForXfer(i2c);
>> +                       if (IsACK(i2c)) {
>>                                i = 0;
>>                                while ((i < addr_len) && (result == I2C_OK)) {
>>                                        writel(addr[i], &i2c->iicds);
>> -                                       ReadWriteByte();
>> -                                       result = WaitForXfer();
>> +                                       ReadWriteByte(i2c);
>> +                                       result = WaitForXfer(i2c);
>>                                        i++;
>>                                }
>>
>> @@ -293,16 +376,17 @@ int i2c_transfer(unsigned char cmd_type,
>>                                /* resend START */
>>                                writel(I2C_MODE_MR | I2C_TXRX_ENA |
>>                                       I2C_START_STOP, &i2c->iicstat);
>> -                               ReadWriteByte();
>> -                               result = WaitForXfer();
>> +                       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)
>> -                                                      & ~0x80, &i2c->iiccon);
>> -                                       ReadWriteByte();
>> -                                       result = WaitForXfer();
>> +                                                       & ~I2CCON_ACKGEN,
>> +                                                       &i2c->iiccon);
>> +                               ReadWriteByte(i2c);
>> +                               result = WaitForXfer(i2c);
>>                                        data[i] = readl(&i2c->iicds);
>>                                        i++;
>>                                }
>> @@ -316,17 +400,18 @@ int i2c_transfer(unsigned char cmd_type,
>>                        /* send START */
>>                        writel(readl(&i2c->iicstat) | I2C_START_STOP,
>>                               &i2c->iicstat);
>> -                       result = WaitForXfer();
>> +                       result = WaitForXfer(i2c);
>>
>> -                       if (IsACK()) {
>> +                       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) &
>> -                                                      ~0x80, &i2c->iiccon);
>> -                                       ReadWriteByte();
>> -                                       result = WaitForXfer();
>> +                                                       ~I2CCON_ACKGEN,
>> +                                                       &i2c->iiccon);
>> +                                       ReadWriteByte(i2c);
>> +                                       result = WaitForXfer(i2c);
>>                                        data[i] = readl(&i2c->iicds);
>>                                        i++;
>>                                }
>> @@ -337,22 +422,24 @@ int i2c_transfer(unsigned char cmd_type,
>>
>>                /* send STOP */
>>                writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
>> -               ReadWriteByte();
>> +               ReadWriteByte(i2c);
>>                break;
>>
>>        default:
>> -               printf("i2c_transfer: bad call\n");
>> +               debug("i2c_transfer: bad call\n");
>>                result = I2C_NOK;
>>                break;
>>        }
>>
>> -       return (result);
>> +       return result;
>>  }
>>
>>  int i2c_probe(uchar chip)
>>  {
>> +       struct s3c24x0_i2c *i2c;
>>        uchar buf[1];
>>
>> +       i2c = get_base_i2c(g_current_bus);
>>        buf[0] = 0;
>>
>>        /*
>> @@ -360,16 +447,17 @@ 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_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
>> +       return i2c_transfer(i2c, 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;
>>
>>        if (alen > 4) {
>> -               printf("I2C read: addr len %d not supported\n", alen);
>> +               debug("I2C read: addr len %d not supported\n", alen);
>>                return 1;
>>        }
>>
>> @@ -396,10 +484,11 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
>>                chip |= ((addr >> (alen * 8)) &
>>                         CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
>>  #endif
>> -       if ((ret =
>> -            i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
>> -                         buffer, len)) != 0) {
>> -               printf("I2c read: failed %d\n", ret);
>> +       i2c = get_base_i2c(g_current_bus);
>> +       ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
>> +                       buffer, len);
>> +       if (ret != 0) {
>> +               debug("I2c read: failed %d\n", ret);
>>                return 1;
>>        }
>>        return 0;
>> @@ -407,10 +496,11 @@ 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) {
>> -               printf("I2C write: addr len %d not supported\n", alen);
>> +               debug("I2C write: addr len %d not supported\n", alen);
>>                return 1;
>>        }
>>
>> @@ -436,8 +526,9 @@ 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(g_current_bus);
>>        return (i2c_transfer
>> -               (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
>> +               (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
>>                 len) != 0);
>>  }
>>  #endif /* CONFIG_HARD_I2C */
>> diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h
>> index d357a0a..57aafb1 100644
>> --- a/drivers/i2c/s3c24x0_i2c.h
>> +++ b/drivers/i2c/s3c24x0_i2c.h
>> @@ -23,6 +23,9 @@
>>  #ifndef _S3C24X0_I2C_H
>>  #define _S3C24X0_I2C_H
>>
>> +/* I2C channels exynos5 has 8 i2c channel */
>> +#define I2C0           0
>> +
>>  struct s3c24x0_i2c {
>>        u32     iiccon;
>>        u32     iicstat;
>> --
>> 1.7.4.4
>>
>
> --
> - Joonyoung Shim
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot

Regards,
Rajeshwari Shinde.
Minkyu Kang June 20, 2012, 8:31 a.m. | #3
Dear Rajeshwari Birje,

On 19 June 2012 19:57, Rajeshwari Birje <rajeshwari.birje@gmail.com> wrote:
> Hi Joonyoung Shim,
>
> On Tue, Jun 19, 2012 at 1:20 PM, Joonyoung Shim <dofmind@gmail.com> wrote:
>> Hi,
>>
>> I add some comments at the below.
>>
> -- ok
>> And current SMDK5250 uses Exynos5250 EVT0 base codes,
>> but i know the kernel supports only Exynos5250 EVT1.
>>
>> So, let's remove Exynos5250 EVT0 codes and add EVT1 codes at the u-boot also.
>> Could you follow up it?
>>
> -- Yes currently we are working on that

So.. do you need to support EVT0? or not?
We want to support EVT1 codes only. (without EVT0)

Thanks.
Minkyu Kang.
Rajeshwari Birje June 20, 2012, 8:47 a.m. | #4
Hi Minkyu Kang,

This being I2C driver code should not have any dependency on EVT0 or EVT1.

Regards,
Rajeshwari Shinde.

On Wed, Jun 20, 2012 at 2:01 PM, Minkyu Kang <promsoft@gmail.com> wrote:
> Dear Rajeshwari Birje,
>
> On 19 June 2012 19:57, Rajeshwari Birje <rajeshwari.birje@gmail.com> wrote:
>> Hi Joonyoung Shim,
>>
>> On Tue, Jun 19, 2012 at 1:20 PM, Joonyoung Shim <dofmind@gmail.com> wrote:
>>> Hi,
>>>
>>> I add some comments at the below.
>>>
>> -- ok
>>> And current SMDK5250 uses Exynos5250 EVT0 base codes,
>>> but i know the kernel supports only Exynos5250 EVT1.
>>>
>>> So, let's remove Exynos5250 EVT0 codes and add EVT1 codes at the u-boot also.
>>> Could you follow up it?
>>>
>> -- Yes currently we are working on that
>
> So.. do you need to support EVT0? or not?
> We want to support EVT1 codes only. (without EVT0)
>
> Thanks.
> Minkyu Kang.
> --
> from. prom.
> www.promsoft.net
Joonyoung Shim June 20, 2012, 9:43 a.m. | #5
2012/6/20 Rajeshwari Birje <rajeshwari.birje@gmail.com>:
> Hi Minkyu Kang,
>
> This being I2C driver code should not have any dependency on EVT0 or EVT1.

I mean *all* arch and driver codes for Exynos5250 should support EVT1 only.

Thanks.

>
> Regards,
> Rajeshwari Shinde.
>
> On Wed, Jun 20, 2012 at 2:01 PM, Minkyu Kang <promsoft@gmail.com> wrote:
>> Dear Rajeshwari Birje,
>>
>> On 19 June 2012 19:57, Rajeshwari Birje <rajeshwari.birje@gmail.com> wrote:
>>> Hi Joonyoung Shim,
>>>
>>> On Tue, Jun 19, 2012 at 1:20 PM, Joonyoung Shim <dofmind@gmail.com> wrote:
>>>> Hi,
>>>>
>>>> I add some comments at the below.
>>>>
>>> -- ok
>>>> And current SMDK5250 uses Exynos5250 EVT0 base codes,
>>>> but i know the kernel supports only Exynos5250 EVT1.
>>>>
>>>> So, let's remove Exynos5250 EVT0 codes and add EVT1 codes at the u-boot also.
>>>> Could you follow up it?
>>>>
>>> -- Yes currently we are working on that
>>
>> So.. do you need to support EVT0? or not?
>> We want to support EVT1 codes only. (without EVT0)
>>
>> Thanks.
>> Minkyu Kang.
>> --
>> from. prom.
>> www.promsoft.net

Patch

diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index ba6f39b..0b31cd1 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -27,10 +27,17 @@ 
  */
 
 #include <common.h>
+#ifdef CONFIG_EXYNOS5
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/pinmux.h>
+#else
 #include <asm/arch/s3c24x0_cpu.h>
-
+#endif
 #include <asm/io.h>
 #include <i2c.h>
+#include "s3c24x0_i2c.h"
 
 #ifdef CONFIG_HARD_I2C
 
@@ -45,6 +52,7 @@ 
 
 #define I2CSTAT_BSY	0x20	/* Busy bit */
 #define I2CSTAT_NACK	0x01	/* Nack bit */
+#define I2CCON_ACKGEN	0x80	/* Acknowledge generation */
 #define I2CCON_IRPND	0x10	/* Interrupt pending bit */
 #define I2C_MODE_MT	0xC0	/* Master Transmit Mode */
 #define I2C_MODE_MR	0x80	/* Master Receive Mode */
@@ -53,6 +61,32 @@ 
 
 #define I2C_TIMEOUT 1		/* 1 second */
 
+static unsigned int g_current_bus;	/* Stores Current I2C Bus */
+
+#ifdef CONFIG_EXYNOS5
+/* We should not rely on any particular ordering of these IDs */
+static enum periph_id periph_for_dev[] = {
+	PERIPH_ID_I2C0,
+	PERIPH_ID_I2C1,
+	PERIPH_ID_I2C2,
+	PERIPH_ID_I2C3,
+	PERIPH_ID_I2C4,
+	PERIPH_ID_I2C5,
+	PERIPH_ID_I2C6,
+	PERIPH_ID_I2C7,
+};
+
+static enum periph_id i2c_get_periph_id(unsigned dev_index)
+{
+	if (dev_index < ARRAY_SIZE(periph_for_dev))
+		return periph_for_dev[dev_index];
+
+	debug("%s: invalid bus %d", __func__, dev_index);
+
+	return PERIPH_ID_NONE;
+}
+
+#else
 static int GetI2CSDA(void)
 {
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
@@ -77,16 +111,17 @@  static void SetI2CSCL(int x)
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
 
 #ifdef CONFIG_S3C2410
-	writel((readl(&gpio->gpedat) & ~0x4000) | (x & 1) << 14, &gpio->gpedat);
+	writel((readl(&gpio->gpedat) & ~0x4000) |
+					(x & 1) << 14, &gpio->gpedat);
 #endif
 #ifdef CONFIG_S3C2400
 	writel((readl(&gpio->pgdat) & ~0x0040) | (x & 1) << 6, &gpio->pgdat);
 #endif
 }
+#endif
 
-static int WaitForXfer(void)
+static int WaitForXfer(struct s3c24x0_i2c *i2c)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
 	int i;
 
 	i = I2C_TIMEOUT * 10000;
@@ -98,27 +133,93 @@  static int WaitForXfer(void)
 	return (readl(&i2c->iiccon) & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
 }
 
-static int IsACK(void)
+static int IsACK(struct s3c24x0_i2c *i2c)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
 	return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
 }
 
-static void ReadWriteByte(void)
+static void ReadWriteByte(struct s3c24x0_i2c *i2c)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
-
 	writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
 }
 
+static struct s3c24x0_i2c *get_base_i2c(int bus_idx)
+{
+#ifdef CONFIG_EXYNOS5
+	struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)samsung_get_base_i2c();
+	return &i2c[bus_idx];
+#else
+	return s3c24x0_get_base_i2c();
+#endif
+}
+
+static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
+{
+	ulong freq, pres = 16, div;
+#ifdef CONFIG_EXYNOS5
+	freq = get_i2c_clk();
+#else
+	freq = get_PCLK();
+#endif
+	/* calculate prescaler and divisor values */
+	if ((freq / pres / (16 + 1)) > speed)
+		/* set prescaler to 512 */
+		pres = 512;
+
+	div = 0;
+	while ((freq / pres / (div + 1)) > speed)
+		div++;
+
+	/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
+	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
+
+	/* init to SLAVE REVEIVE and set slaveaddr */
+	writel(0, &i2c->iicstat);
+	writel(slaveadd, &i2c->iicadd);
+	/* program Master Transmit (and implicit STOP) */
+	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
+}
+
+static void i2c_bus_init(struct s3c24x0_i2c *i2c, unsigned int bus)
+{
+	int periph_id = i2c_get_periph_id(bus);
+
+	exynos_pinmux_config(periph_id, 0);
+
+	i2c_ch_init(i2c, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+}
+
+#ifdef CONFIG_EXYNOS5
 void i2c_init(int speed, int slaveadd)
 {
-	struct s3c24x0_i2c *i2c = s3c24x0_get_base_i2c();
+	struct s3c24x0_i2c *i2c;
+	int i;
+
+	/* By default i2c channel 0 is the current bus */
+	g_current_bus = I2C0;
+
+	i2c = get_base_i2c(g_current_bus);
+
+	i2c_bus_init(i2c, g_current_bus);
+
+	/* 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--;
+	}
+}
+
+#else
+void i2c_init(int speed, int slaveadd)
+{
+	struct s3c24x0_i2c *i2c = get_base_i2c();
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
-	ulong freq, pres = 16, div;
 	int i;
 
+	/* By default i2c channel 0 is the current bus */
+	g_current_bus = I2C0;
+
 	/* wait for some time to give previous transfer a chance to finish */
 
 	i = I2C_TIMEOUT * 1000;
@@ -171,27 +272,9 @@  void i2c_init(int speed, int slaveadd)
 #endif
 	}
 
-	/* calculate prescaler and divisor values */
-	freq = get_PCLK();
-	if ((freq / pres / (16 + 1)) > speed)
-		/* set prescaler to 512 */
-		pres = 512;
-
-	div = 0;
-	while ((freq / pres / (div + 1)) > speed)
-		div++;
-
-	/* set prescaler, divisor according to freq, also set
-	 * ACKGEN, IRQ */
-	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
-
-	/* init to SLAVE REVEIVE and set slaveaddr */
-	writel(0, &i2c->iicstat);
-	writel(slaveadd, &i2c->iicadd);
-	/* program Master Transmit (and implicit STOP) */
-	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
-
+	i2c_ch_init(i2c, speed, slaveadd);
 }
+#endif
 
 /*
  * cmd_type is 0 for write, 1 for read.
@@ -200,19 +283,19 @@  void i2c_init(int speed, int slaveadd)
  * by the char, we could make it larger if needed. If it is
  * 0 we skip the address write cycle.
  */
-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)
+static int i2c_transfer(struct s3c24x0_i2c *i2c,
+			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 = s3c24x0_get_base_i2c();
 	int i, result;
 
 	if (data == 0 || data_len == 0) {
 		/*Don't support data transfer of no length or to address 0 */
-		printf("i2c_transfer: bad call\n");
+		debug("i2c_transfer: bad call\n");
 		return I2C_NOK;
 	}
 
@@ -226,7 +309,7 @@  int i2c_transfer(unsigned char cmd_type,
 	if (readl(&i2c->iicstat) & I2CSTAT_BSY)
 		return I2C_NOK_TOUT;
 
-	writel(readl(&i2c->iiccon) | 0x80, &i2c->iiccon);
+	writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
 	result = I2C_OK;
 
 	switch (cmd_type) {
@@ -238,16 +321,16 @@  int i2c_transfer(unsigned char cmd_type,
 			       &i2c->iicstat);
 			i = 0;
 			while ((i < addr_len) && (result == I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
 				writel(addr[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
 				i++;
 			}
 			i = 0;
 			while ((i < data_len) && (result == I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
 				writel(data[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
 				i++;
 			}
 		} else {
@@ -257,19 +340,19 @@  int i2c_transfer(unsigned char cmd_type,
 			       &i2c->iicstat);
 			i = 0;
 			while ((i < data_len) && (result = I2C_OK)) {
-				result = WaitForXfer();
+				result = WaitForXfer(i2c);
 				writel(data[i], &i2c->iicds);
-				ReadWriteByte();
+				ReadWriteByte(i2c);
 				i++;
 			}
 		}
 
 		if (result == I2C_OK)
-			result = WaitForXfer();
+			result = WaitForXfer(i2c);
 
 		/* send STOP */
 		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-		ReadWriteByte();
+		ReadWriteByte(i2c);
 		break;
 
 	case I2C_READ:
@@ -279,13 +362,13 @@  int i2c_transfer(unsigned char cmd_type,
 			/* send START */
 			writel(readl(&i2c->iicstat) | I2C_START_STOP,
 			       &i2c->iicstat);
-			result = WaitForXfer();
-			if (IsACK()) {
+			result = WaitForXfer(i2c);
+			if (IsACK(i2c)) {
 				i = 0;
 				while ((i < addr_len) && (result == I2C_OK)) {
 					writel(addr[i], &i2c->iicds);
-					ReadWriteByte();
-					result = WaitForXfer();
+					ReadWriteByte(i2c);
+					result = WaitForXfer(i2c);
 					i++;
 				}
 
@@ -293,16 +376,17 @@  int i2c_transfer(unsigned char cmd_type,
 				/* resend START */
 				writel(I2C_MODE_MR | I2C_TXRX_ENA |
 				       I2C_START_STOP, &i2c->iicstat);
-				ReadWriteByte();
-				result = WaitForXfer();
+			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)
-						       & ~0x80, &i2c->iiccon);
-					ReadWriteByte();
-					result = WaitForXfer();
+							& ~I2CCON_ACKGEN,
+							&i2c->iiccon);
+				ReadWriteByte(i2c);
+				result = WaitForXfer(i2c);
 					data[i] = readl(&i2c->iicds);
 					i++;
 				}
@@ -316,17 +400,18 @@  int i2c_transfer(unsigned char cmd_type,
 			/* send START */
 			writel(readl(&i2c->iicstat) | I2C_START_STOP,
 			       &i2c->iicstat);
-			result = WaitForXfer();
+			result = WaitForXfer(i2c);
 
-			if (IsACK()) {
+			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) &
-						       ~0x80, &i2c->iiccon);
-					ReadWriteByte();
-					result = WaitForXfer();
+							~I2CCON_ACKGEN,
+							&i2c->iiccon);
+					ReadWriteByte(i2c);
+					result = WaitForXfer(i2c);
 					data[i] = readl(&i2c->iicds);
 					i++;
 				}
@@ -337,22 +422,24 @@  int i2c_transfer(unsigned char cmd_type,
 
 		/* send STOP */
 		writel(I2C_MODE_MR | I2C_TXRX_ENA, &i2c->iicstat);
-		ReadWriteByte();
+		ReadWriteByte(i2c);
 		break;
 
 	default:
-		printf("i2c_transfer: bad call\n");
+		debug("i2c_transfer: bad call\n");
 		result = I2C_NOK;
 		break;
 	}
 
-	return (result);
+	return result;
 }
 
 int i2c_probe(uchar chip)
 {
+	struct s3c24x0_i2c *i2c;
 	uchar buf[1];
 
+	i2c = get_base_i2c(g_current_bus);
 	buf[0] = 0;
 
 	/*
@@ -360,16 +447,17 @@  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_READ, chip << 1, 0, 0, buf, 1) != I2C_OK;
+	return i2c_transfer(i2c, 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;
 
 	if (alen > 4) {
-		printf("I2C read: addr len %d not supported\n", alen);
+		debug("I2C read: addr len %d not supported\n", alen);
 		return 1;
 	}
 
@@ -396,10 +484,11 @@  int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
 		chip |= ((addr >> (alen * 8)) &
 			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 #endif
-	if ((ret =
-	     i2c_transfer(I2C_READ, chip << 1, &xaddr[4 - alen], alen,
-			  buffer, len)) != 0) {
-		printf("I2c read: failed %d\n", ret);
+	i2c = get_base_i2c(g_current_bus);
+	ret = i2c_transfer(i2c, I2C_READ, chip << 1, &xaddr[4 - alen], alen,
+			buffer, len);
+	if (ret != 0) {
+		debug("I2c read: failed %d\n", ret);
 		return 1;
 	}
 	return 0;
@@ -407,10 +496,11 @@  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) {
-		printf("I2C write: addr len %d not supported\n", alen);
+		debug("I2C write: addr len %d not supported\n", alen);
 		return 1;
 	}
 
@@ -436,8 +526,9 @@  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(g_current_bus);
 	return (i2c_transfer
-		(I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
+		(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
 		 len) != 0);
 }
 #endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h
index d357a0a..57aafb1 100644
--- a/drivers/i2c/s3c24x0_i2c.h
+++ b/drivers/i2c/s3c24x0_i2c.h
@@ -23,6 +23,9 @@ 
 #ifndef _S3C24X0_I2C_H
 #define _S3C24X0_I2C_H
 
+/* I2C channels exynos5 has 8 i2c channel */
+#define I2C0		0
+
 struct s3c24x0_i2c {
 	u32	iiccon;
 	u32	iicstat;