diff options
author | Avinash.H.M <avinashhm@ti.com> | 2011-07-10 07:27:16 -0400 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2011-07-10 07:27:16 -0400 |
commit | 6d3c55fd4f0f94a9455d30df9414ddb0f755f402 (patch) | |
tree | 7b1838e66fa1a424db45c84855062df121b9506b /arch/arm | |
parent | 4d4441a6221ca3a30290045b7b696e5134646449 (diff) |
OMAP: hwmod: fix the i2c-reset timeout during bootup
The sequence of _ocp_softreset doesn't work for i2c. The i2c module has a
special sequence to reset the module. The sequence is
- Disable the I2C.
- Write to SOFTRESET bit.
- Enable the I2C.
- Poll on the RESETDONE bit.
The sequence is implemented as a function and the i2c_class is updated with
the correct 'reset' pointer. omap_hwmod_softreset function is implemented
which triggers the softreset by writing into sysconfig register. On following
this sequence, i2c module resets properly and timeouts are not seen.
Cc: Rajendra Nayak <rnayak@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Kevin Hilman <khilman@ti.com>
Signed-off-by: Avinash.H.M <avinashhm@ti.com>
[paul@pwsan.com: combined this patch with a patch to remove
HWMOD_INIT_NO_RESET from the 44xx hwmod flags; change register
offset conditional code to use the IP block revision; minor code
cleanup]
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/i2c.c | 68 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 27 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod_2420_data.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod_2430_data.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 10 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/i2c.h | 3 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 |
8 files changed, 111 insertions, 7 deletions
diff --git a/arch/arm/mach-omap2/i2c.c b/arch/arm/mach-omap2/i2c.c index 79c478c4cb1c..ace99944e96f 100644 --- a/arch/arm/mach-omap2/i2c.c +++ b/arch/arm/mach-omap2/i2c.c | |||
@@ -21,9 +21,19 @@ | |||
21 | 21 | ||
22 | #include <plat/cpu.h> | 22 | #include <plat/cpu.h> |
23 | #include <plat/i2c.h> | 23 | #include <plat/i2c.h> |
24 | #include <plat/common.h> | ||
25 | #include <plat/omap_hwmod.h> | ||
24 | 26 | ||
25 | #include "mux.h" | 27 | #include "mux.h" |
26 | 28 | ||
29 | /* In register I2C_CON, Bit 15 is the I2C enable bit */ | ||
30 | #define I2C_EN BIT(15) | ||
31 | #define OMAP2_I2C_CON_OFFSET 0x24 | ||
32 | #define OMAP4_I2C_CON_OFFSET 0xA4 | ||
33 | |||
34 | /* Maximum microseconds to wait for OMAP module to softreset */ | ||
35 | #define MAX_MODULE_SOFTRESET_WAIT 10000 | ||
36 | |||
27 | void __init omap2_i2c_mux_pins(int bus_id) | 37 | void __init omap2_i2c_mux_pins(int bus_id) |
28 | { | 38 | { |
29 | char mux_name[sizeof("i2c2_scl.i2c2_scl")]; | 39 | char mux_name[sizeof("i2c2_scl.i2c2_scl")]; |
@@ -37,3 +47,61 @@ void __init omap2_i2c_mux_pins(int bus_id) | |||
37 | sprintf(mux_name, "i2c%i_sda.i2c%i_sda", bus_id, bus_id); | 47 | sprintf(mux_name, "i2c%i_sda.i2c%i_sda", bus_id, bus_id); |
38 | omap_mux_init_signal(mux_name, OMAP_PIN_INPUT); | 48 | omap_mux_init_signal(mux_name, OMAP_PIN_INPUT); |
39 | } | 49 | } |
50 | |||
51 | /** | ||
52 | * omap_i2c_reset - reset the omap i2c module. | ||
53 | * @oh: struct omap_hwmod * | ||
54 | * | ||
55 | * The i2c moudle in omap2, omap3 had a special sequence to reset. The | ||
56 | * sequence is: | ||
57 | * - Disable the I2C. | ||
58 | * - Write to SOFTRESET bit. | ||
59 | * - Enable the I2C. | ||
60 | * - Poll on the RESETDONE bit. | ||
61 | * The sequence is implemented in below function. This is called for 2420, | ||
62 | * 2430 and omap3. | ||
63 | */ | ||
64 | int omap_i2c_reset(struct omap_hwmod *oh) | ||
65 | { | ||
66 | u32 v; | ||
67 | u16 i2c_con; | ||
68 | int c = 0; | ||
69 | |||
70 | if (oh->class->rev == OMAP_I2C_IP_VERSION_2) { | ||
71 | i2c_con = OMAP4_I2C_CON_OFFSET; | ||
72 | } else if (oh->class->rev == OMAP_I2C_IP_VERSION_1) { | ||
73 | i2c_con = OMAP2_I2C_CON_OFFSET; | ||
74 | } else { | ||
75 | WARN(1, "Cannot reset I2C block %s: unsupported revision\n", | ||
76 | oh->name); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | /* Disable I2C */ | ||
81 | v = omap_hwmod_read(oh, i2c_con); | ||
82 | v &= ~I2C_EN; | ||
83 | omap_hwmod_write(v, oh, i2c_con); | ||
84 | |||
85 | /* Write to the SOFTRESET bit */ | ||
86 | omap_hwmod_softreset(oh); | ||
87 | |||
88 | /* Enable I2C */ | ||
89 | v = omap_hwmod_read(oh, i2c_con); | ||
90 | v |= I2C_EN; | ||
91 | omap_hwmod_write(v, oh, i2c_con); | ||
92 | |||
93 | /* Poll on RESETDONE bit */ | ||
94 | omap_test_timeout((omap_hwmod_read(oh, | ||
95 | oh->class->sysc->syss_offs) | ||
96 | & SYSS_RESETDONE_MASK), | ||
97 | MAX_MODULE_SOFTRESET_WAIT, c); | ||
98 | |||
99 | if (c == MAX_MODULE_SOFTRESET_WAIT) | ||
100 | pr_warning("%s: %s: softreset failed (waited %d usec)\n", | ||
101 | __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT); | ||
102 | else | ||
103 | pr_debug("%s: %s: softreset in %d usec\n", __func__, | ||
104 | oh->name, c); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 7d242c9e2a2c..02b6016393a8 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -1656,6 +1656,33 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs) | |||
1656 | } | 1656 | } |
1657 | 1657 | ||
1658 | /** | 1658 | /** |
1659 | * omap_hwmod_softreset - reset a module via SYSCONFIG.SOFTRESET bit | ||
1660 | * @oh: struct omap_hwmod * | ||
1661 | * | ||
1662 | * This is a public function exposed to drivers. Some drivers may need to do | ||
1663 | * some settings before and after resetting the device. Those drivers after | ||
1664 | * doing the necessary settings could use this function to start a reset by | ||
1665 | * setting the SYSCONFIG.SOFTRESET bit. | ||
1666 | */ | ||
1667 | int omap_hwmod_softreset(struct omap_hwmod *oh) | ||
1668 | { | ||
1669 | u32 v; | ||
1670 | int ret; | ||
1671 | |||
1672 | if (!oh || !(oh->_sysc_cache)) | ||
1673 | return -EINVAL; | ||
1674 | |||
1675 | v = oh->_sysc_cache; | ||
1676 | ret = _set_softreset(oh, &v); | ||
1677 | if (ret) | ||
1678 | goto error; | ||
1679 | _write_sysconfig(v, oh); | ||
1680 | |||
1681 | error: | ||
1682 | return ret; | ||
1683 | } | ||
1684 | |||
1685 | /** | ||
1659 | * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode | 1686 | * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode |
1660 | * @oh: struct omap_hwmod * | 1687 | * @oh: struct omap_hwmod * |
1661 | * @idlemode: SIDLEMODE field bits (shifted to bit 0) | 1688 | * @idlemode: SIDLEMODE field bits (shifted to bit 0) |
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c index 7af251448a7e..a015c69068f6 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c | |||
@@ -1030,6 +1030,7 @@ static struct omap_hwmod_class i2c_class = { | |||
1030 | .name = "i2c", | 1030 | .name = "i2c", |
1031 | .sysc = &i2c_sysc, | 1031 | .sysc = &i2c_sysc, |
1032 | .rev = OMAP_I2C_IP_VERSION_1, | 1032 | .rev = OMAP_I2C_IP_VERSION_1, |
1033 | .reset = &omap_i2c_reset, | ||
1033 | }; | 1034 | }; |
1034 | 1035 | ||
1035 | static struct omap_i2c_dev_attr i2c_dev_attr = { | 1036 | static struct omap_i2c_dev_attr i2c_dev_attr = { |
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c index 405688ae265b..16743c7d6e8e 100644 --- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c | |||
@@ -1079,6 +1079,7 @@ static struct omap_hwmod_class i2c_class = { | |||
1079 | .name = "i2c", | 1079 | .name = "i2c", |
1080 | .sysc = &i2c_sysc, | 1080 | .sysc = &i2c_sysc, |
1081 | .rev = OMAP_I2C_IP_VERSION_1, | 1081 | .rev = OMAP_I2C_IP_VERSION_1, |
1082 | .reset = &omap_i2c_reset, | ||
1082 | }; | 1083 | }; |
1083 | 1084 | ||
1084 | static struct omap_i2c_dev_attr i2c_dev_attr = { | 1085 | static struct omap_i2c_dev_attr i2c_dev_attr = { |
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index c704ac8ca6bb..25bf43b5a4ec 100644 --- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | |||
@@ -1306,9 +1306,10 @@ static struct omap_hwmod omap3xxx_uart4_hwmod = { | |||
1306 | }; | 1306 | }; |
1307 | 1307 | ||
1308 | static struct omap_hwmod_class i2c_class = { | 1308 | static struct omap_hwmod_class i2c_class = { |
1309 | .name = "i2c", | 1309 | .name = "i2c", |
1310 | .sysc = &i2c_sysc, | 1310 | .sysc = &i2c_sysc, |
1311 | .rev = OMAP_I2C_IP_VERSION_1, | 1311 | .rev = OMAP_I2C_IP_VERSION_1, |
1312 | .reset = &omap_i2c_reset, | ||
1312 | }; | 1313 | }; |
1313 | 1314 | ||
1314 | static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = { | 1315 | static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = { |
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 55331df4e452..5d5df49749df 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <plat/omap_hwmod.h> | 23 | #include <plat/omap_hwmod.h> |
24 | #include <plat/cpu.h> | 24 | #include <plat/cpu.h> |
25 | #include <plat/i2c.h> | ||
25 | #include <plat/gpio.h> | 26 | #include <plat/gpio.h> |
26 | #include <plat/dma.h> | 27 | #include <plat/dma.h> |
27 | #include <plat/mcspi.h> | 28 | #include <plat/mcspi.h> |
@@ -2162,6 +2163,7 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = { | |||
2162 | .name = "i2c", | 2163 | .name = "i2c", |
2163 | .sysc = &omap44xx_i2c_sysc, | 2164 | .sysc = &omap44xx_i2c_sysc, |
2164 | .rev = OMAP_I2C_IP_VERSION_2, | 2165 | .rev = OMAP_I2C_IP_VERSION_2, |
2166 | .reset = &omap_i2c_reset, | ||
2165 | }; | 2167 | }; |
2166 | 2168 | ||
2167 | static struct omap_i2c_dev_attr i2c_dev_attr = { | 2169 | static struct omap_i2c_dev_attr i2c_dev_attr = { |
@@ -2207,7 +2209,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c1_slaves[] = { | |||
2207 | static struct omap_hwmod omap44xx_i2c1_hwmod = { | 2209 | static struct omap_hwmod omap44xx_i2c1_hwmod = { |
2208 | .name = "i2c1", | 2210 | .name = "i2c1", |
2209 | .class = &omap44xx_i2c_hwmod_class, | 2211 | .class = &omap44xx_i2c_hwmod_class, |
2210 | .flags = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET, | 2212 | .flags = HWMOD_16BIT_REG, |
2211 | .mpu_irqs = omap44xx_i2c1_irqs, | 2213 | .mpu_irqs = omap44xx_i2c1_irqs, |
2212 | .sdma_reqs = omap44xx_i2c1_sdma_reqs, | 2214 | .sdma_reqs = omap44xx_i2c1_sdma_reqs, |
2213 | .main_clk = "i2c1_fck", | 2215 | .main_clk = "i2c1_fck", |
@@ -2261,7 +2263,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c2_slaves[] = { | |||
2261 | static struct omap_hwmod omap44xx_i2c2_hwmod = { | 2263 | static struct omap_hwmod omap44xx_i2c2_hwmod = { |
2262 | .name = "i2c2", | 2264 | .name = "i2c2", |
2263 | .class = &omap44xx_i2c_hwmod_class, | 2265 | .class = &omap44xx_i2c_hwmod_class, |
2264 | .flags = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET, | 2266 | .flags = HWMOD_16BIT_REG, |
2265 | .mpu_irqs = omap44xx_i2c2_irqs, | 2267 | .mpu_irqs = omap44xx_i2c2_irqs, |
2266 | .sdma_reqs = omap44xx_i2c2_sdma_reqs, | 2268 | .sdma_reqs = omap44xx_i2c2_sdma_reqs, |
2267 | .main_clk = "i2c2_fck", | 2269 | .main_clk = "i2c2_fck", |
@@ -2315,7 +2317,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c3_slaves[] = { | |||
2315 | static struct omap_hwmod omap44xx_i2c3_hwmod = { | 2317 | static struct omap_hwmod omap44xx_i2c3_hwmod = { |
2316 | .name = "i2c3", | 2318 | .name = "i2c3", |
2317 | .class = &omap44xx_i2c_hwmod_class, | 2319 | .class = &omap44xx_i2c_hwmod_class, |
2318 | .flags = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET, | 2320 | .flags = HWMOD_16BIT_REG, |
2319 | .mpu_irqs = omap44xx_i2c3_irqs, | 2321 | .mpu_irqs = omap44xx_i2c3_irqs, |
2320 | .sdma_reqs = omap44xx_i2c3_sdma_reqs, | 2322 | .sdma_reqs = omap44xx_i2c3_sdma_reqs, |
2321 | .main_clk = "i2c3_fck", | 2323 | .main_clk = "i2c3_fck", |
@@ -2369,7 +2371,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c4_slaves[] = { | |||
2369 | static struct omap_hwmod omap44xx_i2c4_hwmod = { | 2371 | static struct omap_hwmod omap44xx_i2c4_hwmod = { |
2370 | .name = "i2c4", | 2372 | .name = "i2c4", |
2371 | .class = &omap44xx_i2c_hwmod_class, | 2373 | .class = &omap44xx_i2c_hwmod_class, |
2372 | .flags = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET, | 2374 | .flags = HWMOD_16BIT_REG, |
2373 | .mpu_irqs = omap44xx_i2c4_irqs, | 2375 | .mpu_irqs = omap44xx_i2c4_irqs, |
2374 | .sdma_reqs = omap44xx_i2c4_sdma_reqs, | 2376 | .sdma_reqs = omap44xx_i2c4_sdma_reqs, |
2375 | .main_clk = "i2c4_fck", | 2377 | .main_clk = "i2c4_fck", |
diff --git a/arch/arm/plat-omap/include/plat/i2c.h b/arch/arm/plat-omap/include/plat/i2c.h index fd75dadfa89c..7c22b9e10dc3 100644 --- a/arch/arm/plat-omap/include/plat/i2c.h +++ b/arch/arm/plat-omap/include/plat/i2c.h | |||
@@ -53,4 +53,7 @@ struct omap_i2c_dev_attr { | |||
53 | void __init omap1_i2c_mux_pins(int bus_id); | 53 | void __init omap1_i2c_mux_pins(int bus_id); |
54 | void __init omap2_i2c_mux_pins(int bus_id); | 54 | void __init omap2_i2c_mux_pins(int bus_id); |
55 | 55 | ||
56 | struct omap_hwmod; | ||
57 | int omap_i2c_reset(struct omap_hwmod *oh); | ||
58 | |||
56 | #endif /* __ASM__ARCH_OMAP_I2C_H */ | 59 | #endif /* __ASM__ARCH_OMAP_I2C_H */ |
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index ce06ac6a9709..fafdfe3c8d4e 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h | |||
@@ -566,6 +566,7 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh); | |||
566 | 566 | ||
567 | void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs); | 567 | void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs); |
568 | u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs); | 568 | u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs); |
569 | int omap_hwmod_softreset(struct omap_hwmod *oh); | ||
569 | 570 | ||
570 | int omap_hwmod_count_resources(struct omap_hwmod *oh); | 571 | int omap_hwmod_count_resources(struct omap_hwmod *oh); |
571 | int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res); | 572 | int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res); |