diff options
author | Colin Cross <ccross@android.com> | 2010-04-07 15:59:42 -0400 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-10-21 21:12:01 -0400 |
commit | 2e47b8b3c2dc0f9f0651ee0f20e163da09b20fb9 (patch) | |
tree | ff11a2b600719061af20973ff974ecdcfaccc954 /arch/arm/mach-tegra | |
parent | c5f04b8d10a73f2a016d6815d64dd5eebc734097 (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')
-rw-r--r-- | arch/arm/mach-tegra/gpio.c | 104 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/gpio.h | 4 |
2 files changed, 95 insertions, 13 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 | ||
137 | static void tegra_gpio_irq_ack(unsigned int irq) | 145 | static 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 | ||
256 | void 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 | |||
286 | void 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 | |||
319 | static 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 | ||
248 | static struct irq_chip tegra_gpio_irq_chip = { | 326 | static 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; |
diff --git a/arch/arm/mach-tegra/include/mach/gpio.h b/arch/arm/mach-tegra/include/mach/gpio.h index 540e822e50f7..e31f486d69a2 100644 --- a/arch/arm/mach-tegra/include/mach/gpio.h +++ b/arch/arm/mach-tegra/include/mach/gpio.h | |||
@@ -22,7 +22,7 @@ | |||
22 | 22 | ||
23 | #include <mach/irqs.h> | 23 | #include <mach/irqs.h> |
24 | 24 | ||
25 | #define ARCH_NR_GPIOS INT_GPIO_NR | 25 | #define TEGRA_NR_GPIOS INT_GPIO_NR |
26 | 26 | ||
27 | #include <asm-generic/gpio.h> | 27 | #include <asm-generic/gpio.h> |
28 | 28 | ||
@@ -35,7 +35,7 @@ | |||
35 | 35 | ||
36 | static inline int gpio_to_irq(unsigned int gpio) | 36 | static inline int gpio_to_irq(unsigned int gpio) |
37 | { | 37 | { |
38 | if (gpio < ARCH_NR_GPIOS) | 38 | if (gpio < TEGRA_NR_GPIOS) |
39 | return INT_GPIO_BASE + gpio; | 39 | return INT_GPIO_BASE + gpio; |
40 | return -EINVAL; | 40 | return -EINVAL; |
41 | } | 41 | } |