Path: blob/master/arch/sh/kernel/cpu/shmobile/cpuidle.c
17447 views
/*1* arch/sh/kernel/cpu/shmobile/cpuidle.c2*3* Cpuidle support code for SuperH Mobile4*5* Copyright (C) 2009 Magnus Damm6*7* This file is subject to the terms and conditions of the GNU General Public8* License. See the file "COPYING" in the main directory of this archive9* for more details.10*/11#include <linux/init.h>12#include <linux/kernel.h>13#include <linux/io.h>14#include <linux/suspend.h>15#include <linux/cpuidle.h>16#include <asm/suspend.h>17#include <asm/uaccess.h>18#include <asm/hwblk.h>1920static unsigned long cpuidle_mode[] = {21SUSP_SH_SLEEP, /* regular sleep mode */22SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */23SUSP_SH_STANDBY | SUSP_SH_SF, /* software standby mode + self refresh */24};2526static int cpuidle_sleep_enter(struct cpuidle_device *dev,27struct cpuidle_state *state)28{29unsigned long allowed_mode = arch_hwblk_sleep_mode();30ktime_t before, after;31int requested_state = state - &dev->states[0];32int allowed_state;33int k;3435/* convert allowed mode to allowed state */36for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--)37if (cpuidle_mode[k] == allowed_mode)38break;3940allowed_state = k;4142/* take the following into account for sleep mode selection:43* - allowed_state: best mode allowed by hardware (clock deps)44* - requested_state: best mode allowed by software (latencies)45*/46k = min_t(int, allowed_state, requested_state);4748dev->last_state = &dev->states[k];49before = ktime_get();50sh_mobile_call_standby(cpuidle_mode[k]);51after = ktime_get();52return ktime_to_ns(ktime_sub(after, before)) >> 10;53}5455static struct cpuidle_device cpuidle_dev;56static struct cpuidle_driver cpuidle_driver = {57.name = "sh_idle",58.owner = THIS_MODULE,59};6061void sh_mobile_setup_cpuidle(void)62{63struct cpuidle_device *dev = &cpuidle_dev;64struct cpuidle_state *state;65int i;6667cpuidle_register_driver(&cpuidle_driver);6869for (i = 0; i < CPUIDLE_STATE_MAX; i++) {70dev->states[i].name[0] = '\0';71dev->states[i].desc[0] = '\0';72}7374i = CPUIDLE_DRIVER_STATE_START;7576state = &dev->states[i++];77snprintf(state->name, CPUIDLE_NAME_LEN, "C1");78strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN);79state->exit_latency = 1;80state->target_residency = 1 * 2;81state->power_usage = 3;82state->flags = 0;83state->flags |= CPUIDLE_FLAG_TIME_VALID;84state->enter = cpuidle_sleep_enter;8586dev->safe_state = state;8788if (sh_mobile_sleep_supported & SUSP_SH_SF) {89state = &dev->states[i++];90snprintf(state->name, CPUIDLE_NAME_LEN, "C2");91strncpy(state->desc, "SuperH Sleep Mode [SF]",92CPUIDLE_DESC_LEN);93state->exit_latency = 100;94state->target_residency = 1 * 2;95state->power_usage = 1;96state->flags = 0;97state->flags |= CPUIDLE_FLAG_TIME_VALID;98state->enter = cpuidle_sleep_enter;99}100101if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {102state = &dev->states[i++];103snprintf(state->name, CPUIDLE_NAME_LEN, "C3");104strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",105CPUIDLE_DESC_LEN);106state->exit_latency = 2300;107state->target_residency = 1 * 2;108state->power_usage = 1;109state->flags = 0;110state->flags |= CPUIDLE_FLAG_TIME_VALID;111state->enter = cpuidle_sleep_enter;112}113114dev->state_count = i;115116cpuidle_register_device(dev);117}118119120