1176ce1b7SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
27426394fSMagnus Damm /*
37426394fSMagnus Damm * arch/sh/kernel/cpu/shmobile/cpuidle.c
47426394fSMagnus Damm *
57426394fSMagnus Damm * Cpuidle support code for SuperH Mobile
67426394fSMagnus Damm *
77426394fSMagnus Damm * Copyright (C) 2009 Magnus Damm
87426394fSMagnus Damm */
97426394fSMagnus Damm #include <linux/init.h>
107426394fSMagnus Damm #include <linux/kernel.h>
117426394fSMagnus Damm #include <linux/io.h>
127426394fSMagnus Damm #include <linux/suspend.h>
137426394fSMagnus Damm #include <linux/cpuidle.h>
14f7be3455SPaul Gortmaker #include <linux/export.h>
157426394fSMagnus Damm #include <asm/suspend.h>
167c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
177426394fSMagnus Damm
187426394fSMagnus Damm static unsigned long cpuidle_mode[] = {
197426394fSMagnus Damm SUSP_SH_SLEEP, /* regular sleep mode */
207426394fSMagnus Damm SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */
2163cd91dfSMagnus Damm SUSP_SH_STANDBY | SUSP_SH_SF, /* software standby mode + self refresh */
227426394fSMagnus Damm };
237426394fSMagnus Damm
cpuidle_sleep_enter(struct cpuidle_device * dev,struct cpuidle_driver * drv,int index)247426394fSMagnus Damm static int cpuidle_sleep_enter(struct cpuidle_device *dev,
2546bcfad7SDeepthi Dharwar struct cpuidle_driver *drv,
26e978aa7dSDeepthi Dharwar int index)
277426394fSMagnus Damm {
284be88734SPaul Mundt unsigned long allowed_mode = SUSP_SH_SLEEP;
29e978aa7dSDeepthi Dharwar int requested_state = index;
307426394fSMagnus Damm int allowed_state;
317426394fSMagnus Damm int k;
327426394fSMagnus Damm
337426394fSMagnus Damm /* convert allowed mode to allowed state */
347426394fSMagnus Damm for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--)
357426394fSMagnus Damm if (cpuidle_mode[k] == allowed_mode)
367426394fSMagnus Damm break;
377426394fSMagnus Damm
387426394fSMagnus Damm allowed_state = k;
397426394fSMagnus Damm
407426394fSMagnus Damm /* take the following into account for sleep mode selection:
417426394fSMagnus Damm * - allowed_state: best mode allowed by hardware (clock deps)
427426394fSMagnus Damm * - requested_state: best mode allowed by software (latencies)
437426394fSMagnus Damm */
447426394fSMagnus Damm k = min_t(int, allowed_state, requested_state);
457426394fSMagnus Damm
467426394fSMagnus Damm sh_mobile_call_standby(cpuidle_mode[k]);
47e978aa7dSDeepthi Dharwar
48e978aa7dSDeepthi Dharwar return k;
497426394fSMagnus Damm }
507426394fSMagnus Damm
517426394fSMagnus Damm static struct cpuidle_driver cpuidle_driver = {
527426394fSMagnus Damm .name = "sh_idle",
537426394fSMagnus Damm .owner = THIS_MODULE,
540a4f841eSDaniel Lezcano .states = {
550a4f841eSDaniel Lezcano {
560a4f841eSDaniel Lezcano .exit_latency = 1,
570a4f841eSDaniel Lezcano .target_residency = 1 * 2,
580a4f841eSDaniel Lezcano .power_usage = 3,
590a4f841eSDaniel Lezcano .enter = cpuidle_sleep_enter,
600a4f841eSDaniel Lezcano .name = "C1",
610a4f841eSDaniel Lezcano .desc = "SuperH Sleep Mode",
620a4f841eSDaniel Lezcano },
630a4f841eSDaniel Lezcano {
640a4f841eSDaniel Lezcano .exit_latency = 100,
650a4f841eSDaniel Lezcano .target_residency = 1 * 2,
660a4f841eSDaniel Lezcano .power_usage = 1,
670a4f841eSDaniel Lezcano .enter = cpuidle_sleep_enter,
680a4f841eSDaniel Lezcano .name = "C2",
690a4f841eSDaniel Lezcano .desc = "SuperH Sleep Mode [SF]",
70*ba1e78a1SRafael J. Wysocki .flags = CPUIDLE_FLAG_UNUSABLE,
710a4f841eSDaniel Lezcano },
720a4f841eSDaniel Lezcano {
730a4f841eSDaniel Lezcano .exit_latency = 2300,
740a4f841eSDaniel Lezcano .target_residency = 1 * 2,
750a4f841eSDaniel Lezcano .power_usage = 1,
760a4f841eSDaniel Lezcano .enter = cpuidle_sleep_enter,
770a4f841eSDaniel Lezcano .name = "C3",
780a4f841eSDaniel Lezcano .desc = "SuperH Mobile Standby Mode [SF]",
79*ba1e78a1SRafael J. Wysocki .flags = CPUIDLE_FLAG_UNUSABLE,
800a4f841eSDaniel Lezcano },
810a4f841eSDaniel Lezcano },
820a4f841eSDaniel Lezcano .safe_state_index = 0,
830a4f841eSDaniel Lezcano .state_count = 3,
847426394fSMagnus Damm };
857426394fSMagnus Damm
sh_mobile_setup_cpuidle(void)8638a94f41SDaniel Lezcano int __init sh_mobile_setup_cpuidle(void)
877426394fSMagnus Damm {
880a4f841eSDaniel Lezcano if (sh_mobile_sleep_supported & SUSP_SH_SF)
89*ba1e78a1SRafael J. Wysocki cpuidle_driver.states[1].flags = CPUIDLE_FLAG_NONE;
907426394fSMagnus Damm
910a4f841eSDaniel Lezcano if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
92*ba1e78a1SRafael J. Wysocki cpuidle_driver.states[2].flags = CPUIDLE_FLAG_NONE;
937426394fSMagnus Damm
94c78e4360SGeert Uytterhoeven return cpuidle_register(&cpuidle_driver, NULL);
957426394fSMagnus Damm }
96