[U-Boot,5/6,V2] I2C: Driver changes for FDT support

Submitted by Rajeshwari Birje on Nov. 14, 2012, 9:11 a.m.

Details

Message ID 1352884279-24067-6-git-send-email-rajeshwari.s@samsung.com
State Superseded
Delegated to: Heiko Schocher
Headers show

Commit Message

Rajeshwari Birje Nov. 14, 2012, 9:11 a.m.
Functions added to get the I2C bus number and reset I2C bus using
FDT node.

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
---
Changes in V2:
	- Added periph id to I2C bus structure.
	- Modified i2c_get_bus_num_fdt function to compare with node.
	- Board i2c init moved to driver in case of FDT.
 drivers/i2c/s3c24x0_i2c.c |   90 ++++++++++++++++++++++++++++++++++++++++++++-
 drivers/i2c/s3c24x0_i2c.h |    8 ++++
 include/i2c.h             |   26 +++++++++++++
 3 files changed, 123 insertions(+), 1 deletions(-)

Comments

Simon Glass Nov. 14, 2012, 6:45 p.m.
Hi,

On Wed, Nov 14, 2012 at 1:11 AM, Rajeshwari Shinde
<rajeshwari.s@samsung.com> wrote:
> Functions added to get the I2C bus number and reset I2C bus using
> FDT node.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
> ---
> Changes in V2:
>         - Added periph id to I2C bus structure.
>         - Modified i2c_get_bus_num_fdt function to compare with node.
>         - Board i2c init moved to driver in case of FDT.

This looks good to me, apart from a small thing you can probably drop below.

>  drivers/i2c/s3c24x0_i2c.c |   90 ++++++++++++++++++++++++++++++++++++++++++++-
>  drivers/i2c/s3c24x0_i2c.h |    8 ++++
>  include/i2c.h             |   26 +++++++++++++
>  3 files changed, 123 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
> index 9bc4c7f..840585d 100644
> --- a/drivers/i2c/s3c24x0_i2c.c
> +++ b/drivers/i2c/s3c24x0_i2c.c
> @@ -27,9 +27,11 @@
>   */
>
>  #include <common.h>
> +#include <fdtdec.h>
>  #ifdef CONFIG_EXYNOS5
>  #include <asm/arch/clk.h>
>  #include <asm/arch/cpu.h>
> +#include <asm/arch/pinmux.h>
>  #else
>  #include <asm/arch/s3c24x0_cpu.h>
>  #endif
> @@ -60,7 +62,14 @@
>  #define I2C_TIMEOUT 1          /* 1 second */
>
>
> -static unsigned int g_current_bus;     /* Stores Current I2C Bus */
> +/*
> + * For SPL boot some boards need i2c before SDRAM is initialised so force
> + * variables to live in SRAM
> + */
> +static unsigned int g_current_bus __attribute__((section(".data")));
> +static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
> +                       __attribute__((section(".data")));
> +static int i2c_busses __attribute__((section(".data")));
>
>  #ifndef CONFIG_EXYNOS5
>  static int GetI2CSDA(void)
> @@ -507,4 +516,83 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
>                 (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
>                  len) != 0);
>  }
> +
> +#ifdef CONFIG_OF_CONTROL
> +void board_i2c_init(const void *blob)
> +{
> +
> +       int node_list[CONFIG_MAX_I2C_NUM];
> +       int count, i;
> +
> +       count = fdtdec_find_aliases_for_id(blob, "i2c",
> +               COMPAT_SAMSUNG_S3C2440_I2C, node_list,
> +               CONFIG_MAX_I2C_NUM);
> +       for (i = 0; i < count; i++) {
> +               struct s3c24x0_i2c_bus *bus;
> +               int node = node_list[i];
> +
> +               if (node < 0)
> +                       continue;
> +               bus = &i2c_bus[i];
> +               bus->regs = (struct s3c24x0_i2c *)
> +                       fdtdec_get_addr(blob, node, "reg");
> +               bus->id = (enum periph_id)
> +                       fdtdec_get_int(blob, node, "samsung,periph-id", -1);
> +               bus->node = node;
> +               bus->bus_num = i2c_busses++;
> +               exynos_pinmux_config(bus->id, 0);
> +       }
> +
> +}
> +
> +static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx)
> +{
> +       if (bus_idx < i2c_busses)
> +               return &i2c_bus[bus_idx];
> +       debug("Undefined bus: %d\n", bus_idx);
> +       return NULL;
> +}
> +
> +int i2c_get_bus_num_fdt(const void *blob, int node)
> +{
> +       enum fdt_compat_id compat;
> +       int i;
> +
> +       compat = fdtdec_lookup(blob, node);
> +       if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
> +               debug("%s: Not a supported I2C node\n", __func__);
> +               return -1;
> +       }

