[U-Boot] [PATCH 0/6] EXYNOS5: FDT Support for I2C

This patch set adds FDT support for I2C driver and API's to acess the bus number using the fdt node and also reset the port.
Rajeshwari Shinde (6): EXYNOS5: FDT: Add I2C device node data EXYNOS5 : FDT: Add Aliases for I2C device EXYNOS5: FDT: Add compatible string for I2C FDT: Api to find compatible id for a given node I2C: Driver changes for FDT support SMDK5250: Populate I2C data using FDT.
arch/arm/dts/exynos5250.dtsi | 64 +++++++++++++++++++++ board/samsung/dts/exynos5250-smdk5250.dts | 11 ++++ board/samsung/smdk5250/smdk5250.c | 7 ++- drivers/i2c/s3c24x0_i2c.c | 89 ++++++++++++++++++++++++++++- drivers/i2c/s3c24x0_i2c.h | 7 ++ include/fdtdec.h | 15 +++++ include/i2c.h | 28 +++++++++ lib/fdtdec.c | 13 ++++ 8 files changed, 231 insertions(+), 3 deletions(-)

Add I2C device node data for exynos
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- arch/arm/dts/exynos5250.dtsi | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 64 insertions(+), 0 deletions(-)
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index db22db6..e877e6c 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -33,4 +33,68 @@ compatible = "samsung,exynos-tmu"; reg = <0x10060000 0xffff>; }; + + i2c@12c60000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12C60000 0x100>; + interrupts = <0 56 0>; + }; + + i2c@12c70000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12C70000 0x100>; + interrupts = <0 57 0>; + }; + + i2c@12c80000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12C80000 0x100>; + interrupts = <0 58 0>; + }; + + i2c@12c90000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12C90000 0x100>; + interrupts = <0 59 0>; + }; + + i2c@12ca0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12CA0000 0x100>; + interrupts = <0 60 0>; + }; + + i2c@12cb0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12CB0000 0x100>; + interrupts = <0 61 0>; + }; + + i2c@12cc0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12CC0000 0x100>; + interrupts = <0 62 0>; + }; + + i2c@12cd0000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "samsung,s3c2440-i2c"; + reg = <0x12CD0000 0x100>; + interrupts = <0 63 0>; + }; };

On Wed, Nov 7, 2012 at 9:29 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
Add I2C device node data for exynos
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
arch/arm/dts/exynos5250.dtsi | 64 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 64 insertions(+), 0 deletions(-)
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index db22db6..e877e6c 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -33,4 +33,68 @@ compatible = "samsung,exynos-tmu"; reg = <0x10060000 0xffff>; };
i2c@12c60000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12C60000 0x100>;
interrupts = <0 56 0>;
};
i2c@12c70000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12C70000 0x100>;
interrupts = <0 57 0>;
};
i2c@12c80000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12C80000 0x100>;
interrupts = <0 58 0>;
};
i2c@12c90000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12C90000 0x100>;
interrupts = <0 59 0>;
};
i2c@12ca0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12CA0000 0x100>;
interrupts = <0 60 0>;
};
i2c@12cb0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12CB0000 0x100>;
interrupts = <0 61 0>;
};
i2c@12cc0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12CC0000 0x100>;
interrupts = <0 62 0>;
};
i2c@12cd0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "samsung,s3c2440-i2c";
reg = <0x12CD0000 0x100>;
interrupts = <0 63 0>;
};
};
1.7.4.4

