Merge branch 'fixes-v3.2-rc2' into fixes
[pandora-kernel.git] / arch / arm / mach-omap2 / cpuidle34xx.c
index 2e0fa5a..942bb4f 100644 (file)
@@ -89,17 +89,21 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
 /**
  * omap3_enter_idle - Programs OMAP3 to enter the specified state
  * @dev: cpuidle device
- * @state: The target state to be programmed
+ * @drv: cpuidle driver
+ * @index: the index of state to be entered
  *
  * Called from the CPUidle framework to program the device to the
  * specified target state selected by the governor.
  */
 static int omap3_enter_idle(struct cpuidle_device *dev,
-                       struct cpuidle_state *state)
+                               struct cpuidle_driver *drv,
+                               int index)
 {
-       struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
+       struct omap3_idle_statedata *cx =
+                       cpuidle_get_statedata(&dev->states_usage[index]);
        struct timespec ts_preidle, ts_postidle, ts_idle;
        u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+       int idle_time;
 
        /* Used to keep track of the total time in idle */
        getnstimeofday(&ts_preidle);
@@ -114,7 +118,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
                goto return_sleep_time;
 
        /* Deny idle for C1 */
-       if (state == &dev->states[0]) {
+       if (index == 0) {
                pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
                pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
        }
@@ -123,7 +127,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
        omap_sram_idle();
 
        /* Re-allow idle for C1 */
-       if (state == &dev->states[0]) {
+       if (index == 0) {
                pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
                pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
        }
@@ -135,28 +139,38 @@ return_sleep_time:
        local_irq_enable();
        local_fiq_enable();
 
-       return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
+       idle_time = ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * \
+                                                               USEC_PER_SEC;
+
+       /* Update cpuidle counters */
+       dev->last_residency = idle_time;
+
+       return index;
 }
 
 /**
  * next_valid_state - Find next valid C-state
  * @dev: cpuidle device
- * @state: Currently selected C-state
+ * @drv: cpuidle driver
+ * @index: Index of currently selected c-state
  *
- * If the current state is valid, it is returned back to the caller.
- * Else, this function searches for a lower c-state which is still
- * valid.
+ * If the state corresponding to index is valid, index is returned back
+ * to the caller. Else, this function searches for a lower c-state which is
+ * still valid (as defined in omap3_power_states[]) and returns its index.
  *
  * A state is valid if the 'valid' field is enabled and
  * if it satisfies the enable_off_mode condition.
  */
-static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
-                                             struct cpuidle_state *curr)
+static int next_valid_state(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv,
+                               int index)
 {
-       struct cpuidle_state *next = NULL;
-       struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
+       struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
+       struct cpuidle_state *curr = &drv->states[index];
+       struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
        u32 mpu_deepest_state = PWRDM_POWER_RET;
        u32 core_deepest_state = PWRDM_POWER_RET;
+       int next_index = -1;
 
        if (enable_off_mode) {
                mpu_deepest_state = PWRDM_POWER_OFF;
@@ -173,20 +187,20 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
        if ((cx->valid) &&
            (cx->mpu_state >= mpu_deepest_state) &&
            (cx->core_state >= core_deepest_state)) {
-               return curr;
+               return index;
        } else {
                int idx = OMAP3_NUM_STATES - 1;
 
                /* Reach the current state starting at highest C-state */
                for (; idx >= 0; idx--) {
-                       if (&dev->states[idx] == curr) {
-                               next = &dev->states[idx];
+                       if (&drv->states[idx] == curr) {
+                               next_index = idx;
                                break;
                        }
                }
 
                /* Should never hit this condition */
-               WARN_ON(next == NULL);
+               WARN_ON(next_index == -1);
 
                /*
                 * Drop to next valid state.
@@ -194,41 +208,44 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
                 */
                idx--;
                for (; idx >= 0; idx--) {
-                       cx = cpuidle_get_statedata(&dev->states[idx]);
+                       cx = cpuidle_get_statedata(&dev->states_usage[idx]);
                        if ((cx->valid) &&
                            (cx->mpu_state >= mpu_deepest_state) &&
                            (cx->core_state >= core_deepest_state)) {
-                               next = &dev->states[idx];
+                               next_index = idx;
                                break;
                        }
                }
                /*
                 * C1 is always valid.
-                * So, no need to check for 'next==NULL' outside this loop.
+                * So, no need to check for 'next_index == -1' outside
+                * this loop.
                 */
        }
 
-       return next;
+       return next_index;
 }
 
 /**
  * omap3_enter_idle_bm - Checks for any bus activity
  * @dev: cpuidle device
- * @state: The target state to be programmed
+ * @drv: cpuidle driver
+ * @index: array index of target state to be programmed
  *
  * This function checks for any pending activity and then programs
  * the device to the specified or a safer state.
  */
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
-                              struct cpuidle_state *state)
+                               struct cpuidle_driver *drv,
+                              int index)
 {
-       struct cpuidle_state *new_state;
+       int new_state_idx;
        u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
        struct omap3_idle_statedata *cx;
        int ret;
 
        if (!omap3_can_sleep()) {
-               new_state = dev->safe_state;
+               new_state_idx = drv->safe_state_index;
                goto select_state;
        }
 
@@ -238,7 +255,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
         */
        cam_state = pwrdm_read_pwrst(cam_pd);
        if (cam_state == PWRDM_POWER_ON) {
-               new_state = dev->safe_state;
+               new_state_idx = drv->safe_state_index;
                goto select_state;
        }
 
@@ -254,7 +271,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
         * Prevent PER off if CORE is not in retention or off as this
         * would disable PER wakeups completely.
         */
-       cx = cpuidle_get_statedata(state);
+       cx = cpuidle_get_statedata(&dev->states_usage[index]);
        core_next_state = cx->core_state;
        per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
        if ((per_next_state == PWRDM_POWER_OFF) &&
@@ -265,11 +282,10 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
        if (per_next_state != per_saved_state)
                pwrdm_set_next_pwrst(per_pd, per_next_state);
 
-       new_state = next_valid_state(dev, state);
+       new_state_idx = next_valid_state(dev, drv, index);
 
 select_state:
-       dev->last_state = new_state;
-       ret = omap3_enter_idle(dev, new_state);
+       ret = omap3_enter_idle(dev, drv, new_state_idx);
 
        /* Restore original PER state if it was modified */
        if (per_next_state != per_saved_state)
@@ -302,22 +318,31 @@ struct cpuidle_driver omap3_idle_driver = {
        .owner =        THIS_MODULE,
 };
 
-/* Helper to fill the C-state common data and register the driver_data */
-static inline struct omap3_idle_statedata *_fill_cstate(
-                                       struct cpuidle_device *dev,
+/* Helper to fill the C-state common data*/
+static inline void _fill_cstate(struct cpuidle_driver *drv,
                                        int idx, const char *descr)
 {
-       struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
-       struct cpuidle_state *state = &dev->states[idx];
+       struct cpuidle_state *state = &drv->states[idx];
 
        state->exit_latency     = cpuidle_params_table[idx].exit_latency;
        state->target_residency = cpuidle_params_table[idx].target_residency;
        state->flags            = CPUIDLE_FLAG_TIME_VALID;
        state->enter            = omap3_enter_idle_bm;
-       cx->valid               = cpuidle_params_table[idx].valid;
        sprintf(state->name, "C%d", idx + 1);
        strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
-       cpuidle_set_statedata(state, cx);
+
+}
+
+/* Helper to register the driver_data */
+static inline struct omap3_idle_statedata *_fill_cstate_usage(
+                                       struct cpuidle_device *dev,
+                                       int idx)
+{
+       struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
+       struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
+
+       cx->valid               = cpuidle_params_table[idx].valid;
+       cpuidle_set_statedata(state_usage, cx);
 
        return cx;
 }
@@ -331,6 +356,7 @@ static inline struct omap3_idle_statedata *_fill_cstate(
 int __init omap3_idle_init(void)
 {
        struct cpuidle_device *dev;
+       struct cpuidle_driver *drv = &omap3_idle_driver;
        struct omap3_idle_statedata *cx;
 
        mpu_pd = pwrdm_lookup("mpu_pwrdm");
@@ -338,44 +364,52 @@ int __init omap3_idle_init(void)
        per_pd = pwrdm_lookup("per_pwrdm");
        cam_pd = pwrdm_lookup("cam_pwrdm");
 
-       cpuidle_register_driver(&omap3_idle_driver);
+
+       drv->safe_state_index = -1;
        dev = &per_cpu(omap3_idle_dev, smp_processor_id());
 
        /* C1 . MPU WFI + Core active */
-       cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
-       (&dev->states[0])->enter = omap3_enter_idle;
-       dev->safe_state = &dev->states[0];
+       _fill_cstate(drv, 0, "MPU ON + CORE ON");
+       (&drv->states[0])->enter = omap3_enter_idle;
+       drv->safe_state_index = 0;
+       cx = _fill_cstate_usage(dev, 0);
        cx->valid = 1;  /* C1 is always valid */
        cx->mpu_state = PWRDM_POWER_ON;
        cx->core_state = PWRDM_POWER_ON;
 
        /* C2 . MPU WFI + Core inactive */
-       cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
+       _fill_cstate(drv, 1, "MPU ON + CORE ON");
+       cx = _fill_cstate_usage(dev, 1);
        cx->mpu_state = PWRDM_POWER_ON;
        cx->core_state = PWRDM_POWER_ON;
 
        /* C3 . MPU CSWR + Core inactive */
-       cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
+       _fill_cstate(drv, 2, "MPU RET + CORE ON");
+       cx = _fill_cstate_usage(dev, 2);
        cx->mpu_state = PWRDM_POWER_RET;
        cx->core_state = PWRDM_POWER_ON;
 
        /* C4 . MPU OFF + Core inactive */
-       cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
+       _fill_cstate(drv, 3, "MPU OFF + CORE ON");
+       cx = _fill_cstate_usage(dev, 3);
        cx->mpu_state = PWRDM_POWER_OFF;
        cx->core_state = PWRDM_POWER_ON;
 
        /* C5 . MPU RET + Core RET */
-       cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
+       _fill_cstate(drv, 4, "MPU RET + CORE RET");
+       cx = _fill_cstate_usage(dev, 4);
        cx->mpu_state = PWRDM_POWER_RET;
        cx->core_state = PWRDM_POWER_RET;
 
        /* C6 . MPU OFF + Core RET */
-       cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
+       _fill_cstate(drv, 5, "MPU OFF + CORE RET");
+       cx = _fill_cstate_usage(dev, 5);
        cx->mpu_state = PWRDM_POWER_OFF;
        cx->core_state = PWRDM_POWER_RET;
 
        /* C7 . MPU OFF + Core OFF */
-       cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
+       _fill_cstate(drv, 6, "MPU OFF + CORE OFF");
+       cx = _fill_cstate_usage(dev, 6);
        /*
         * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
         * enable OFF mode in a stable form for previous revisions.
@@ -389,6 +423,9 @@ int __init omap3_idle_init(void)
        cx->mpu_state = PWRDM_POWER_OFF;
        cx->core_state = PWRDM_POWER_OFF;
 
+       drv->state_count = OMAP3_NUM_STATES;
+       cpuidle_register_driver(&omap3_idle_driver);
+
        dev->state_count = OMAP3_NUM_STATES;
        if (cpuidle_register_device(dev)) {
                printk(KERN_ERR "%s: CPUidle register device failed\n",