I think you can drop this check, since your code immediately below
will handle a missing node.

> +       for (i = 0; i < i2c_busses; i++) {
> +               if (node == i2c_bus[i].node)
> +                       return i;
> +       }
> +
> +       debug("%s: Can't find any matched I2C bus\n", __func__);
> +       return -1;
> +}
> +
> +int i2c_reset_port_fdt(const void *blob, int node)
> +{
> +       struct s3c24x0_i2c_bus *i2c;
> +
> +       int bus;
> +
> +       bus = i2c_get_bus_num_fdt(blob, node);
> +       if (bus < 0) {
> +               debug("could not get bus for node %d\n", node);
> +               return -1;
> +       }
> +       i2c = get_bus(bus);
> +       if (!i2c) {
> +               debug("get_bus() failed for node node %d\n", node);
> +               return -1;
> +       }
> +
> +       i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
> +
> +       return 0;
> +}
> +#endif
> +
>  #endif /* CONFIG_HARD_I2C */
> diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h
> index 2dd4b06..1243bf1 100644
> --- a/drivers/i2c/s3c24x0_i2c.h
> +++ b/drivers/i2c/s3c24x0_i2c.h
> @@ -30,4 +30,12 @@ struct s3c24x0_i2c {
>         u32     iicds;
>         u32     iiclc;
>  };
> +
> +struct s3c24x0_i2c_bus {
> +       int node;       /* device tree node */
> +       int bus_num;    /* i2c bus number */
> +       struct s3c24x0_i2c *regs;
> +       enum periph_id id;
> +};
> +
>  #endif /* _S3C24X0_I2C_H */
> diff --git a/include/i2c.h b/include/i2c.h
> index 16f099d..efb097f 100644
> --- a/include/i2c.h
> +++ b/include/i2c.h
> @@ -262,4 +262,30 @@ extern int get_multi_scl_pin(void);
>  extern int get_multi_sda_pin(void);
>  extern int multi_i2c_init(void);
>  #endif
> +
> +/**
> + * Get FDT values for i2c bus.
> + *
> + * @param blob  Device tree blbo
> + * @return the number of I2C bus
> + */
> +void board_i2c_init(const void *blob);
> +
> +/**
> + * Find the I2C bus number by given a FDT I2C node.
> + *
> + * @param blob  Device tree blbo
> + * @param node  FDT I2C node to find
> + * @return the number of I2C bus (zero based), or -1 on error
> + */
> +int i2c_get_bus_num_fdt(const void *blob, int node);
> +
> +/**
> + * Reset the I2C bus represented by the given a FDT I2C node.
> + *
> + * @param blob  Device tree blbo
> + * @param node  FDT I2C node to find
> + * @return 0 if port was reset, -1 if not found
> + */
> +int i2c_reset_port_fdt(const void *blob, int node);
>  #endif /* _I2C_H_ */
> --
> 1.7.4.4
>

Regards,
Simon
Heiko Schocher Nov. 15, 2012, 6:59 a.m.
Hello Rajeshwari,

On 14.11.2012 10:11, Rajeshwari Shinde wrote:
> Functions added to get the I2C bus number and reset I2C bus using
> FDT node.
>
> Signed-off-by: Simon Glass<sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde<rajeshwari.s@samsung.com>
> ---
> Changes in V2:
> 	- Added periph id to I2C bus structure.
> 	- Modified i2c_get_bus_num_fdt function to compare with node.
> 	- Board i2c init moved to driver in case of FDT.
>   drivers/i2c/s3c24x0_i2c.c |   90 ++++++++++++++++++++++++++++++++++++++++++++-
>   drivers/i2c/s3c24x0_i2c.h |    8 ++++
>   include/i2c.h             |   26 +++++++++++++
>   3 files changed, 123 insertions(+), 1 deletions(-)

patch looks good, just some nitpicking comments ...

> diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
> index 9bc4c7f..840585d 100644
> --- a/drivers/i2c/s3c24x0_i2c.c
> +++ b/drivers/i2c/s3c24x0_i2c.c
[...]
> @@ -507,4 +516,83 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
>   		(i2c, I2C_WRITE, chip<<  1,&xaddr[4 - alen], alen, buffer,
>   		 len) != 0);
>   }
> +
> +#ifdef CONFIG_OF_CONTROL
> +void board_i2c_init(const void *blob)
> +{
> +
> +	int node_list[CONFIG_MAX_I2C_NUM];
> +	int count, i;
> +
> +	count = fdtdec_find_aliases_for_id(blob, "i2c",
> +		COMPAT_SAMSUNG_S3C2440_I2C, node_list,
> +		CONFIG_MAX_I2C_NUM);
> +	for (i = 0; i<  count; i++) {
> +		struct s3c24x0_i2c_bus *bus;
> +		int node = node_list[i];
> +
> +		if (node<  0)
> +			continue;
> +		bus =&i2c_bus[i];
                      ^
                      space please
> +		bus->regs = (struct s3c24x0_i2c *)
> +			fdtdec_get_addr(blob, node, "reg");
> +		bus->id = (enum periph_id)
> +			fdtdec_get_int(blob, node, "samsung,periph-id", -1);
> +		bus->node = node;
> +		bus->bus_num = i2c_busses++;
> +		exynos_pinmux_config(bus->id, 0);
> +	}
> +
> +}
> +
> +static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx)
> +{
> +	if (bus_idx<  i2c_busses)
                    ^
                    space please
> +		return&i2c_bus[bus_idx];
                       ^
                       space please
> +	debug("Undefined bus: %d\n", bus_idx);
> +	return NULL;
> +}
> +
> +int i2c_get_bus_num_fdt(const void *blob, int node)
> +{
> +	enum fdt_compat_id compat;
> +	int i;
> +
> +	compat = fdtdec_lookup(blob, node);
> +	if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
> +		debug("%s: Not a supported I2C node\n", __func__);
> +		return -1;
> +	}
> +	for (i = 0; i<  i2c_busses; i++) {
> +		if (node == i2c_bus[i].node)
> +			return i;
> +	}
> +
> +	debug("%s: Can't find any matched I2C bus\n", __func__);
> +	return -1;
> +}
> +
> +int i2c_reset_port_fdt(const void *blob, int node)
> +{
> +	struct s3c24x0_i2c_bus *i2c;
> +
> +	int bus;
> +
> +	bus = i2c_get_bus_num_fdt(blob, node);
> +	if (bus<  0) {
                ^
                space
> +		debug("could not get bus for node %d\n", node);
> +		return -1;
> +	}
> +	i2c = get_bus(bus);
> +	if (!i2c) {
> +		debug("get_bus() failed for node node %d\n", node);
> +		return -1;
> +	}
> +
> +	i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
> +
> +	return 0;
> +}
> +#endif
> +
>   #endif /* CONFIG_HARD_I2C */
> diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h
> index 2dd4b06..1243bf1 100644
> --- a/drivers/i2c/s3c24x0_i2c.h
> +++ b/drivers/i2c/s3c24x0_i2c.h
> @@ -30,4 +30,12 @@ struct s3c24x0_i2c {
>   	u32	iicds;
>   	u32	iiclc;
>   };
> +
> +struct s3c24x0_i2c_bus {
> +	int node;	/* device tree node */
> +	int bus_num;	/* i2c bus number */
> +	struct s3c24x0_i2c *regs;
> +	enum periph_id id;
> +};
> +
>   #endif /* _S3C24X0_I2C_H */
> diff --git a/include/i2c.h b/include/i2c.h
> index 16f099d..efb097f 100644
> --- a/include/i2c.h
> +++ b/include/i2c.h
> @@ -262,4 +262,30 @@ extern int get_multi_scl_pin(void);
>   extern int get_multi_sda_pin(void);
>   extern int multi_i2c_init(void);
>   #endif
> +
> +/**
> + * Get FDT values for i2c bus.
> + *
> + * @param blob  Device tree blbo
                                ^
                                blob
> + * @return the number of I2C bus
> + */
> +void board_i2c_init(const void *blob);
> +
> +/**
> + * Find the I2C bus number by given a FDT I2C node.
> + *
> + * @param blob  Device tree blbo
                                ^
                                blob
> + * @param node  FDT I2C node to find
> + * @return the number of I2C bus (zero based), or -1 on error
> + */
> +int i2c_get_bus_num_fdt(const void *blob, int node);
> +
> +/**
> + * Reset the I2C bus represented by the given a FDT I2C node.
> + *
> + * @param blob  Device tree blbo
> + * @param node  FDT I2C node to find
> + * @return 0 if port was reset, -1 if not found
> + */
> +int i2c_reset_port_fdt(const void *blob, int node);
>   #endif	/* _I2C_H_ */

