blob: 1cd23b8019034f4f5e161853c3ee84f5802ca38b [file] [log] [blame]
Colin Cross06e85722011-11-09 16:39:19 -05001/*
2 * Copyright (C) 2011 Google, Inc.
3 *
4 * Author:
5 * Colin Cross <ccross <at> android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include <linux/kernel.h>
19#include <linux/cpu_pm.h>
20#include <linux/module.h>
21#include <linux/notifier.h>
22#include <linux/spinlock.h>
23
24static DEFINE_RWLOCK(cpu_pm_notifier_lock);
25static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain);
26
27int cpu_pm_register_notifier(struct notifier_block *nb)
28{
29 unsigned long flags;
30 int ret;
31
32 write_lock_irqsave(&cpu_pm_notifier_lock, flags);
33 ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
34 write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
35
36 return ret;
37}
38EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
39
40int cpu_pm_unregister_notifier(struct notifier_block *nb)
41{
42 unsigned long flags;
43 int ret;
44
45 write_lock_irqsave(&cpu_pm_notifier_lock, flags);
46 ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
47 write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
48
49 return ret;
50}
51EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
52
53static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
54{
55 int ret;
56
57 ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
58 nr_to_call, nr_calls);
59
60 return notifier_to_errno(ret);
61}
62
63int cpu_pm_enter(void)
64{
65 int nr_calls;
66 int ret = 0;
67
68 read_lock(&cpu_pm_notifier_lock);
69 ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
70 if (ret)
71 cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
72 read_unlock(&cpu_pm_notifier_lock);
73
74 return ret;
75}
76EXPORT_SYMBOL_GPL(cpu_pm_enter);
77
78int cpu_pm_exit(void)
79{
80 int ret;
81
82 read_lock(&cpu_pm_notifier_lock);
83 ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
84 read_unlock(&cpu_pm_notifier_lock);
85
86 return ret;
87}
88EXPORT_SYMBOL_GPL(cpu_pm_exit);
89
90int cpu_cluster_pm_enter(void)
91{
92 int nr_calls;
93 int ret = 0;
94
95 read_lock(&cpu_pm_notifier_lock);
96 ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
97 if (ret)
98 cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
99 read_unlock(&cpu_pm_notifier_lock);
100
101 return ret;
102}
103EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
104
105int cpu_cluster_pm_exit(void)
106{
107 int ret;
108
109 read_lock(&cpu_pm_notifier_lock);
110 ret = cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
111 read_unlock(&cpu_pm_notifier_lock);
112
113 return ret;
114}
115EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);