aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorKevin Hilman <khilman@deeprootsystems.com>2010-12-21 23:08:34 -0500
committerPaul Walmsley <paul@pwsan.com>2010-12-21 23:08:34 -0500
commit5a7ddcbdaf1bb7603422fb6188156ccc39711b0f (patch)
tree6bac2de38f18fad4a6adbb3e12ed8b8dc9cd7789 /arch/arm/mach-omap2/omap_hwmod.c
parentb399bca897802db3f342b6f3032a19ab8f2af99b (diff)
OMAP2+: omap_hwmod: fix wakeup enable/disable for consistency
In the omap_hwmod core, most of the SYSCONFIG register helper functions do not directly write the register, but instead just modify a value passed in. This patch converts the _enable_wakeup() and _disable_wakeup() helper functions to take a value argument and only modify it instead of actually writing the register. This makes the wakeup helpers consistent with the other helper functions and avoids unintentional problems like the following. This problem was found after discovering that GPIO wakeups were no longer functional. The root cause was that the ENAWAKEUP bit of the SYSCONFIG register was being unintentionaly overwritten, leaving wakeups disabled after the following two commits were combined: commit: 9980ce53c97392a3dbdc9d1ac3e455d79b4167ed OMAP: hwmod: Enable module wakeup if in smartidle commit: 78f26e872f77b6312273216de1a8f836c6f2e143 OMAP: hwmod: Set autoidle after smartidle during _sysc_enable There resulting in code in _enable_sysc() was this: /* * XXX The clock framework should handle this, by * calling into this code. But this must wait until the * clock structures are tagged with omap_hwmod entries */ if ((oh->flags & HWMOD_SET_DEFAULT_CLOCKACT) && (sf & SYSC_HAS_CLOCKACTIVITY)) _set_clockactivity(oh, oh->class->sysc->clockact, &v); _write_sysconfig(v, oh); so here, 'v' has wakeups disabled. /* If slave is in SMARTIDLE, also enable wakeup */ if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE)) _enable_wakeup(oh); Here wakeup is enabled in the SYSCONFIG register (but 'v' is not updated) /* * Set the autoidle bit only after setting the smartidle bit * Setting this will not have any impact on the other modules. */ if (sf & SYSC_HAS_AUTOIDLE) { idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ? 0 : 1; _set_module_autoidle(oh, idlemode, &v); _write_sysconfig(v, oh); } And here, SYSCONFIG is updated again using 'v', which does not have wakeups enabled, resulting in ENAWAKEUP being cleared. Special thanks to Benoit Cousson for pointing out that wakeups were supposed to be automatically enabled when a hwmod is enabled, and thus helping target the root cause of this problem. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Benoit Cousson <b-cousson@ti.com> Signed-off-by: Benoit Cousson <b-cousson@ti.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c32
1 files changed, 17 insertions, 15 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 12856eb7b179..81c109774b31 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -390,9 +390,9 @@ static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle,
390 * Allow the hardware module @oh to send wakeups. Returns -EINVAL 390 * Allow the hardware module @oh to send wakeups. Returns -EINVAL
391 * upon error or 0 upon success. 391 * upon error or 0 upon success.
392 */ 392 */
393static int _enable_wakeup(struct omap_hwmod *oh) 393static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
394{ 394{
395 u32 v, wakeup_mask; 395 u32 wakeup_mask;
396 396
397 if (!oh->class->sysc || 397 if (!oh->class->sysc ||
398 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) 398 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
@@ -405,9 +405,7 @@ static int _enable_wakeup(struct omap_hwmod *oh)
405 405
406 wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); 406 wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
407 407
408 v = oh->_sysc_cache; 408 *v |= wakeup_mask;
409 v |= wakeup_mask;
410 _write_sysconfig(v, oh);
411 409
412 /* XXX test pwrdm_get_wken for this hwmod's subsystem */ 410 /* XXX test pwrdm_get_wken for this hwmod's subsystem */
413 411
@@ -423,9 +421,9 @@ static int _enable_wakeup(struct omap_hwmod *oh)
423 * Prevent the hardware module @oh to send wakeups. Returns -EINVAL 421 * Prevent the hardware module @oh to send wakeups. Returns -EINVAL
424 * upon error or 0 upon success. 422 * upon error or 0 upon success.
425 */ 423 */
426static int _disable_wakeup(struct omap_hwmod *oh) 424static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
427{ 425{
428 u32 v, wakeup_mask; 426 u32 wakeup_mask;
429 427
430 if (!oh->class->sysc || 428 if (!oh->class->sysc ||
431 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) 429 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
@@ -438,9 +436,7 @@ static int _disable_wakeup(struct omap_hwmod *oh)
438 436
439 wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift); 437 wakeup_mask = (0x1 << oh->class->sysc->sysc_fields->enwkup_shift);
440 438
441 v = oh->_sysc_cache; 439 *v &= ~wakeup_mask;
442 v &= ~wakeup_mask;
443 _write_sysconfig(v, oh);
444 440
445 /* XXX test pwrdm_get_wken for this hwmod's subsystem */ 441 /* XXX test pwrdm_get_wken for this hwmod's subsystem */
446 442
@@ -788,11 +784,11 @@ static void _enable_sysc(struct omap_hwmod *oh)
788 (sf & SYSC_HAS_CLOCKACTIVITY)) 784 (sf & SYSC_HAS_CLOCKACTIVITY))
789 _set_clockactivity(oh, oh->class->sysc->clockact, &v); 785 _set_clockactivity(oh, oh->class->sysc->clockact, &v);
790 786
791 _write_sysconfig(v, oh);
792
793 /* If slave is in SMARTIDLE, also enable wakeup */ 787 /* If slave is in SMARTIDLE, also enable wakeup */
794 if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE)) 788 if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE))
795 _enable_wakeup(oh); 789 _enable_wakeup(oh, &v);
790
791 _write_sysconfig(v, oh);
796 792
797 /* 793 /*
798 * Set the autoidle bit only after setting the smartidle bit 794 * Set the autoidle bit only after setting the smartidle bit
@@ -2011,13 +2007,16 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh,
2011int omap_hwmod_enable_wakeup(struct omap_hwmod *oh) 2007int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
2012{ 2008{
2013 unsigned long flags; 2009 unsigned long flags;
2010 u32 v;
2014 2011
2015 if (!oh->class->sysc || 2012 if (!oh->class->sysc ||
2016 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) 2013 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
2017 return -EINVAL; 2014 return -EINVAL;
2018 2015
2019 spin_lock_irqsave(&oh->_lock, flags); 2016 spin_lock_irqsave(&oh->_lock, flags);
2020 _enable_wakeup(oh); 2017 v = oh->_sysc_cache;
2018 _enable_wakeup(oh, &v);
2019 _write_sysconfig(v, oh);
2021 spin_unlock_irqrestore(&oh->_lock, flags); 2020 spin_unlock_irqrestore(&oh->_lock, flags);
2022 2021
2023 return 0; 2022 return 0;
@@ -2038,13 +2037,16 @@ int omap_hwmod_enable_wakeup(struct omap_hwmod *oh)
2038int omap_hwmod_disable_wakeup(struct omap_hwmod *oh) 2037int omap_hwmod_disable_wakeup(struct omap_hwmod *oh)
2039{ 2038{
2040 unsigned long flags; 2039 unsigned long flags;
2040 u32 v;
2041 2041
2042 if (!oh->class->sysc || 2042 if (!oh->class->sysc ||
2043 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP)) 2043 !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
2044 return -EINVAL; 2044 return -EINVAL;
2045 2045
2046 spin_lock_irqsave(&oh->_lock, flags); 2046 spin_lock_irqsave(&oh->_lock, flags);
2047 _disable_wakeup(oh); 2047 v = oh->_sysc_cache;
2048 _disable_wakeup(oh, &v);
2049 _write_sysconfig(v, oh);
2048 spin_unlock_irqrestore(&oh->_lock, flags); 2050 spin_unlock_irqrestore(&oh->_lock, flags);
2049 2051
2050 return 0; 2052 return 0;