Thanks!

Reviewed-by: Heiko Schocher <hs@denx.de>

bye,
Heiko
Rajeshwari Birje Nov. 15, 2012, 11 a.m.
Hi Heiko,

Thank you for the comments will modify the same and resend the patch.

Regards,
Rajeshwari Shinde.

On Thu, Nov 15, 2012 at 12:29 PM, Heiko Schocher <hs@denx.de> wrote:
> Hello Rajeshwari,
>
>
> On 14.11.2012 10:11, Rajeshwari Shinde wrote:
>>
>> Functions added to get the I2C bus number and reset I2C bus using
>> FDT node.
>>
>> Signed-off-by: Simon Glass<sjg@chromium.org>
>> Signed-off-by: Rajeshwari Shinde<rajeshwari.s@samsung.com>
>> ---
>> Changes in V2:
>>         - Added periph id to I2C bus structure.
>>         - Modified i2c_get_bus_num_fdt function to compare with node.
>>         - Board i2c init moved to driver in case of FDT.
>>   drivers/i2c/s3c24x0_i2c.c |   90
>> ++++++++++++++++++++++++++++++++++++++++++++-
>>   drivers/i2c/s3c24x0_i2c.h |    8 ++++
>>   include/i2c.h             |   26 +++++++++++++
>>   3 files changed, 123 insertions(+), 1 deletions(-)
>
>
> patch looks good, just some nitpicking comments ...
>
>
>> diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
>> index 9bc4c7f..840585d 100644
>> --- a/drivers/i2c/s3c24x0_i2c.c
>> +++ b/drivers/i2c/s3c24x0_i2c.c
>
> [...]
>>
>> @@ -507,4 +516,83 @@ int i2c_write(uchar chip, uint addr, int alen, uchar
>> *buffer, int len)
>>                 (i2c, I2C_WRITE, chip<<  1,&xaddr[4 - alen], alen, buffer,
>>
>>                  len) != 0);
>>   }
>> +
>> +#ifdef CONFIG_OF_CONTROL
>> +void board_i2c_init(const void *blob)
>> +{
>> +
>> +       int node_list[CONFIG_MAX_I2C_NUM];
>> +       int count, i;
>> +
>> +       count = fdtdec_find_aliases_for_id(blob, "i2c",
>> +               COMPAT_SAMSUNG_S3C2440_I2C, node_list,
>> +               CONFIG_MAX_I2C_NUM);
>> +       for (i = 0; i<  count; i++) {
>> +               struct s3c24x0_i2c_bus *bus;
>> +               int node = node_list[i];
>> +
>> +               if (node<  0)
>> +                       continue;
>> +               bus =&i2c_bus[i];
>
>                      ^
>                      space please
>
>> +               bus->regs = (struct s3c24x0_i2c *)
>> +                       fdtdec_get_addr(blob, node, "reg");
>> +               bus->id = (enum periph_id)
>> +                       fdtdec_get_int(blob, node, "samsung,periph-id",
>> -1);
>> +               bus->node = node;
>> +               bus->bus_num = i2c_busses++;
>> +               exynos_pinmux_config(bus->id, 0);
>> +       }
>> +
>> +}
>> +
>> +static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx)
>> +{
>> +       if (bus_idx<  i2c_busses)
>
>                    ^
>                    space please
>>
>> +               return&i2c_bus[bus_idx];
>
>                       ^
>                       space please
>
>> +       debug("Undefined bus: %d\n", bus_idx);
>> +       return NULL;
>> +}
>> +
>> +int i2c_get_bus_num_fdt(const void *blob, int node)
>> +{
>> +       enum fdt_compat_id compat;
>> +       int i;
>> +
>> +       compat = fdtdec_lookup(blob, node);
>> +       if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
>> +               debug("%s: Not a supported I2C node\n", __func__);
>> +               return -1;
>> +       }
>> +       for (i = 0; i<  i2c_busses; i++) {
>> +               if (node == i2c_bus[i].node)
>> +                       return i;
>> +       }
>> +
>> +       debug("%s: Can't find any matched I2C bus\n", __func__);
>> +       return -1;
>> +}
>> +
>> +int i2c_reset_port_fdt(const void *blob, int node)
>> +{
>> +       struct s3c24x0_i2c_bus *i2c;
>> +
>> +       int bus;
>> +
>> +       bus = i2c_get_bus_num_fdt(blob, node);
>> +       if (bus<  0) {
>
>                ^
>                space
>
>> +               debug("could not get bus for node %d\n", node);
>> +               return -1;
>> +       }
>> +       i2c = get_bus(bus);
>> +       if (!i2c) {
>> +               debug("get_bus() failed for node node %d\n", node);
>> +               return -1;
>> +       }
>> +
>> +       i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED,
>> CONFIG_SYS_I2C_SLAVE);
>> +
>> +       return 0;
>> +}
>> +#endif
>> +
>>   #endif /* CONFIG_HARD_I2C */
>> diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h
>> index 2dd4b06..1243bf1 100644
>> --- a/drivers/i2c/s3c24x0_i2c.h
>> +++ b/drivers/i2c/s3c24x0_i2c.h
>> @@ -30,4 +30,12 @@ struct s3c24x0_i2c {
>>         u32     iicds;
>>         u32     iiclc;
>>   };
>> +
>> +struct s3c24x0_i2c_bus {
>> +       int node;       /* device tree node */
>> +       int bus_num;    /* i2c bus number */
>> +       struct s3c24x0_i2c *regs;
>> +       enum periph_id id;
>> +};
>> +
>>   #endif /* _S3C24X0_I2C_H */
>> diff --git a/include/i2c.h b/include/i2c.h
>> index 16f099d..efb097f 100644
>> --- a/include/i2c.h
>> +++ b/include/i2c.h
>> @@ -262,4 +262,30 @@ extern int get_multi_scl_pin(void);
>>   extern int get_multi_sda_pin(void);
>>   extern int multi_i2c_init(void);
>>   #endif
>> +
>> +/**
>> + * Get FDT values for i2c bus.
>> + *
>> + * @param blob  Device tree blbo
>
>                                ^
>                                blob
>
>> + * @return the number of I2C bus
>> + */
>> +void board_i2c_init(const void *blob);
>> +
>> +/**
>> + * Find the I2C bus number by given a FDT I2C node.
>> + *
>> + * @param blob  Device tree blbo
>
>                                ^
>                                blob
>
>> + * @param node  FDT I2C node to find
>> + * @return the number of I2C bus (zero based), or -1 on error
>> + */
>> +int i2c_get_bus_num_fdt(const void *blob, int node);
>> +
>> +/**
>> + * Reset the I2C bus represented by the given a FDT I2C node.
>> + *
>> + * @param blob  Device tree blbo
>> + * @param node  FDT I2C node to find
>> + * @return 0 if port was reset, -1 if not found
>> + */
>> +int i2c_reset_port_fdt(const void *blob, int node);
>>   #endif        /* _I2C_H_ */
>
>
> Thanks!
>
> Reviewed-by: Heiko Schocher <hs@denx.de>
>
> bye,
> Heiko
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
Heiko Schocher Nov. 19, 2012, 8:54 a.m.
Hello Rajeshwari,

