Commit | Line | Data |
---|---|---|
b858fbc1 GC |
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 = "MV CPU 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 = "MV CPU 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"); |