ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / tegra-wakeups.c
1 /*
2  * Tegra Wakeups for NVIDIA SoCs Tegra
3  *
4  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * Author: Laxman Dewangan <ldewangan@nvidia.com>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/export.h>
22 #include <linux/kernel.h>
23 #include <linux/gpio.h>
24 #include <linux/init.h>
25 #include <linux/interrupt.h>
26 #include <linux/irq.h>
27 #include <linux/io.h>
28 #include <linux/irqchip/tegra.h>
29 #include <linux/system-wakeup.h>
30
31 #include <mach/irqs.h>
32 #include <mach/gpio-tegra.h>
33
34 int *tegra_gpio_wake_table;
35 EXPORT_SYMBOL_GPL(tegra_gpio_wake_table);
36
37 int *tegra_irq_wake_table;
38 EXPORT_SYMBOL_GPL(tegra_irq_wake_table);
39
40 int tegra_wake_table_len;
41 EXPORT_SYMBOL_GPL(tegra_wake_table_len);
42
43 static int last_gpio = -1;
44
45 int tegra_set_wake_gpio(unsigned int wake, int gpio)
46 {
47         if (wake >= tegra_wake_table_len)
48                 return -EINVAL;
49
50         tegra_irq_wake_table[wake] = -EAGAIN;
51         tegra_gpio_wake_table[wake] = gpio;
52
53         return 0;
54 }
55
56 int tegra_set_wake_irq(unsigned int wake, int irq)
57 {
58         if (wake >= tegra_wake_table_len)
59                 return -EINVAL;
60
61         tegra_irq_wake_table[wake] = irq;
62
63         return 0;
64 }
65
66 int tegra_gpio_to_wake(int gpio)
67 {
68         int i;
69
70         for (i = 0; i < tegra_wake_table_len; i++) {
71                 if (tegra_gpio_wake_table[i] == gpio) {
72                         pr_info("gpio wake%d for gpio=%d\n", i, gpio);
73                         last_gpio = i;
74                         return i;
75                 }
76         }
77
78         return -EINVAL;
79 }
80
81 void tegra_irq_to_wake(int irq, int *wak_list, int *wak_size)
82 {
83         int i;
84         int bank_irq;
85
86         *wak_size = 0;
87         for (i = 0; i < tegra_wake_table_len; i++) {
88                 if (tegra_irq_wake_table[i] == irq) {
89                         pr_info("Wake%d for irq=%d\n", i, irq);
90                         wak_list[*wak_size] = i;
91                         *wak_size = *wak_size + 1;
92                 }
93         }
94         if (*wak_size)
95                 goto out;
96
97         /* The gpio set_wake code bubbles the set_wake call up to the irq
98          * set_wake code. This insures that the nested irq set_wake call
99          * succeeds, even though it doesn't have to do any pm setup for the
100          * bank.
101          *
102          * This is very fragile - there's no locking, so two callers could
103          * cause issues with this.
104          */
105         if (last_gpio < 0)
106                 goto out;
107
108         bank_irq = tegra_gpio_get_bank_int_nr(tegra_gpio_wake_table[last_gpio]);
109         if (bank_irq == irq) {
110                 pr_info("gpio bank wake found: wake%d for irq=%d\n", i, irq);
111                 wak_list[*wak_size] = last_gpio;
112                 *wak_size = 1;
113         }
114
115 out:
116         return;
117 }
118
119 int tegra_wake_to_irq(int wake)
120 {
121         int ret;
122
123         if (wake < 0)
124                 return -EINVAL;
125
126         if (wake >= tegra_wake_table_len)
127                 return -EINVAL;
128
129         ret = tegra_irq_wake_table[wake];
130         if (ret == -EAGAIN) {
131                 ret = tegra_gpio_wake_table[wake];
132                 if (ret != -EINVAL)
133                         ret = gpio_to_irq(ret);
134         }
135
136         return ret;
137 }
138
139 int tegra_set_wake_source(int wake, int irq)
140 {
141         if (wake < 0)
142                 return -EINVAL;
143
144         if (wake >= tegra_wake_table_len)
145                 return -EINVAL;
146
147         tegra_irq_wake_table[wake] = irq;
148         return 0;
149 }
150
151 int tegra_disable_wake_source(int wake)
152 {
153         return tegra_set_wake_source(wake, -EINVAL);
154 }
155
156 int get_wakeup_reason_irq(void)
157 {
158         unsigned long long wake_status = tegra_read_pmc_wake_status();
159         unsigned long long mask_ll = 1ULL;
160         int irq;
161         struct irq_desc *desc;
162         int i;
163
164         for (i = 0; i < tegra_wake_table_len; ++i) {
165                 if (mask_ll & wake_status) {
166                         irq = tegra_wake_to_irq(i);
167                         if (!irq)
168                                 continue;
169                         desc = irq_to_desc(irq);
170                         if (!desc || !desc->action || !desc->action->name)
171                                 continue;
172                         return irq;
173                 }
174                 mask_ll <<= 1;
175         }
176         return -EINVAL;
177 }
178 EXPORT_SYMBOL_GPL(get_wakeup_reason_irq);