On 14.11.2012 10:11, Rajeshwari Shinde:wrote
> Functions added to get the I2C bus number and reset I2C bus using
> FDT node.
>
> Signed-off-by: Simon Glass<sjg@chromium.org>
> Signed-off-by: Rajeshwari Shinde<rajeshwari.s@samsung.com>
> ---
> Changes in V2:
> 	- Added periph id to I2C bus structure.
> 	- Modified i2c_get_bus_num_fdt function to compare with node.
> 	- Board i2c init moved to driver in case of FDT.
>   drivers/i2c/s3c24x0_i2c.c |   90 ++++++++++++++++++++++++++++++++++++++++++++-
>   drivers/i2c/s3c24x0_i2c.h |    8 ++++
>   include/i2c.h             |   26 +++++++++++++
>   3 files changed, 123 insertions(+), 1 deletions(-)

Acked-by: Heiko Schocher <hs@denx.de>

bye,
Heiko

Patch hide | download patch | download mbox

diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index 9bc4c7f..840585d 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -27,9 +27,11 @@ 
  */
 
 #include <common.h>
+#include <fdtdec.h>
 #ifdef CONFIG_EXYNOS5
 #include <asm/arch/clk.h>
 #include <asm/arch/cpu.h>
+#include <asm/arch/pinmux.h>
 #else
 #include <asm/arch/s3c24x0_cpu.h>
 #endif
@@ -60,7 +62,14 @@ 
 #define I2C_TIMEOUT 1		/* 1 second */
 
 