This patch adds aliases for I2C.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- board/samsung/dts/exynos5250-smdk5250.dts | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index 2d3ecca..8722b36 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -16,6 +16,17 @@ model = "SAMSUNG SMDK5250 board based on EXYNOS5250"; compatible = "samsung,smdk5250", "samsung,exynos5250";
+ aliases { + i2c0 = "/i2c@12c60000"; + i2c1 = "/i2c@12c70000"; + i2c2 = "/i2c@12c80000"; + i2c3 = "/i2c@12c90000"; + i2c4 = "/i2c@12ca0000"; + i2c5 = "/i2c@12cb0000"; + i2c6 = "/i2c@12cc0000"; + i2c7 = "/i2c@12cd0000"; + }; + sromc@12250000 { bank = <1>; srom-timing = <1 9 12 1 6 1 1>;

On Wed, Nov 7, 2012 at 9:29 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds aliases for I2C.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
board/samsung/dts/exynos5250-smdk5250.dts | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index 2d3ecca..8722b36 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -16,6 +16,17 @@ model = "SAMSUNG SMDK5250 board based on EXYNOS5250"; compatible = "samsung,smdk5250", "samsung,exynos5250";
aliases {
i2c0 = "/i2c@12c60000";
i2c1 = "/i2c@12c70000";
i2c2 = "/i2c@12c80000";
i2c3 = "/i2c@12c90000";
i2c4 = "/i2c@12ca0000";
i2c5 = "/i2c@12cb0000";
i2c6 = "/i2c@12cc0000";
i2c7 = "/i2c@12cd0000";
};
sromc@12250000 { bank = <1>; srom-timing = <1 9 12 1 6 1 1>;
-- 1.7.4.4

Add required compatible information for I2C driver.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/fdtdec.h b/include/fdtdec.h index 180dfff..f9aac31 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -69,6 +69,7 @@ enum fdt_compat_id { COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */ COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */ COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */ + COMPAT_SAMSUNG_S3C2440_I2C, /* Exynos I2C Controller */
COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 8e5ed21..6e8c24c 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -46,6 +46,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SMSC_LAN9215, "smsc,lan9215"), COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), + COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

On Wed, Nov 7, 2012 at 9:30 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
Add required compatible information for I2C driver.
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org
include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/fdtdec.h b/include/fdtdec.h index 180dfff..f9aac31 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -69,6 +69,7 @@ enum fdt_compat_id { COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */ COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */ COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */
COMPAT_SAMSUNG_S3C2440_I2C, /* Exynos I2C Controller */ COMPAT_COUNT,
}; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 8e5ed21..6e8c24c 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -46,6 +46,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SMSC_LAN9215, "smsc,lan9215"), COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
1.7.4.4

This patch adds api to find compatible id for a given FDT node
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- include/fdtdec.h | 14 ++++++++++++++ lib/fdtdec.c | 12 ++++++++++++ 2 files changed, 26 insertions(+), 0 deletions(-)
diff --git a/include/fdtdec.h b/include/fdtdec.h index f9aac31..d501d7e 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -389,4 +389,18 @@ int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name, */ const u8 *fdtdec_locate_byte_array(const void *blob, int node, const char *prop_name, int count); + +/** + * Find the compatible ID for a given node. + * + * Generally each node has at least one compatible string attached to it. + * This function looks through our list of known compatible strings and + * returns the corresponding ID which matches the compatible string. + * + * @param blob FDT blob to use + * @param node Node containing compatible string to find + * @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match + */ +enum fdt_compat_id fdtdec_lookup(const void *blob, int node); + #endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 6e8c24c..dbfca1a 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -516,3 +516,15 @@ const u8 *fdtdec_locate_byte_array(const void *blob, int node, return NULL; return cell; } + +enum fdt_compat_id fdtdec_lookup(const void *blob, int node) +{ + enum fdt_compat_id id; + + /* Search our drivers */ + for (id = COMPAT_UNKNOWN; id < COMPAT_COUNT; id++) + if (0 == fdt_node_check_compatible(blob, node, + compat_names[id])) + return id; + return COMPAT_UNKNOWN; +}

