OMAP2/3: hwmod: fix the i2c-reset timeout during bootup
Subsystems (5)
PATCH v4 1/1 OMAP2/3: 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.
---
The patch is based on
* git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
* master branch.
* 693d92a commit. (Linux 2.6.39-rc7)
Changes from previous versions:
from v1:
- moved i2c specific things from hwmod files to i2c files.
- fixed comments from Paul.
- http://www.spinics.net/lists/linux-omap/msg49483.html
from v2:
- Avoided direct SYSCONFIG access in i2c.c
- http://www.spinics.net/lists/linux-omap/msg49632.html
from v3:
- Addressed comments from Paul Walmsley.
- http://www.spinics.net/lists/arm-kernel/msg124120.html
Testing:
* build tested omap2plus_defconfig for warnings and errors. none introduced.
* boot tested on 2430.
* tested for 'core off' in suspend resume on 3430 sdp. core off counters increment after suspend resume.
Dependency:
* This needs "OMAP2+: hwmod data: Set hwmod flags to only allow 16-bit accesses to i2c" from Andry Green for accessing i2c_sysc. Without this even with this patch, we will see i2c reset timeouts.
arch/arm/mach-omap2/i2c.c | 54 ++++++++++++++++++++++++++ arch/arm/mach-omap2/omap_hwmod.c | 27 +++++++++++++ arch/arm/mach-omap2/omap_hwmod_2420_data.c | 1 + arch/arm/mach-omap2/omap_hwmod_2430_data.c | 1 + arch/arm/mach-omap2/omap_hwmod_3xxx_data.c | 1 + arch/arm/plat-omap/include/plat/i2c.h | 4 ++ arch/arm/plat-omap/include/plat/omap_hwmod.h | 1 + 7 files changed, 89 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/i2c.c +54 -0
@@ -21,9 +21,16 @@#include <plat/cpu.h> #include <plat/i2c.h> +#include <plat/common.h> #include "mux.h" +/* In register I2C_CON, Bit 15 is the I2C enable bit */ +#define I2C_EN BIT(15) +#define I2C_CON_OFFSET 0x24 +/* 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 +44,50 @@ 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; +int c =0 ; + +/* Disable I2C */ + v =omap_hwmod_read (oh,I2C_CON_OFFSET ); + v = v & ~I2C_EN ; +omap_hwmod_write (v, oh,I2C_CON_OFFSET ); + +/* Write to the SOFTRESET bit */ +omap_hwmod_softreset (oh); + +/* Enable I2C */ + v =omap_hwmod_read (oh,I2C_CON_OFFSET ); + v |=I2C_EN ; +omap_hwmod_write (v, oh,I2C_CON_OFFSET ); + +/* 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 ; +}
arch/arm/mach-omap2/omap_hwmod.c +27 -0
@@ -1562,6 +1562,33 @@ void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 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 * * @idlemode: SIDLEMODE field bits (shifted to bit 0)
arch/arm/mach-omap2/omap_hwmod_2420_data.c +1 -0
@@ -1447,6 +1447,7 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {static struct omap_hwmod_class i2c_class = { .name ="i2c" , .sysc = &i2c_sysc, + .reset = &omap_i2c_reset, };static struct omap_i2c_dev_attr i2c_dev_attr;
arch/arm/mach-omap2/omap_hwmod_2430_data.c +1 -0
@@ -1524,6 +1524,7 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {static struct omap_hwmod_class i2c_class = { .name ="i2c" , .sysc = &i2c_sysc, + .reset = &omap_i2c_reset, };static struct omap_i2c_dev_attr i2c_dev_attr = {
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +1 -0
@@ -1460,6 +1460,7 @@ static struct omap_hwmod omap3xxx_uart4_hwmod = {static struct omap_hwmod_class i2c_class = { .name ="i2c" , .sysc = &i2c_sysc, + .reset = &omap_i2c_reset, };/*
arch/arm/plat-omap/include/plat/i2c.h +4 -0
@@ -23,6 +23,8 @@#include <linux/i2c.h> +#include <plat/omap_hwmod.h> +#if defined(CONFIG_I2C_OMAP ) || defined(CONFIG_I2C_OMAP_MODULE ) extern int omap_register_i2c_bus(int bus_id, u32 clkrate, struct i2c_board_info const *info,
@@ -52,4 +54,6 @@ struct omap_i2c_dev_attr {void __init omap1_i2c_mux_pins (int bus_id);void __init omap2_i2c_mux_pins (int bus_id); +int omap_i2c_reset (struct omap_hwmod *oh); +#endif /* __ASM__ARCH_OMAP_I2C_H */
arch/arm/plat-omap/include/plat/omap_hwmod.h +1 -0
@@ -572,6 +572,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);
Signature · 1 line
1.7.1
PATCH v4 1/1 OMAP2/3: hwmod: fix the i2c-reset timeout during bootup
Quoted 17 lines · Avinash.H.M
The sequence of
_ocp_softresetdoesn'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 thei2c_classis updated with the correct 'reset' pointer.omap_hwmod_softresetfunction 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 <[email protected]>Cc Paul Walmsley <[email protected]>Cc Benoit Cousson <[email protected]>Cc Kevin Hilman <[email protected]>Signed-off-by Avinash.H.M <[email protected]>---
<snip>
Quoted 14 lines
arch/arm/plat-omap/include/plat/i2c.h +2
-0@@ -23,6 +23,8 @@#include <linux/i2c.h> +#include <plat/omap_hwmod.h> +#if defined(CONFIG_I2C_OMAP ) || defined(CONFIG_I2C_OMAP_MODULE ) extern int omap_register_i2c_bus(int bus_id, u32 clkrate, struct i2c_board_info const *info,
arch/arm/plat-omap/include/plat/i2c.h struct omap_i2c_dev_attr { · line 58
Quoted 5 lines
arch/arm/plat-omap/include/plat/i2c.h +2
-0@@ -52,4 +54,6 @@ struct omap_i2c_dev_attr {void __init omap1_i2c_mux_pins (int bus_id);void __init omap2_i2c_mux_pins (int bus_id); +int omap_i2c_reset (struct omap_hwmod *oh); +
It's not necessary to include omap_hwmod.h, just declare
struct omap_hwmod;
Tomi
PATCH v4 1/1 OMAP2/3: hwmod: fix the i2c-reset timeout during bootup
Quoted 38 lines · Tomi Valkeinen
Quoted 17 lines · Avinash.H.M
The sequence of
_ocp_softresetdoesn'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 thei2c_classis updated with the correct 'reset' pointer.omap_hwmod_softresetfunction 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 <[email protected]>Cc Paul Walmsley <[email protected]>Cc Benoit Cousson <[email protected]>Cc Kevin Hilman <[email protected]>Signed-off-by Avinash.H.M <[email protected]>---
<snip>
Quoted 17 lines
arch/arm/plat-omap/include/plat/i2c.h +2
-0@@ -23,6 +23,8 @@#include <linux/i2c.h> +#include <plat/omap_hwmod.h> +#if defined(CONFIG_I2C_OMAP ) || defined(CONFIG_I2C_OMAP_MODULE ) extern int omap_register_i2c_bus(int bus_id, u32 clkrate, struct i2c_board_info const *info,@@ -52,4 +54,6 @@ struct omap_i2c_dev_attr {void __init omap1_i2c_mux_pins (int bus_id);void __init omap2_i2c_mux_pins (int bus_id);
Quoted 6 lines
arch/arm/plat-omap/include/plat/i2c.h struct omap_i2c_dev_attr { · line 58
Quoted 2 lines
arch/arm/plat-omap/include/plat/i2c.h +2
-0+int omap_i2c_reset (struct omap_hwmod *oh); +It's not necessary to include
omap_hwmod.h, just declarestruct
omap_hwmod;
Hi Tomi ,
I agree to the comment, since it is a header file (i2c.h), no need to include hwmod.h.
I ll drop the file inclusion. Thanks for reviewing.
B R ,
- Avinash
Quoted 4 lines
Tomi
PATCH v4 1/1 OMAP2/3: hwmod: fix the i2c-reset timeout during bootup
In reply to Avinash.H.MQuoted 11 lines · Avinash.H.M
The sequence of
_ocp_softresetdoesn'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 thei2c_classis updated with the correct 'reset' pointer.omap_hwmod_softresetfunction is implemented which triggers the softreset by writing into sysconfig register. On following this sequence, i2c module resets properly and timeouts are not seen.
Quoted 6 lines
Cc Rajendra Nayak <[email protected]>Cc Paul Walmsley <[email protected]>Cc Benoit Cousson <[email protected]>Cc Kevin Hilman <[email protected]>Signed-off-by Avinash.H.M <[email protected]>---
Hi Kevin, Paul ,
Ping .. could you please review this.
thanks ,
- Avinash
PATCH v4 1/1 OMAP2/3: hwmod: fix the i2c-reset timeout during bootup
Quoted 19 lines · Avinash.H.M.
Quoted 11 lines · Avinash.H.M
The sequence of
_ocp_softresetdoesn'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 thei2c_classis updated with the correct 'reset' pointer.omap_hwmod_softresetfunction is implemented which triggers the softreset by writing into sysconfig register. On following this sequence, i2c module resets properly and timeouts are not seen.Quoted 6 lines
Cc Rajendra Nayak <[email protected]>Cc Paul Walmsley <[email protected]>Cc Benoit Cousson <[email protected]>Cc Kevin Hilman <[email protected]>Signed-off-by Avinash.H.M <[email protected]>---
Quoted 3 lines
Hi Kevin, Paul ,
Ping .. could you please review this.
Hi Paul ,
I recently observed that the sequence we are following to reset i2c in omap2, 3 is also applicable for omap4. On checking the the omap4 TRM sequence , i confirmed this.
The reason why there were no timeouts seen in omap4 was, because of the 'HWMOD_INIT_NO_RESET' flag in the omap4 i2c hwmods. Because of these flags, hwmod wasn't really attempting to reset i2c in omap4 and hence no timeouts were seen.
I ll extend the patch to omap4 and send out new patch, also fixing comments from Tomi. I ll send out v5 and you can review directly v5.
thanks ,
- Avinash
Quoted 5 lines
thanks ,
- Avinash