-static unsigned int g_current_bus;	/* Stores Current I2C Bus */
+/*
+ * For SPL boot some boards need i2c before SDRAM is initialised so force
+ * variables to live in SRAM
+ */
+static unsigned int g_current_bus __attribute__((section(".data")));
+static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
+			__attribute__((section(".data")));
+static int i2c_busses __attribute__((section(".data")));
 
 #ifndef CONFIG_EXYNOS5
 static int GetI2CSDA(void)
@@ -507,4 +516,83 @@  int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
 		(i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
 		 len) != 0);
 }
+
+#ifdef CONFIG_OF_CONTROL
+void board_i2c_init(const void *blob)
+{
+
+	int node_list[CONFIG_MAX_I2C_NUM];
+	int count, i;
+
+	count = fdtdec_find_aliases_for_id(blob, "i2c",
+		COMPAT_SAMSUNG_S3C2440_I2C, node_list,
+		CONFIG_MAX_I2C_NUM);
+	for (i = 0; i < count; i++) {
+		struct s3c24x0_i2c_bus *bus;
+		int node = node_list[i];
+
+		if (node < 0)
+			continue;
+		bus = &i2c_bus[i];
+		bus->regs = (struct s3c24x0_i2c *)
+			fdtdec_get_addr(blob, node, "reg");
+		bus->id = (enum periph_id)
+			fdtdec_get_int(blob, node, "samsung,periph-id", -1);
+		bus->node = node;
+		bus->bus_num = i2c_busses++;
+		exynos_pinmux_config(bus->id, 0);
+	}
+
+}
+
+static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx)
+{
+	if (bus_idx < i2c_busses)
+		return &i2c_bus[bus_idx];
+	debug("Undefined bus: %d\n", bus_idx);
+	return NULL;
+}
+
+int i2c_get_bus_num_fdt(const void *blob, int node)
+{
+	enum fdt_compat_id compat;
+	int i;
+
+	compat = fdtdec_lookup(blob, node);
+	if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
+		debug("%s: Not a supported I2C node\n", __func__);
+		return -1;
+	}
+	for (i = 0; i < i2c_busses; i++) {
+		if (node == i2c_bus[i].node)
+			return i;
+	}
+
+	debug("%s: Can't find any matched I2C bus\n", __func__);
+	return -1;
+}
+
+int i2c_reset_port_fdt(const void *blob, int node)
+{
+	struct s3c24x0_i2c_bus *i2c;
+
+	int bus;
+
+	bus = i2c_get_bus_num_fdt(blob, node);
+	if (bus < 0) {
+		debug("could not get bus for node %d\n", node);
+		return -1;
+	}
+	i2c = get_bus(bus);
+	if (!i2c) {
+		debug("get_bus() failed for node node %d\n", node);
+		return -1;
+	}
+
+	i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+	return 0;
+}
+#endif
+
 #endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h
index 2dd4b06..1243bf1 100644
--- a/drivers/i2c/s3c24x0_i2c.h
+++ b/drivers/i2c/s3c24x0_i2c.h
@@ -30,4 +30,12 @@  struct s3c24x0_i2c {
 	u32	iicds;
 	u32	iiclc;
 };
+
+struct s3c24x0_i2c_bus {
+	int node;	/* device tree node */
+	int bus_num;	/* i2c bus number */
+	struct s3c24x0_i2c *regs;
+	enum periph_id id;
+};
+
 #endif /* _S3C24X0_I2C_H */
diff --git a/include/i2c.h b/include/i2c.h
index 16f099d..efb097f 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -262,4 +262,30 @@  extern int get_multi_scl_pin(void);
 extern int get_multi_sda_pin(void);
 extern int multi_i2c_init(void);
 #endif
+
+/**
+ * Get FDT values for i2c bus.
+ *
+ * @param blob  Device tree blbo
+ * @return the number of I2C bus
+ */
+void board_i2c_init(const void *blob);
+
+/**
+ * Find the I2C bus number by given a FDT I2C node.
+ *
+ * @param blob  Device tree blbo
+ * @param node  FDT I2C node to find
+ * @return the number of I2C bus (zero based), or -1 on error
+ */
+int i2c_get_bus_num_fdt(const void *blob, int node);
+
+/**
+ * Reset the I2C bus represented by the given a FDT I2C node.
+ *
+ * @param blob  Device tree blbo
+ * @param node  FDT I2C node to find
+ * @return 0 if port was reset, -1 if not found
+ */
+int i2c_reset_port_fdt(const void *blob, int node);
 #endif	/* _I2C_H_ */