aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/twl6030-irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/twl6030-irq.c')
-rw-r--r--drivers/mfd/twl6030-irq.c75
1 files changed, 67 insertions, 8 deletions
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index eb3b5f88e566..deec3ec858bf 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -37,6 +37,7 @@
37#include <linux/kthread.h> 37#include <linux/kthread.h>
38#include <linux/i2c/twl.h> 38#include <linux/i2c/twl.h>
39#include <linux/platform_device.h> 39#include <linux/platform_device.h>
40#include <linux/suspend.h>
40 41
41#include "twl-core.h" 42#include "twl-core.h"
42 43
@@ -83,8 +84,48 @@ static int twl6030_interrupt_mapping[24] = {
83/*----------------------------------------------------------------------*/ 84/*----------------------------------------------------------------------*/
84 85
85static unsigned twl6030_irq_base; 86static unsigned twl6030_irq_base;
87static int twl_irq;
88static bool twl_irq_wake_enabled;
86 89
87static struct completion irq_event; 90static struct completion irq_event;
91static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
92
93static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
94 unsigned long pm_event, void *unused)
95{
96 int chained_wakeups;
97
98 switch (pm_event) {
99 case PM_SUSPEND_PREPARE:
100 chained_wakeups = atomic_read(&twl6030_wakeirqs);
101
102 if (chained_wakeups && !twl_irq_wake_enabled) {
103 if (enable_irq_wake(twl_irq))
104 pr_err("twl6030 IRQ wake enable failed\n");
105 else
106 twl_irq_wake_enabled = true;
107 } else if (!chained_wakeups && twl_irq_wake_enabled) {
108 disable_irq_wake(twl_irq);
109 twl_irq_wake_enabled = false;
110 }
111
112 disable_irq(twl_irq);
113 break;
114
115 case PM_POST_SUSPEND:
116 enable_irq(twl_irq);
117 break;
118
119 default:
120 break;
121 }
122
123 return NOTIFY_DONE;
124}
125
126static struct notifier_block twl6030_irq_pm_notifier_block = {
127 .notifier_call = twl6030_irq_pm_notifier,
128};
88 129
89/* 130/*
90 * This thread processes interrupts reported by the Primary Interrupt Handler. 131 * This thread processes interrupts reported by the Primary Interrupt Handler.
@@ -187,6 +228,16 @@ static inline void activate_irq(int irq)
187#endif 228#endif
188} 229}
189 230
231int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
232{
233 if (on)
234 atomic_inc(&twl6030_wakeirqs);
235 else
236 atomic_dec(&twl6030_wakeirqs);
237
238 return 0;
239}
240
190/*----------------------------------------------------------------------*/ 241/*----------------------------------------------------------------------*/
191 242
192static unsigned twl6030_irq_next; 243static unsigned twl6030_irq_next;
@@ -318,10 +369,12 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
318 twl6030_irq_chip = dummy_irq_chip; 369 twl6030_irq_chip = dummy_irq_chip;
319 twl6030_irq_chip.name = "twl6030"; 370 twl6030_irq_chip.name = "twl6030";
320 twl6030_irq_chip.irq_set_type = NULL; 371 twl6030_irq_chip.irq_set_type = NULL;
372 twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
321 373
322 for (i = irq_base; i < irq_end; i++) { 374 for (i = irq_base; i < irq_end; i++) {
323 irq_set_chip_and_handler(i, &twl6030_irq_chip, 375 irq_set_chip_and_handler(i, &twl6030_irq_chip,
324 handle_simple_irq); 376 handle_simple_irq);
377 irq_set_chip_data(i, (void *)irq_num);
325 activate_irq(i); 378 activate_irq(i);
326 } 379 }
327 380
@@ -331,6 +384,14 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
331 384
332 /* install an irq handler to demultiplex the TWL6030 interrupt */ 385 /* install an irq handler to demultiplex the TWL6030 interrupt */
333 init_completion(&irq_event); 386 init_completion(&irq_event);
387
388 status = request_irq(irq_num, handle_twl6030_pih, 0,
389 "TWL6030-PIH", &irq_event);
390 if (status < 0) {
391 pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
392 goto fail_irq;
393 }
394
334 task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); 395 task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
335 if (IS_ERR(task)) { 396 if (IS_ERR(task)) {
336 pr_err("twl6030: could not create irq %d thread!\n", irq_num); 397 pr_err("twl6030: could not create irq %d thread!\n", irq_num);
@@ -338,17 +399,14 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
338 goto fail_kthread; 399 goto fail_kthread;
339 } 400 }
340 401
341 status = request_irq(irq_num, handle_twl6030_pih, IRQF_DISABLED, 402 twl_irq = irq_num;
342 "TWL6030-PIH", &irq_event); 403 register_pm_notifier(&twl6030_irq_pm_notifier_block);
343 if (status < 0) {
344 pr_err("twl6030: could not claim irq%d: %d\n", irq_num, status);
345 goto fail_irq;
346 }
347 return status; 404 return status;
348fail_irq:
349 free_irq(irq_num, &irq_event);
350 405
351fail_kthread: 406fail_kthread:
407 free_irq(irq_num, &irq_event);
408
409fail_irq:
352 for (i = irq_base; i < irq_end; i++) 410 for (i = irq_base; i < irq_end; i++)
353 irq_set_chip_and_handler(i, NULL, NULL); 411 irq_set_chip_and_handler(i, NULL, NULL);
354 return status; 412 return status;
@@ -356,6 +414,7 @@ fail_kthread:
356 414
357int twl6030_exit_irq(void) 415int twl6030_exit_irq(void)
358{ 416{
417 unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
359 418
360 if (twl6030_irq_base) { 419 if (twl6030_irq_base) {
361 pr_err("twl6030: can't yet clean up IRQs?\n"); 420 pr_err("twl6030: can't yet clean up IRQs?\n");