aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/twl6030-irq.c
diff options
context:
space:
mode:
authorTodd Poynor <toddpoynor@google.com>2011-10-04 05:52:29 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2011-10-24 08:09:17 -0400
commitab2b9260df67e29d5bd69d989f2f84f8c2ed4238 (patch)
tree23ae7c73b270d41656673c6beed9c2dd5344b1d1 /drivers/mfd/twl6030-irq.c
parentd3efa4edd5a3b90aff813524aeece01d73d2279b (diff)
mfd: Fix twl6030 lockdep recursion warning on setting wake IRQs
LOCKDEP explicitly sets all irq_desc locks as a single lock-class, causing "possible recursive locking detected" when the TWL RTC driver calls through enable_irq_wake to twl6030_irq_set_wake, which recursively calls irq_set_irq_wake. Although the irq_desc and lock are different, LOCKDEP treats these as equivalent, presumably due to problems that can be incurred when locking more than one irq_desc, so best to avoid this. Suspend/resume actions implemented as PM notifiers to avoid touch the TWL core for this. Signed-off-by: Todd Poynor <toddpoynor@google.com> Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/twl6030-irq.c')
-rw-r--r--drivers/mfd/twl6030-irq.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index a17b42360e52..a014ec489e68 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,42 @@ 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 break;
113 default:
114 break;
115 }
116
117 return NOTIFY_DONE;
118}
119
120static struct notifier_block twl6030_irq_pm_notifier_block = {
121 .notifier_call = twl6030_irq_pm_notifier,
122};
88 123
89/* 124/*
90 * This thread processes interrupts reported by the Primary Interrupt Handler. 125 * This thread processes interrupts reported by the Primary Interrupt Handler.
@@ -189,9 +224,12 @@ static inline void activate_irq(int irq)
189 224
190int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) 225int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
191{ 226{
192 int twl_irq = (int)irq_get_chip_data(d->irq); 227 if (on)
228 atomic_inc(&twl6030_wakeirqs);
229 else
230 atomic_dec(&twl6030_wakeirqs);
193 231
194 return irq_set_irq_wake(twl_irq, on); 232 return 0;
195} 233}
196 234
197/*----------------------------------------------------------------------*/ 235/*----------------------------------------------------------------------*/
@@ -354,6 +392,9 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
354 status = PTR_ERR(task); 392 status = PTR_ERR(task);
355 goto fail_kthread; 393 goto fail_kthread;
356 } 394 }
395
396 twl_irq = irq_num;
397 register_pm_notifier(&twl6030_irq_pm_notifier_block);
357 return status; 398 return status;
358 399
359fail_kthread: 400fail_kthread:
@@ -367,6 +408,7 @@ fail_irq:
367 408
368int twl6030_exit_irq(void) 409int twl6030_exit_irq(void)
369{ 410{
411 unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
370 412
371 if (twl6030_irq_base) { 413 if (twl6030_irq_base) {
372 pr_err("twl6030: can't yet clean up IRQs?\n"); 414 pr_err("twl6030: can't yet clean up IRQs?\n");