On Wed, Nov 7, 2012 at 9:30 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
This patch adds api to find compatible id for a given FDT node
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
Acked-by: Simon Glass sjg@chromium.org

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 --- drivers/i2c/s3c24x0_i2c.c | 89 ++++++++++++++++++++++++++++++++++++++++++++- drivers/i2c/s3c24x0_i2c.h | 7 ++++ include/i2c.h | 28 ++++++++++++++ 3 files changed, 123 insertions(+), 1 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9bc4c7f..952f76c 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,6 +27,7 @@ */
#include <common.h> +#include <fdtdec.h> #ifdef CONFIG_EXYNOS5 #include <asm/arch/clk.h> #include <asm/arch/cpu.h> @@ -60,7 +61,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 +515,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 +unsigned int i2c_fdt_bus_values(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->node = node; + bus->bus_num = i2c_busses++; + } + + return count; +} + +static struct s3c24x0_i2c_bus *get_bus(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; + fdt_addr_t reg; + int i; + + compat = fdtdec_lookup(blob, node); + if (compat != COMPAT_SAMSUNG_S3C2440_I2C) { + debug("%s: Not a supported I2C node\n", __func__); + return -1; + } + reg = fdtdec_get_addr(blob, node, "reg"); + for (i = 0; i < i2c_busses; i++) { + if (reg == (fdt_addr_t)(uintptr_t)i2c_bus[i].regs) + 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..bdd5514 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -30,4 +30,11 @@ 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; +}; + #endif /* _S3C24X0_I2C_H */ diff --git a/include/i2c.h b/include/i2c.h index 16f099d..52be093 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -262,4 +262,32 @@ extern int get_multi_scl_pin(void); extern int get_multi_sda_pin(void); extern int multi_i2c_init(void); #endif + +#ifdef CONFIG_OF_CONTROL +/** + * Get FDT values for i2c bus. + * + * @param blob Device tree blbo + * @return the number of I2C bus + */ +unsigned int i2c_fdt_bus_values(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 #endif /* _I2C_H_ */

