Merge tag 'memblock-v6.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rppt...
[platform/kernel/linux-rpi.git] / drivers / cpuidle / cpuidle-mvebu-v7.c
1 /*
2  * Marvell Armada 370, 38x and XP SoC cpuidle driver
3  *
4  * Copyright (C) 2014 Marvell
5  *
6  * Nadav Haklai <nadavh@marvell.com>
7  * Gregory CLEMENT <gregory.clement@free-electrons.com>
8  *
9  * This file is licensed under the terms of the GNU General Public
10  * License version 2.  This program is licensed "as is" without any
11  * warranty of any kind, whether express or implied.
12  *
13  * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com>
14  */
15
16 #include <linux/cpu_pm.h>
17 #include <linux/cpuidle.h>
18 #include <linux/module.h>
19 #include <linux/of.h>
20 #include <linux/suspend.h>
21 #include <linux/platform_device.h>
22 #include <asm/cpuidle.h>
23
24 #define MVEBU_V7_FLAG_DEEP_IDLE 0x10000
25
26 static int (*mvebu_v7_cpu_suspend)(int);
27
28 static __cpuidle int mvebu_v7_enter_idle(struct cpuidle_device *dev,
29                                          struct cpuidle_driver *drv,
30                                          int index)
31 {
32         int ret;
33         bool deepidle = false;
34         cpu_pm_enter();
35
36         if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE)
37                 deepidle = true;
38
39         ct_cpuidle_enter();
40         ret = mvebu_v7_cpu_suspend(deepidle);
41         ct_cpuidle_exit();
42
43         cpu_pm_exit();
44
45         if (ret)
46                 return ret;
47
48         return index;
49 }
50
51 static struct cpuidle_driver armadaxp_idle_driver = {
52         .name                   = "armada_xp_idle",
53         .states[0]              = ARM_CPUIDLE_WFI_STATE,
54         .states[1]              = {
55                 .enter                  = mvebu_v7_enter_idle,
56                 .exit_latency           = 100,
57                 .power_usage            = 50,
58                 .target_residency       = 1000,
59                 .flags                  = CPUIDLE_FLAG_RCU_IDLE,
60                 .name                   = "MV CPU IDLE",
61                 .desc                   = "CPU power down",
62         },
63         .states[2]              = {
64                 .enter                  = mvebu_v7_enter_idle,
65                 .exit_latency           = 1000,
66                 .power_usage            = 5,
67                 .target_residency       = 10000,
68                 .flags                  = MVEBU_V7_FLAG_DEEP_IDLE | CPUIDLE_FLAG_RCU_IDLE,
69                 .name                   = "MV CPU DEEP IDLE",
70                 .desc                   = "CPU and L2 Fabric power down",
71         },
72         .state_count = 3,
73 };
74
75 static struct cpuidle_driver armada370_idle_driver = {
76         .name                   = "armada_370_idle",
77         .states[0]              = ARM_CPUIDLE_WFI_STATE,
78         .states[1]              = {
79                 .enter                  = mvebu_v7_enter_idle,
80                 .exit_latency           = 100,
81                 .power_usage            = 5,
82                 .target_residency       = 1000,
83                 .flags                  = MVEBU_V7_FLAG_DEEP_IDLE | CPUIDLE_FLAG_RCU_IDLE,
84                 .name                   = "Deep Idle",
85                 .desc                   = "CPU and L2 Fabric power down",
86         },
87         .state_count = 2,
88 };
89
90 static struct cpuidle_driver armada38x_idle_driver = {
91         .name                   = "armada_38x_idle",
92         .states[0]              = ARM_CPUIDLE_WFI_STATE,
93         .states[1]              = {
94                 .enter                  = mvebu_v7_enter_idle,
95                 .exit_latency           = 10,
96                 .power_usage            = 5,
97                 .target_residency       = 100,
98                 .flags                  = CPUIDLE_FLAG_RCU_IDLE,
99                 .name                   = "Idle",
100                 .desc                   = "CPU and SCU power down",
101         },
102         .state_count = 2,
103 };
104
105 static int mvebu_v7_cpuidle_probe(struct platform_device *pdev)
106 {
107         const struct platform_device_id *id = pdev->id_entry;
108
109         if (!id)
110                 return -EINVAL;
111
112         mvebu_v7_cpu_suspend = pdev->dev.platform_data;
113
114         return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL);
115 }
116
117 static const struct platform_device_id mvebu_cpuidle_ids[] = {
118         {
119                 .name = "cpuidle-armada-xp",
120                 .driver_data = (unsigned long)&armadaxp_idle_driver,
121         }, {
122                 .name = "cpuidle-armada-370",
123                 .driver_data = (unsigned long)&armada370_idle_driver,
124         }, {
125                 .name = "cpuidle-armada-38x",
126                 .driver_data = (unsigned long)&armada38x_idle_driver,
127         },
128         {}
129 };
130
131 static struct platform_driver mvebu_cpuidle_driver = {
132         .probe = mvebu_v7_cpuidle_probe,
133         .driver = {
134                 .name = "cpuidle-mbevu",
135                 .suppress_bind_attrs = true,
136         },
137         .id_table = mvebu_cpuidle_ids,
138 };
139
140 builtin_platform_driver(mvebu_cpuidle_driver);
141
142 MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
143 MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver");
144 MODULE_LICENSE("GPL");