OMAP: hwmod: fix the i2c-reset timeout during bootup
authorAvinash.H.M <avinashhm@ti.com>
Sun, 10 Jul 2011 11:27:16 +0000 (05:27 -0600)
committerPaul Walmsley <paul@pwsan.com>
Sun, 10 Jul 2011 11:27:16 +0000 (05:27 -0600)
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>
arch/arm/mach-omap2/i2c.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod_2420_data.c
arch/arm/mach-omap2/omap_hwmod_2430_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/plat-omap/include/plat/i2c.h
arch/arm/plat-omap/include/plat/omap_hwmod.h

index 79c478c4cb1cc0696b62cb0e23ca53596588d14f..ace99944e96f1b0ac50224cc24a838849fc77d49 100644 (file)
 
 #include <plat/cpu.h>
 #include <plat/i2c.h>
+#include <plat/common.h>
+#include <plat/omap_hwmod.h>
 
 #include "mux.h"
 
+/* In register I2C_CON, Bit 15 is the I2C enable bit */
+#define I2C_EN                                 BIT(15)
+#define OMAP2_I2C_CON_OFFSET                   0x24
+#define OMAP4_I2C_CON_OFFSET                   0xA4
+
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT      10000
+
 void __init omap2_i2c_mux_pins(int bus_id)
 {
        char mux_name[sizeof("i2c2_scl.i2c2_scl")];
@@ -37,3 +47,61 @@ void __init omap2_i2c_mux_pins(int bus_id)
        sprintf(mux_name, "i2c%i_sda.i2c%i_sda", bus_id, bus_id);
        omap_mux_init_signal(mux_name, OMAP_PIN_INPUT);
 }
+
+/**
+ * omap_i2c_reset - reset the omap i2c module.
+ * @oh: struct omap_hwmod *
+ *
+ * The i2c moudle in omap2, omap3 had a special sequence to reset. The
+ * sequence is:
+ * - Disable the I2C.
+ * - Write to SOFTRESET bit.
+ * - Enable the I2C.
+ * - Poll on the RESETDONE bit.
+ * The sequence is implemented in below function. This is called for 2420,
+ * 2430 and omap3.
+ */
+int omap_i2c_reset(struct omap_hwmod *oh)
+{
+       u32 v;
+       u16 i2c_con;
+       int c = 0;
+
+       if (oh->class->rev == OMAP_I2C_IP_VERSION_2) {
+               i2c_con = OMAP4_I2C_CON_OFFSET;
+       } else if (oh->class->rev == OMAP_I2C_IP_VERSION_1) {
+               i2c_con = OMAP2_I2C_CON_OFFSET;
+       } else {
+               WARN(1, "Cannot reset I2C block %s: unsupported revision\n",
+                    oh->name);
+               return -EINVAL;
+       }
+
+       /* Disable I2C */
+       v = omap_hwmod_read(oh, i2c_con);
+       v &= ~I2C_EN;
+       omap_hwmod_write(v, oh, i2c_con);
+
+       /* Write to the SOFTRESET bit */
+       omap_hwmod_softreset(oh);
+
+       /* Enable I2C */
+       v = omap_hwmod_read(oh, i2c_con);
+       v |= I2C_EN;
+       omap_hwmod_write(v, oh, i2c_con);
+
+       /* Poll on RESETDONE bit */
+       omap_test_timeout((omap_hwmod_read(oh,
+                               oh->class->sysc->syss_offs)
+                               & SYSS_RESETDONE_MASK),
+                               MAX_MODULE_SOFTRESET_WAIT, c);
+
+       if (c == MAX_MODULE_SOFTRESET_WAIT)
+               pr_warning("%s: %s: softreset failed (waited %d usec)\n",
+                       __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
+       else
+               pr_debug("%s: %s: softreset in %d usec\n", __func__,
+                       oh->name, c);
+
+       return 0;
+}
index 7d242c9e2a2c7b5db7a2de4c5aedee3169fbb5e6..02b6016393a8ff24cba4e11af5fbac8738068f82 100644 (file)
@@ -1655,6 +1655,33 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs)
                __raw_writel(v, oh->_mpu_rt_va + reg_offs);
 }
 
