diff options
Diffstat (limited to 'drivers/cpuidle/cpuidle-kirkwood.c')
-rw-r--r-- | drivers/cpuidle/cpuidle-kirkwood.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c new file mode 100644 index 000000000000..670aa1e55cd6 --- /dev/null +++ b/drivers/cpuidle/cpuidle-kirkwood.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-kirkwood/cpuidle.c | ||
3 | * | ||
4 | * CPU idle Marvell Kirkwood SoCs | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | ||
7 | * License version 2. This program is licensed "as is" without any | ||
8 | * warranty of any kind, whether express or implied. | ||
9 | * | ||
10 | * The cpu idle uses wait-for-interrupt and DDR self refresh in order | ||
11 | * to implement two idle states - | ||
12 | * #1 wait-for-interrupt | ||
13 | * #2 wait-for-interrupt and DDR self refresh | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/cpuidle.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/export.h> | ||
23 | #include <asm/proc-fns.h> | ||
24 | #include <asm/cpuidle.h> | ||
25 | |||
26 | #define KIRKWOOD_MAX_STATES 2 | ||
27 | |||
28 | static void __iomem *ddr_operation_base; | ||
29 | |||
30 | /* Actual code that puts the SoC in different idle states */ | ||
31 | static int kirkwood_enter_idle(struct cpuidle_device *dev, | ||
32 | struct cpuidle_driver *drv, | ||
33 | int index) | ||
34 | { | ||
35 | writel(0x7, ddr_operation_base); | ||
36 | cpu_do_idle(); | ||
37 | |||
38 | return index; | ||
39 | } | ||
40 | |||
41 | static struct cpuidle_driver kirkwood_idle_driver = { | ||
42 | .name = "kirkwood_idle", | ||
43 | .owner = THIS_MODULE, | ||
44 | .en_core_tk_irqen = 1, | ||
45 | .states[0] = ARM_CPUIDLE_WFI_STATE, | ||
46 | .states[1] = { | ||
47 | .enter = kirkwood_enter_idle, | ||
48 | .exit_latency = 10, | ||
49 | .target_residency = 100000, | ||
50 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
51 | .name = "DDR SR", | ||
52 | .desc = "WFI and DDR Self Refresh", | ||
53 | }, | ||
54 | .state_count = KIRKWOOD_MAX_STATES, | ||
55 | }; | ||
56 | static struct cpuidle_device *device; | ||
57 | |||
58 | static DEFINE_PER_CPU(struct cpuidle_device, kirkwood_cpuidle_device); | ||
59 | |||
60 | /* Initialize CPU idle by registering the idle states */ | ||
61 | static int kirkwood_cpuidle_probe(struct platform_device *pdev) | ||
62 | { | ||
63 | struct resource *res; | ||
64 | |||
65 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
66 | if (res == NULL) | ||
67 | return -EINVAL; | ||
68 | |||
69 | ddr_operation_base = devm_request_and_ioremap(&pdev->dev, res); | ||
70 | if (!ddr_operation_base) | ||
71 | return -EADDRNOTAVAIL; | ||
72 | |||
73 | device = &per_cpu(kirkwood_cpuidle_device, smp_processor_id()); | ||
74 | device->state_count = KIRKWOOD_MAX_STATES; | ||
75 | |||
76 | cpuidle_register_driver(&kirkwood_idle_driver); | ||
77 | if (cpuidle_register_device(device)) { | ||
78 | pr_err("kirkwood_init_cpuidle: Failed registering\n"); | ||
79 | return -EIO; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | int kirkwood_cpuidle_remove(struct platform_device *pdev) | ||
85 | { | ||
86 | cpuidle_unregister_device(device); | ||
87 | cpuidle_unregister_driver(&kirkwood_idle_driver); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static struct platform_driver kirkwood_cpuidle_driver = { | ||
93 | .probe = kirkwood_cpuidle_probe, | ||
94 | .remove = kirkwood_cpuidle_remove, | ||
95 | .driver = { | ||
96 | .name = "kirkwood_cpuidle", | ||
97 | .owner = THIS_MODULE, | ||
98 | }, | ||
99 | }; | ||
100 | |||
101 | module_platform_driver(kirkwood_cpuidle_driver); | ||
102 | |||
103 | MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); | ||
104 | MODULE_DESCRIPTION("Kirkwood cpu idle driver"); | ||
105 | MODULE_LICENSE("GPL v2"); | ||
106 | MODULE_ALIAS("platform:kirkwood-cpuidle"); | ||