1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright 2012 Calxeda, Inc.
4  *
5  * Based on arch/arm/plat-mxc/cpuidle.c: #v3.7
6  * Copyright 2012 Freescale Semiconductor, Inc.
7  * Copyright 2012 Linaro Ltd.
8  *
9  * Maintainer: Rob Herring <rob.herring@calxeda.com>
10  */
11 
12 #include <linux/cpuidle.h>
13 #include <linux/cpu_pm.h>
14 #include <linux/init.h>
15 #include <linux/mm.h>
16 #include <linux/platform_device.h>
17 #include <linux/psci.h>
18 
19 #include <asm/cpuidle.h>
20 #include <asm/suspend.h>
21 
22 #include <uapi/linux/psci.h>
23 
24 #define CALXEDA_IDLE_PARAM \
25 	((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
26 	 (0 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
27 	 (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
28 
29 static int calxeda_idle_finish(unsigned long val)
30 {
31 	return psci_ops.cpu_suspend(CALXEDA_IDLE_PARAM, __pa(cpu_resume));
32 }
33 
34 static int calxeda_pwrdown_idle(struct cpuidle_device *dev,
35 				struct cpuidle_driver *drv,
36 				int index)
37 {
38 	cpu_pm_enter();
39 	cpu_suspend(0, calxeda_idle_finish);
40 	cpu_pm_exit();
41 
42 	return index;
43 }
44 
45 static struct cpuidle_driver calxeda_idle_driver = {
46 	.name = "calxeda_idle",
47 	.states = {
48 		ARM_CPUIDLE_WFI_STATE,
49 		{
50 			.name = "PG",
51 			.desc = "Power Gate",
52 			.exit_latency = 30,
53 			.power_usage = 50,
54 			.target_residency = 200,
55 			.enter = calxeda_pwrdown_idle,
56 		},
57 	},
58 	.state_count = 2,
59 };
60 
61 static int calxeda_cpuidle_probe(struct platform_device *pdev)
62 {
63 	return cpuidle_register(&calxeda_idle_driver, NULL);
64 }
65 
66 static struct platform_driver calxeda_cpuidle_plat_driver = {
67         .driver = {
68                 .name = "cpuidle-calxeda",
69         },
70         .probe = calxeda_cpuidle_probe,
71 };
72 builtin_platform_driver(calxeda_cpuidle_plat_driver);
73