Merge tag 'mvebu-fixes-3.16-3' of git://git.infradead.org/linux-mvebu into fixes
[cascardo/linux.git] / drivers / cpuidle / cpuidle-armada-370-xp.c
1 /*
2  * Marvell Armada 370 and Armada 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 ARMADA_370_XP_MAX_STATES        3
25 #define ARMADA_370_XP_FLAG_DEEP_IDLE    0x10000
26
27 static int (*armada_370_xp_cpu_suspend)(int);
28
29 static int armada_370_xp_enter_idle(struct cpuidle_device *dev,
30                                 struct cpuidle_driver *drv,
31                                 int index)
32 {
33         int ret;
34         bool deepidle = false;
35         cpu_pm_enter();
36
37         if (drv->states[index].flags & ARMADA_370_XP_FLAG_DEEP_IDLE)
38                 deepidle = true;
39
40         ret = armada_370_xp_cpu_suspend(deepidle);
41         if (ret)
42                 return ret;
43
44         cpu_pm_exit();
45
46         return index;
47 }
48
49 static struct cpuidle_driver armada_370_xp_idle_driver = {
50         .name                   = "armada_370_xp_idle",
51         .states[0]              = ARM_CPUIDLE_WFI_STATE,
52         .states[1]              = {
53                 .enter                  = armada_370_xp_enter_idle,
54                 .exit_latency           = 10,
55                 .power_usage            = 50,
56                 .target_residency       = 100,
57                 .flags                  = CPUIDLE_FLAG_TIME_VALID,
58                 .name                   = "Idle",
59                 .desc                   = "CPU power down",
60         },
61         .states[2]              = {
62                 .enter                  = armada_370_xp_enter_idle,
63                 .exit_latency           = 100,
64                 .power_usage            = 5,
65                 .target_residency       = 1000,
66                 .flags                  = CPUIDLE_FLAG_TIME_VALID |
67                                                 ARMADA_370_XP_FLAG_DEEP_IDLE,
68                 .name                   = "Deep idle",
69                 .desc                   = "CPU and L2 Fabric power down",
70         },
71         .state_count = ARMADA_370_XP_MAX_STATES,
72 };
73
74 static int armada_370_xp_cpuidle_probe(struct platform_device *pdev)
75 {
76
77         armada_370_xp_cpu_suspend = (void *)(pdev->dev.platform_data);
78         return cpuidle_register(&armada_370_xp_idle_driver, NULL);
79 }
80
81 static struct platform_driver armada_370_xp_cpuidle_plat_driver = {
82         .driver = {
83                 .name = "cpuidle-armada-370-xp",
84                 .owner = THIS_MODULE,
85         },
86         .probe = armada_370_xp_cpuidle_probe,
87 };
88
89 module_platform_driver(armada_370_xp_cpuidle_plat_driver);
90
91 MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
92 MODULE_DESCRIPTION("Armada 370/XP cpu idle driver");
93 MODULE_LICENSE("GPL");