Merge branch 'stable/bug-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.git] / arch / arm / mach-omap2 / omap_hwmod.c
index 91b011e..e282e35 100644 (file)
  * - Open Core Protocol Specification 2.2
  *
  * To do:
- * - pin mux handling
  * - handle IO mapping
  * - bus throughput & module latency measurement code
  *
 #include "cm44xx.h"
 #include "prm2xxx_3xxx.h"
 #include "prm44xx.h"
+#include "mux.h"
 
 /* Maximum microseconds to wait for OMAP module to softreset */
 #define MAX_MODULE_SOFTRESET_WAIT      10000
@@ -393,7 +393,8 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
        u32 wakeup_mask;
 
        if (!oh->class->sysc ||
-           !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
+           !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
+             (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)))
                return -EINVAL;
 
        if (!oh->class->sysc->sysc_fields) {
@@ -405,6 +406,9 @@ static int _enable_wakeup(struct omap_hwmod *oh, u32 *v)
 
        *v |= wakeup_mask;
 
+       if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
+               _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART_WKUP, v);
+
        /* XXX test pwrdm_get_wken for this hwmod's subsystem */
 
        oh->_int_flags |= _HWMOD_WAKEUP_ENABLED;
@@ -424,7 +428,8 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
        u32 wakeup_mask;
 
        if (!oh->class->sysc ||
-           !(oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP))
+           !((oh->class->sysc->sysc_flags & SYSC_HAS_ENAWAKEUP) ||
+             (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)))
                return -EINVAL;
 
        if (!oh->class->sysc->sysc_fields) {
@@ -436,6 +441,9 @@ static int _disable_wakeup(struct omap_hwmod *oh, u32 *v)
 
        *v &= ~wakeup_mask;
 
+       if (oh->class->sysc->idlemodes & SIDLE_SMART_WKUP)
+               _set_slave_idlemode(oh, HWMOD_IDLEMODE_SMART, v);
+
        /* XXX test pwrdm_get_wken for this hwmod's subsystem */
 
        oh->_int_flags &= ~_HWMOD_WAKEUP_ENABLED;
@@ -832,6 +840,10 @@ static void _idle_sysc(struct omap_hwmod *oh)
                _set_master_standbymode(oh, idlemode, &v);
        }
 
+       /* If slave is in SMARTIDLE, also enable wakeup */
+       if ((sf & SYSC_HAS_SIDLEMODE) && !(oh->flags & HWMOD_SWSUP_SIDLE))
+               _enable_wakeup(oh, &v);
+
        _write_sysconfig(v, oh);
 }
 
@@ -1217,7 +1229,9 @@ static int _enable(struct omap_hwmod *oh)
             oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
                _deassert_hardreset(oh, oh->rst_lines[0].name);
 
-       /* XXX mux balls */
+       /* Mux pins for device runtime if populated */
+       if (oh->mux)
+               omap_hwmod_mux(oh->mux, _HWMOD_STATE_ENABLED);
 
        _add_initiator_dep(oh, mpu_oh);
        _enable_clocks(oh);
@@ -1233,6 +1247,7 @@ static int _enable(struct omap_hwmod *oh)
                        _enable_sysc(oh);
                }
        } else {
+               _disable_clocks(oh);
                pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n",
                         oh->name, r);
        }
@@ -1263,6 +1278,10 @@ static int _idle(struct omap_hwmod *oh)
        _del_initiator_dep(oh, mpu_oh);
        _disable_clocks(oh);
 
+       /* Mux pins for device idle if populated */
+       if (oh->mux)
+               omap_hwmod_mux(oh->mux, _HWMOD_STATE_IDLE);
+
        oh->_state = _HWMOD_STATE_IDLE;
 
        return 0;
@@ -1321,7 +1340,9 @@ static int _shutdown(struct omap_hwmod *oh)
        }
        /* XXX Should this code also force-disable the optional clocks? */
 
-       /* XXX mux any associated balls to safe mode */
+       /* Mux pins to safe mode or use populated off mode values */
+       if (oh->mux)
+               omap_hwmod_mux(oh->mux, _HWMOD_STATE_DISABLED);
 
        oh->_state = _HWMOD_STATE_DISABLED;
 
@@ -2175,3 +2196,25 @@ ohsps_unlock:
 
        return ret;
 }
+
+/**
+ * omap_hwmod_get_context_loss_count - get lost context count
+ * @oh: struct omap_hwmod *
+ *
+ * Query the powerdomain of of @oh to get the context loss
+ * count for this device.
+ *
+ * Returns the context loss count of the powerdomain assocated with @oh
+ * upon success, or zero if no powerdomain exists for @oh.
+ */
+u32 omap_hwmod_get_context_loss_count(struct omap_hwmod *oh)
+{
+       struct powerdomain *pwrdm;
+       int ret = 0;
+
+       pwrdm = omap_hwmod_get_pwrdm(oh);
+       if (pwrdm)
+               ret = pwrdm_get_context_loss_count(pwrdm);
+
+       return ret;
+}