Hi Rajeshwari,
On Wed, Nov 7, 2012 at 9:30 PM, 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
drivers/i2c/s3c24x0_i2c.c | 89 ++++++++++++++++++++++++++++++++++++++++++++- drivers/i2c/s3c24x0_i2c.h | 7 ++++ include/i2c.h | 28 ++++++++++++++ 3 files changed, 123 insertions(+), 1 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9bc4c7f..952f76c 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,6 +27,7 @@ */
#include <common.h> +#include <fdtdec.h> #ifdef CONFIG_EXYNOS5 #include <asm/arch/clk.h> #include <asm/arch/cpu.h> @@ -60,7 +61,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 +515,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 +unsigned int i2c_fdt_bus_values(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->node = node;
bus->bus_num = i2c_busses++;
}
return count;
+}
This seems to be the init function for i2c, so how about calling it board_i2c_init() or similar. I don't think you need to return the count of i2c ports - you can just use CONFIG_MAX_I2C_NUM anywhere that it is needed.
+static struct s3c24x0_i2c_bus *get_bus(int bus_idx)
should probably be unsigned so that you don't need to check < 0
+{
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;
fdt_addr_t reg;
int i;
compat = fdtdec_lookup(blob, node);
if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
debug("%s: Not a supported I2C node\n", __func__);
return -1;
}
reg = fdtdec_get_addr(blob, node, "reg");
for (i = 0; i < i2c_busses; i++) {
if (reg == (fdt_addr_t)(uintptr_t)i2c_bus[i].regs)
return i;
}
This seems painful. You already have a table of node versus bus number, created in the function above, so why not just look in that?
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..bdd5514 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -30,4 +30,11 @@ 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;
+};
#endif /* _S3C24X0_I2C_H */ diff --git a/include/i2c.h b/include/i2c.h index 16f099d..52be093 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -262,4 +262,32 @@ extern int get_multi_scl_pin(void); extern int get_multi_sda_pin(void); extern int multi_i2c_init(void); #endif
+#ifdef CONFIG_OF_CONTROL
I think you can omit this line - it doesn't hurt to have unused prototypes. We will get a link error if someone does something silly.
+/**
- Get FDT values for i2c bus.
- @param blob Device tree blbo
- @return the number of I2C bus
- */
+unsigned int i2c_fdt_bus_values(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
#endif /* _I2C_H_ */
1.7.4.4
Regards, Simon

Hi Simon Glass,
Thank you for comments.
On Fri, Nov 9, 2012 at 6:34 AM, Simon Glass sjg@chromium.org wrote:
Hi Rajeshwari,
On Wed, Nov 7, 2012 at 9:30 PM, 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
drivers/i2c/s3c24x0_i2c.c | 89 ++++++++++++++++++++++++++++++++++++++++++++- drivers/i2c/s3c24x0_i2c.h | 7 ++++ include/i2c.h | 28 ++++++++++++++ 3 files changed, 123 insertions(+), 1 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9bc4c7f..952f76c 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,6 +27,7 @@ */
#include <common.h> +#include <fdtdec.h> #ifdef CONFIG_EXYNOS5 #include <asm/arch/clk.h> #include <asm/arch/cpu.h> @@ -60,7 +61,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 +515,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 +unsigned int i2c_fdt_bus_values(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->node = node;
bus->bus_num = i2c_busses++;
}
return count;
+}
This seems to be the init function for i2c, so how about calling it board_i2c_init() or similar. I don't think you need to return the count of i2c ports - you can just use CONFIG_MAX_I2C_NUM anywhere that it is needed.
+static struct s3c24x0_i2c_bus *get_bus(int bus_idx)
should probably be unsigned so that you don't need to check < 0
+{
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;
fdt_addr_t reg;
int i;
compat = fdtdec_lookup(blob, node);
if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
debug("%s: Not a supported I2C node\n", __func__);
return -1;
}
reg = fdtdec_get_addr(blob, node, "reg");
for (i = 0; i < i2c_busses; i++) {
if (reg == (fdt_addr_t)(uintptr_t)i2c_bus[i].regs)
return i;
}
This seems painful. You already have a table of node versus bus number, created in the function above, so why not just look in that?
You want me to use get_bus function? but that function takes the bus number and gives the handle to the structure and not the i2c channel register address. Hence we cannot use that function here, instead I am using the structures populated in board_i2c_init. Do clarify if I have misunderstood the comment.
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..bdd5514 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -30,4 +30,11 @@ 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;
+};
#endif /* _S3C24X0_I2C_H */ diff --git a/include/i2c.h b/include/i2c.h index 16f099d..52be093 100644 --- a/include/i2c.h +++ b/include/i2c.h @@ -262,4 +262,32 @@ extern int get_multi_scl_pin(void); extern int get_multi_sda_pin(void); extern int multi_i2c_init(void); #endif
+#ifdef CONFIG_OF_CONTROL
I think you can omit this line - it doesn't hurt to have unused prototypes. We will get a link error if someone does something silly.
+/**
- Get FDT values for i2c bus.
- @param blob Device tree blbo
- @return the number of I2C bus
- */
+unsigned int i2c_fdt_bus_values(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
#endif /* _I2C_H_ */
1.7.4.4
Regards, Simon _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot
Regards, Rajeshwari

Hi Rajeshwari,
On Mon, Nov 12, 2012 at 5:03 AM, Rajeshwari Birje rajeshwari.birje@gmail.com wrote:
Hi Simon Glass,
Thank you for comments.
On Fri, Nov 9, 2012 at 6:34 AM, Simon Glass sjg@chromium.org wrote:
Hi Rajeshwari,
On Wed, Nov 7, 2012 at 9:30 PM, 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
drivers/i2c/s3c24x0_i2c.c | 89 ++++++++++++++++++++++++++++++++++++++++++++- drivers/i2c/s3c24x0_i2c.h | 7 ++++ include/i2c.h | 28 ++++++++++++++ 3 files changed, 123 insertions(+), 1 deletions(-)
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9bc4c7f..952f76c 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,6 +27,7 @@ */
#include <common.h> +#include <fdtdec.h> #ifdef CONFIG_EXYNOS5 #include <asm/arch/clk.h> #include <asm/arch/cpu.h> @@ -60,7 +61,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 +515,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 +unsigned int i2c_fdt_bus_values(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->node = node;
bus->bus_num = i2c_busses++;
}
return count;
+}
This seems to be the init function for i2c, so how about calling it board_i2c_init() or similar. I don't think you need to return the count of i2c ports - you can just use CONFIG_MAX_I2C_NUM anywhere that it is needed.
+static struct s3c24x0_i2c_bus *get_bus(int bus_idx)
should probably be unsigned so that you don't need to check < 0
+{
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;
fdt_addr_t reg;
int i;
compat = fdtdec_lookup(blob, node);
if (compat != COMPAT_SAMSUNG_S3C2440_I2C) {
debug("%s: Not a supported I2C node\n", __func__);
return -1;
}
reg = fdtdec_get_addr(blob, node, "reg");
for (i = 0; i < i2c_busses; i++) {
if (reg == (fdt_addr_t)(uintptr_t)i2c_bus[i].regs)
return i;
}
This seems painful. You already have a table of node versus bus number, created in the function above, so why not just look in that?
You want me to use get_bus function? but that function takes the bus number and gives the handle to the structure and not the i2c channel register address. Hence we cannot use that function here, instead I am using the structures populated in board_i2c_init. Do clarify if I have misunderstood the comment.
What I mean is that you have set up a table of node versus bus number in i2c_fdt_bus_values(). So there should be no need to go and look again at the fdt in i2c_get_bus_num_fdt() - you can just write a function to search your table.
[snip]
Regards, Simon

Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com --- board/samsung/smdk5250/smdk5250.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index db2457b..dfb7239 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -276,8 +276,11 @@ static int board_uart_init(void) static int board_i2c_init(void) { int i, err; - - for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) { + int count = CONFIG_MAX_I2C_NUM; +#ifdef CONFIG_OF_CONTROL + count = i2c_fdt_bus_values(gd->fdt_blob); +#endif + for (i = 0; i < count; i++) { err = exynos_pinmux_config((PERIPH_ID_I2C0 + i), PINMUX_FLAG_NONE); if (err) {

Hi Rajeshwari,
On Wed, Nov 7, 2012 at 9:30 PM, Rajeshwari Shinde rajeshwari.s@samsung.com wrote:
Signed-off-by: Rajeshwari Shinde rajeshwari.s@samsung.com
board/samsung/smdk5250/smdk5250.c | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index db2457b..dfb7239 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -276,8 +276,11 @@ static int board_uart_init(void) static int board_i2c_init(void) { int i, err;
for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) {
int count = CONFIG_MAX_I2C_NUM;
+#ifdef CONFIG_OF_CONTROL
count = i2c_fdt_bus_values(gd->fdt_blob);
+#endif
for (i = 0; i < count; i++) { err = exynos_pinmux_config((PERIPH_ID_I2C0 + i), PINMUX_FLAG_NONE); if (err) {
Hmmm well I think you are trying to avoid setting the pinmux for unused ports. But actually the active ports are determined by the aliases at present (later we will perhaps use the 'status' property as we should).
So getting the number of ports doesn't help you - for example, there might be 4 ports, but only 0 and 3 are used. You may as well just use CONFIG_MAX_I2C_NUM as it will be no less correct in general.
If you want to setup pinmux only for the ports that are used you will need to put the exynos_pinmux_config() call inside the driver in the fdt case. It can set up pinmux in your init function when it finds a port that is being used in the fdt (the function I suggested you rename to board_init_i2c()()).
-- 1.7.4.4
Regards, Simon
participants (3)
-
Rajeshwari Birje
-
Rajeshwari Shinde
-
Simon Glass