linux/arch/sh/kernel/cpu/shmobile/cpuidle.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * arch/sh/kernel/cpu/shmobile/cpuidle.c
   4 *
   5 * Cpuidle support code for SuperH Mobile
   6 *
   7 *  Copyright (C) 2009 Magnus Damm
   8 */
   9#include <linux/init.h>
  10#include <linux/kernel.h>
  11#include <linux/io.h>
  12#include <linux/suspend.h>
  13#include <linux/cpuidle.h>
  14#include <linux/export.h>
  15#include <asm/suspend.h>
  16#include <linux/uaccess.h>
  17
  18static unsigned long cpuidle_mode[] = {
  19        SUSP_SH_SLEEP, /* regular sleep mode */
  20        SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */
  21        SUSP_SH_STANDBY | SUSP_SH_SF, /* software standby mode + self refresh */
  22};
  23
  24static int cpuidle_sleep_enter(struct cpuidle_device *dev,
  25                                struct cpuidle_driver *drv,
  26                                int index)
  27{
  28        unsigned long allowed_mode = SUSP_SH_SLEEP;
  29        int requested_state = index;
  30        int allowed_state;
  31        int k;
  32
  33        /* convert allowed mode to allowed state */
  34        for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--)
  35                if (cpuidle_mode[k] == allowed_mode)
  36                        break;
  37
  38        allowed_state = k;
  39
  40        /* take the following into account for sleep mode selection:
  41         * - allowed_state: best mode allowed by hardware (clock deps)
  42         * - requested_state: best mode allowed by software (latencies)
  43         */
  44        k = min_t(int, allowed_state, requested_state);
  45
  46        sh_mobile_call_standby(cpuidle_mode[k]);
  47
  48        return k;
  49}
  50
  51static struct cpuidle_driver cpuidle_driver = {
  52        .name   = "sh_idle",
  53        .owner  = THIS_MODULE,
  54        .states = {
  55                {
  56                        .exit_latency = 1,
  57                        .target_residency = 1 * 2,
  58                        .power_usage = 3,
  59                        .enter = cpuidle_sleep_enter,
  60                        .name = "C1",
  61                        .desc = "SuperH Sleep Mode",
  62                },
  63                {
  64                        .exit_latency = 100,
  65                        .target_residency = 1 * 2,
  66                        .power_usage = 1,
  67                        .enter = cpuidle_sleep_enter,
  68                        .name = "C2",
  69                        .desc = "SuperH Sleep Mode [SF]",
  70                        .flags = CPUIDLE_FLAG_UNUSABLE,
  71                },
  72                {
  73                        .exit_latency = 2300,
  74                        .target_residency = 1 * 2,
  75                        .power_usage = 1,
  76                        .enter = cpuidle_sleep_enter,
  77                        .name = "C3",
  78                        .desc = "SuperH Mobile Standby Mode [SF]",
  79                        .flags = CPUIDLE_FLAG_UNUSABLE,
  80                },
  81        },
  82        .safe_state_index = 0,
  83        .state_count = 3,
  84};
  85
  86int __init sh_mobile_setup_cpuidle(void)
  87{
  88        if (sh_mobile_sleep_supported & SUSP_SH_SF)
  89                cpuidle_driver.states[1].flags = CPUIDLE_FLAG_NONE;
  90
  91        if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
  92                cpuidle_driver.states[2].flags = CPUIDLE_FLAG_NONE;
  93
  94        return cpuidle_register(&cpuidle_driver, NULL);
  95}
  96