aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/gpio.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-04-07 15:59:42 -0400
committerColin Cross <ccross@android.com>2010-10-21 21:12:01 -0400
commit2e47b8b3c2dc0f9f0651ee0f20e163da09b20fb9 (patch)
treeff11a2b600719061af20973ff974ecdcfaccc954 /arch/arm/mach-tegra/gpio.c
parentc5f04b8d10a73f2a016d6815d64dd5eebc734097 (diff)
[ARM] tegra: gpio: Add suspend and wake support
Includes checkpatch fixes and TEGRA_NR_GPIOS changes from Mike Rapoport <mike@compulab.co.il> Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/gpio.c')
-rw-r--r--arch/arm/mach-tegra/gpio.c104
1 files changed, 93 insertions, 11 deletions
diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c
index fe78fba25f3c..0775265e69f5 100644
--- a/arch/arm/mach-tegra/gpio.c
+++ b/arch/arm/mach-tegra/gpio.c
@@ -19,6 +19,7 @@
19 19
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/irq.h> 21#include <linux/irq.h>
22#include <linux/interrupt.h>
22 23
23#include <linux/io.h> 24#include <linux/io.h>
24#include <linux/gpio.h> 25#include <linux/gpio.h>
@@ -60,6 +61,13 @@ struct tegra_gpio_bank {
60 int bank; 61 int bank;
61 int irq; 62 int irq;
62 spinlock_t lvl_lock[4]; 63 spinlock_t lvl_lock[4];
64#ifdef CONFIG_PM
65 u32 cnf[4];
66 u32 out[4];
67 u32 oe[4];
68 u32 int_enb[4];
69 u32 int_lvl[4];
70#endif
63}; 71};
64 72
65 73
@@ -131,7 +139,7 @@ static struct gpio_chip tegra_gpio_chip = {
131 .direction_output = tegra_gpio_direction_output, 139 .direction_output = tegra_gpio_direction_output,
132 .set = tegra_gpio_set, 140 .set = tegra_gpio_set,
133 .base = 0, 141 .base = 0,
134 .ngpio = ARCH_NR_GPIOS, 142 .ngpio = TEGRA_NR_GPIOS,
135}; 143};
136 144
137static void tegra_gpio_irq_ack(unsigned int irq) 145static void tegra_gpio_irq_ack(unsigned int irq)
@@ -244,6 +252,76 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
244 252
245} 253}
246 254
255#ifdef CONFIG_PM
256void tegra_gpio_resume(void)
257{
258 unsigned long flags;
259 int b, p, i;
260
261 local_irq_save(flags);
262
263 for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
264 struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
265
266 for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
267 unsigned int gpio = (b<<5) | (p<<3);
268 __raw_writel(bank->cnf[p], GPIO_CNF(gpio));
269 __raw_writel(bank->out[p], GPIO_OUT(gpio));
270 __raw_writel(bank->oe[p], GPIO_OE(gpio));
271 __raw_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
272 __raw_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
273 }
274 }
275
276 local_irq_restore(flags);
277
278 for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
279 struct irq_desc *desc = irq_to_desc(i);
280 if (!desc || (desc->status & IRQ_WAKEUP))
281 continue;
282 enable_irq(i);
283 }
284}
285
286void tegra_gpio_suspend(void)
287{
288 unsigned long flags;
289 int b, p, i;
290
291 for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
292 struct irq_desc *desc = irq_to_desc(i);
293 if (!desc)
294 continue;
295 if (desc->status & IRQ_WAKEUP) {
296 int gpio = i - INT_GPIO_BASE;
297 pr_debug("gpio %d.%d is wakeup\n", gpio/8, gpio&7);
298 continue;
299 }
300 disable_irq(i);
301 }
302
303 local_irq_save(flags);
304 for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) {
305 struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
306
307 for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
308 unsigned int gpio = (b<<5) | (p<<3);
309 bank->cnf[p] = __raw_readl(GPIO_CNF(gpio));
310 bank->out[p] = __raw_readl(GPIO_OUT(gpio));
311 bank->oe[p] = __raw_readl(GPIO_OE(gpio));
312 bank->int_enb[p] = __raw_readl(GPIO_INT_ENB(gpio));
313 bank->int_lvl[p] = __raw_readl(GPIO_INT_LVL(gpio));
314 }
315 }
316 local_irq_restore(flags);
317}
318
319static int tegra_gpio_wake_enable(unsigned int irq, unsigned int enable)
320{
321 struct tegra_gpio_bank *bank = get_irq_chip_data(irq);
322 return set_irq_wake(bank->irq, enable);
323}
324#endif
247 325
248static struct irq_chip tegra_gpio_irq_chip = { 326static struct irq_chip tegra_gpio_irq_chip = {
249 .name = "GPIO", 327 .name = "GPIO",
@@ -251,6 +329,9 @@ static struct irq_chip tegra_gpio_irq_chip = {
251 .mask = tegra_gpio_irq_mask, 329 .mask = tegra_gpio_irq_mask,
252 .unmask = tegra_gpio_irq_unmask, 330 .unmask = tegra_gpio_irq_unmask,
253 .set_type = tegra_gpio_irq_set_type, 331 .set_type = tegra_gpio_irq_set_type,
332#ifdef CONFIG_PM
333 .set_wake = tegra_gpio_wake_enable,
334#endif
254}; 335};
255 336
256 337
@@ -274,7 +355,7 @@ static int __init tegra_gpio_init(void)
274 355
275 gpiochip_add(&tegra_gpio_chip); 356 gpiochip_add(&tegra_gpio_chip);
276 357
277 for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + ARCH_NR_GPIOS); i++) { 358 for (i = INT_GPIO_BASE; i < (INT_GPIO_BASE + TEGRA_NR_GPIOS); i++) {
278 bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))]; 359 bank = &tegra_gpio_banks[GPIO_BANK(irq_to_gpio(i))];
279 360
280 lockdep_set_class(&irq_desc[i].lock, &gpio_lock_class); 361 lockdep_set_class(&irq_desc[i].lock, &gpio_lock_class);
@@ -312,15 +393,16 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
312 for (i = 0; i < 7; i++) { 393 for (i = 0; i < 7; i++) {
313 for (j = 0; j < 4; j++) { 394 for (j = 0; j < 4; j++) {
314 int gpio = tegra_gpio_compose(i, j, 0); 395 int gpio = tegra_gpio_compose(i, j, 0);
315 seq_printf(s, "%d:%d %02x %02x %02x %02x %02x %02x %06x\n", 396 seq_printf(s,
316 i, j, 397 "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
317 __raw_readl(GPIO_CNF(gpio)), 398 i, j,
318 __raw_readl(GPIO_OE(gpio)), 399 __raw_readl(GPIO_CNF(gpio)),
319 __raw_readl(GPIO_OUT(gpio)), 400 __raw_readl(GPIO_OE(gpio)),
320 __raw_readl(GPIO_IN(gpio)), 401 __raw_readl(GPIO_OUT(gpio)),
321 __raw_readl(GPIO_INT_STA(gpio)), 402 __raw_readl(GPIO_IN(gpio)),
322 __raw_readl(GPIO_INT_ENB(gpio)), 403 __raw_readl(GPIO_INT_STA(gpio)),
323 __raw_readl(GPIO_INT_LVL(gpio))); 404 __raw_readl(GPIO_INT_ENB(gpio)),
405 __raw_readl(GPIO_INT_LVL(gpio)));
324 } 406 }
325 } 407 }
326 return 0; 408 return 0;