+/**
+ * omap_hwmod_softreset - reset a module via SYSCONFIG.SOFTRESET bit
+ * @oh: struct omap_hwmod *
+ *
+ * This is a public function exposed to drivers. Some drivers may need to do
+ * some settings before and after resetting the device.  Those drivers after
+ * doing the necessary settings could use this function to start a reset by
+ * setting the SYSCONFIG.SOFTRESET bit.
+ */
+int omap_hwmod_softreset(struct omap_hwmod *oh)
+{
+       u32 v;
+       int ret;
+
+       if (!oh || !(oh->_sysc_cache))
+               return -EINVAL;
+
+       v = oh->_sysc_cache;
+       ret = _set_softreset(oh, &v);
+       if (ret)
+               goto error;
+       _write_sysconfig(v, oh);
+
+error:
+       return ret;
+}
+
 /**
  * omap_hwmod_set_slave_idlemode - set the hwmod's OCP slave idlemode
  * @oh: struct omap_hwmod *
index 7af251448a7e5205242715f94ae7557c21f4e65f..a015c69068f68fc9d86a242fc019cd87e7beb7f3 100644 (file)
@@ -1030,6 +1030,7 @@ static struct omap_hwmod_class i2c_class = {
        .name           = "i2c",
        .sysc           = &i2c_sysc,
        .rev            = OMAP_I2C_IP_VERSION_1,
+       .reset          = &omap_i2c_reset,
 };
 
 static struct omap_i2c_dev_attr i2c_dev_attr = {
index 405688ae265b2298d90faf518d9f244abeb75a5d..16743c7d6e8effe6c1b0089008865543f5798c43 100644 (file)
@@ -1079,6 +1079,7 @@ static struct omap_hwmod_class i2c_class = {
        .name           = "i2c",
        .sysc           = &i2c_sysc,
        .rev            = OMAP_I2C_IP_VERSION_1,
+       .reset          = &omap_i2c_reset,
 };
 
 static struct omap_i2c_dev_attr i2c_dev_attr = {
index c704ac8ca6bbb0f88ea62dee7ca082da6a0878a2..25bf43b5a4ec02922049abd9fd16806297fc1b37 100644 (file)
@@ -1306,9 +1306,10 @@ static struct omap_hwmod omap3xxx_uart4_hwmod = {
 };
 
 static struct omap_hwmod_class i2c_class = {
-       .name = "i2c",
-       .sysc = &i2c_sysc,
-       .rev  = OMAP_I2C_IP_VERSION_1,
+       .name   = "i2c",
+       .sysc   = &i2c_sysc,
+       .rev    = OMAP_I2C_IP_VERSION_1,
+       .reset  = &omap_i2c_reset,
 };
 
 static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
index 55331df4e452120d7c297752d3968f4aa0e8495e..5d5df49749dfe5b69ceccdc71896ecdf4f837940 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <plat/omap_hwmod.h>
 #include <plat/cpu.h>
+#include <plat/i2c.h>
 #include <plat/gpio.h>
 #include <plat/dma.h>
 #include <plat/mcspi.h>
@@ -2162,6 +2163,7 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
        .name   = "i2c",
        .sysc   = &omap44xx_i2c_sysc,
        .rev    = OMAP_I2C_IP_VERSION_2,
+       .reset  = &omap_i2c_reset,
 };
 
 static struct omap_i2c_dev_attr i2c_dev_attr = {
@@ -2207,7 +2209,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c1_slaves[] = {
 static struct omap_hwmod omap44xx_i2c1_hwmod = {
        .name           = "i2c1",
        .class          = &omap44xx_i2c_hwmod_class,
-       .flags          = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET,
+       .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c1_irqs,
        .sdma_reqs      = omap44xx_i2c1_sdma_reqs,
        .main_clk       = "i2c1_fck",
@@ -2261,7 +2263,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c2_slaves[] = {
 static struct omap_hwmod omap44xx_i2c2_hwmod = {
        .name           = "i2c2",
        .class          = &omap44xx_i2c_hwmod_class,
-       .flags          = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET,
+       .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c2_irqs,
        .sdma_reqs      = omap44xx_i2c2_sdma_reqs,
        .main_clk       = "i2c2_fck",
@@ -2315,7 +2317,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c3_slaves[] = {
 static struct omap_hwmod omap44xx_i2c3_hwmod = {
        .name           = "i2c3",
        .class          = &omap44xx_i2c_hwmod_class,
-       .flags          = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET,
+       .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c3_irqs,
        .sdma_reqs      = omap44xx_i2c3_sdma_reqs,
        .main_clk       = "i2c3_fck",
@@ -2369,7 +2371,7 @@ static struct omap_hwmod_ocp_if *omap44xx_i2c4_slaves[] = {
 static struct omap_hwmod omap44xx_i2c4_hwmod = {
        .name           = "i2c4",
        .class          = &omap44xx_i2c_hwmod_class,
-       .flags          = HWMOD_16BIT_REG | HWMOD_INIT_NO_RESET,
+       .flags          = HWMOD_16BIT_REG,
        .mpu_irqs       = omap44xx_i2c4_irqs,
        .sdma_reqs      = omap44xx_i2c4_sdma_reqs,
        .main_clk       = "i2c4_fck",
index fd75dadfa89ca12c09c7aca20ff9551edcd22842..7c22b9e10dc3513c6598934943798ee092858803 100644 (file)
@@ -53,4 +53,7 @@ struct omap_i2c_dev_attr {
 void __init omap1_i2c_mux_pins(int bus_id);
 void __init omap2_i2c_mux_pins(int bus_id);
 
+struct omap_hwmod;
+int omap_i2c_reset(struct omap_hwmod *oh);
+
 #endif /* __ASM__ARCH_OMAP_I2C_H */
index ce06ac6a9709e8ec6fb6e012c4f4f39cc011dc53..fafdfe3c8d4e8e92d3f4a9f610e30d8f38935fa8 100644 (file)
@@ -566,6 +566,7 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh);
 
 void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs);
 u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs);
+int omap_hwmod_softreset(struct omap_hwmod *oh);
 
 int omap_hwmod_count_resources(struct omap_hwmod *oh);
 int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res);