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.c101
1 files changed, 59 insertions, 42 deletions
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 1b03ce9e9f15..e3c54f80b9f0 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -86,36 +86,44 @@ static int twl6030_interrupt_mapping[24] = {
86}; 86};
87/*----------------------------------------------------------------------*/ 87/*----------------------------------------------------------------------*/
88 88
89static int twl_irq; 89struct twl6030_irq {
90static bool twl_irq_wake_enabled; 90 unsigned int irq_base;
91 int twl_irq;
92 bool irq_wake_enabled;
93 atomic_t wakeirqs;
94 struct notifier_block pm_nb;
95 struct irq_chip irq_chip;
96 struct irq_domain *irq_domain;
97};
91 98
92static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); 99static struct twl6030_irq *twl6030_irq;
93struct irq_domain *irq_domain;
94 100
95static int twl6030_irq_pm_notifier(struct notifier_block *notifier, 101static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
96 unsigned long pm_event, void *unused) 102 unsigned long pm_event, void *unused)
97{ 103{
98 int chained_wakeups; 104 int chained_wakeups;
105 struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq,
106 pm_nb);
99 107
100 switch (pm_event) { 108 switch (pm_event) {
101 case PM_SUSPEND_PREPARE: 109 case PM_SUSPEND_PREPARE:
102 chained_wakeups = atomic_read(&twl6030_wakeirqs); 110 chained_wakeups = atomic_read(&pdata->wakeirqs);
103 111
104 if (chained_wakeups && !twl_irq_wake_enabled) { 112 if (chained_wakeups && !pdata->irq_wake_enabled) {
105 if (enable_irq_wake(twl_irq)) 113 if (enable_irq_wake(pdata->twl_irq))
106 pr_err("twl6030 IRQ wake enable failed\n"); 114 pr_err("twl6030 IRQ wake enable failed\n");
107 else 115 else
108 twl_irq_wake_enabled = true; 116 pdata->irq_wake_enabled = true;
109 } else if (!chained_wakeups && twl_irq_wake_enabled) { 117 } else if (!chained_wakeups && pdata->irq_wake_enabled) {
110 disable_irq_wake(twl_irq); 118 disable_irq_wake(pdata->twl_irq);
111 twl_irq_wake_enabled = false; 119 pdata->irq_wake_enabled = false;
112 } 120 }
113 121
114 disable_irq(twl_irq); 122 disable_irq(pdata->twl_irq);
115 break; 123 break;
116 124
117 case PM_POST_SUSPEND: 125 case PM_POST_SUSPEND:
118 enable_irq(twl_irq); 126 enable_irq(pdata->twl_irq);
119 break; 127 break;
120 128
121 default: 129 default:
@@ -125,10 +133,6 @@ static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
125 return NOTIFY_DONE; 133 return NOTIFY_DONE;
126} 134}
127 135
128static struct notifier_block twl6030_irq_pm_notifier_block = {
129 .notifier_call = twl6030_irq_pm_notifier,
130};
131
132/* 136/*
133* Threaded irq handler for the twl6030 interrupt. 137* Threaded irq handler for the twl6030 interrupt.
134* We query the interrupt controller in the twl6030 to determine 138* We query the interrupt controller in the twl6030 to determine
@@ -138,11 +142,11 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
138static irqreturn_t twl6030_irq_thread(int irq, void *data) 142static irqreturn_t twl6030_irq_thread(int irq, void *data)
139{ 143{
140 int i, ret; 144 int i, ret;
141 struct irq_domain *irq_domain = (struct irq_domain *)data;
142 union { 145 union {
143 u8 bytes[4]; 146 u8 bytes[4];
144 u32 int_sts; 147 u32 int_sts;
145 } sts; 148 } sts;
149 struct twl6030_irq *pdata = data;
146 150
147 /* read INT_STS_A, B and C in one shot using a burst read */ 151 /* read INT_STS_A, B and C in one shot using a burst read */
148 ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3); 152 ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3);
@@ -163,7 +167,7 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
163 for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) 167 for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
164 if (sts.int_sts & 0x1) { 168 if (sts.int_sts & 0x1) {
165 int module_irq = 169 int module_irq =
166 irq_find_mapping(irq_domain, 170 irq_find_mapping(pdata->irq_domain,
167 twl6030_interrupt_mapping[i]); 171 twl6030_interrupt_mapping[i]);
168 if (module_irq) 172 if (module_irq)
169 handle_nested_irq(module_irq); 173 handle_nested_irq(module_irq);
@@ -194,10 +198,12 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
194 198
195static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) 199static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
196{ 200{
201 struct twl6030_irq *pdata = irq_get_chip_data(d->irq);
202
197 if (on) 203 if (on)
198 atomic_inc(&twl6030_wakeirqs); 204 atomic_inc(&pdata->wakeirqs);
199 else 205 else
200 atomic_dec(&twl6030_wakeirqs); 206 atomic_dec(&pdata->wakeirqs);
201 207
202 return 0; 208 return 0;
203} 209}
@@ -272,7 +278,8 @@ int twl6030_mmc_card_detect_config(void)
272 return ret; 278 return ret;
273 } 279 }
274 280
275 return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET); 281 return irq_find_mapping(twl6030_irq->irq_domain,
282 MMCDETECT_INTR_OFFSET);
276} 283}
277EXPORT_SYMBOL(twl6030_mmc_card_detect_config); 284EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
278 285
@@ -301,15 +308,15 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
301} 308}
302EXPORT_SYMBOL(twl6030_mmc_card_detect); 309EXPORT_SYMBOL(twl6030_mmc_card_detect);
303 310
304static struct irq_chip twl6030_irq_chip;
305
306static int twl6030_irq_map(struct irq_domain *d, unsigned int virq, 311static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
307 irq_hw_number_t hwirq) 312 irq_hw_number_t hwirq)
308{ 313{
309 irq_set_chip_data(virq, &twl6030_irq_chip); 314 struct twl6030_irq *pdata = d->host_data;
310 irq_set_chip_and_handler(virq, &twl6030_irq_chip, handle_simple_irq); 315
316 irq_set_chip_data(virq, pdata);
317 irq_set_chip_and_handler(virq, &pdata->irq_chip, handle_simple_irq);
311 irq_set_nested_thread(virq, true); 318 irq_set_nested_thread(virq, true);
312 irq_set_parent(virq, twl_irq); 319 irq_set_parent(virq, pdata->twl_irq);
313 320
314#ifdef CONFIG_ARM 321#ifdef CONFIG_ARM
315 /* 322 /*
@@ -349,6 +356,12 @@ int twl6030_init_irq(struct device *dev, int irq_num)
349 356
350 nr_irqs = TWL6030_NR_IRQS; 357 nr_irqs = TWL6030_NR_IRQS;
351 358
359 twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL);
360 if (!twl6030_irq) {
361 dev_err(dev, "twl6030_irq: Memory allocation failed\n");
362 return -ENOMEM;
363 }
364
352 mask[0] = 0xFF; 365 mask[0] = 0xFF;
353 mask[1] = 0xFF; 366 mask[1] = 0xFF;
354 mask[2] = 0xFF; 367 mask[2] = 0xFF;
@@ -369,14 +382,18 @@ int twl6030_init_irq(struct device *dev, int irq_num)
369 * install an irq handler for each of the modules; 382 * install an irq handler for each of the modules;
370 * clone dummy irq_chip since PIH can't *do* anything 383 * clone dummy irq_chip since PIH can't *do* anything
371 */ 384 */
372 twl6030_irq_chip = dummy_irq_chip; 385 twl6030_irq->irq_chip = dummy_irq_chip;
373 twl6030_irq_chip.name = "twl6030"; 386 twl6030_irq->irq_chip.name = "twl6030";
374 twl6030_irq_chip.irq_set_type = NULL; 387 twl6030_irq->irq_chip.irq_set_type = NULL;
375 twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake; 388 twl6030_irq->irq_chip.irq_set_wake = twl6030_irq_set_wake;
376 389
377 irq_domain = irq_domain_add_linear(node, nr_irqs, 390 twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
378 &twl6030_irq_domain_ops, NULL); 391 atomic_set(&twl6030_irq->wakeirqs, 0);
379 if (!irq_domain) { 392
393 twl6030_irq->irq_domain =
394 irq_domain_add_linear(node, nr_irqs,
395 &twl6030_irq_domain_ops, twl6030_irq);
396 if (!twl6030_irq->irq_domain) {
380 dev_err(dev, "Can't add irq_domain\n"); 397 dev_err(dev, "Can't add irq_domain\n");
381 return -ENOMEM; 398 return -ENOMEM;
382 } 399 }
@@ -385,26 +402,26 @@ int twl6030_init_irq(struct device *dev, int irq_num)
385 402
386 /* install an irq handler to demultiplex the TWL6030 interrupt */ 403 /* install an irq handler to demultiplex the TWL6030 interrupt */
387 status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread, 404 status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
388 IRQF_ONESHOT, "TWL6030-PIH", irq_domain); 405 IRQF_ONESHOT, "TWL6030-PIH", twl6030_irq);
389 if (status < 0) { 406 if (status < 0) {
390 dev_err(dev, "could not claim irq %d: %d\n", irq_num, status); 407 dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
391 goto fail_irq; 408 goto fail_irq;
392 } 409 }
393 410
394 twl_irq = irq_num; 411 twl6030_irq->twl_irq = irq_num;
395 register_pm_notifier(&twl6030_irq_pm_notifier_block); 412 register_pm_notifier(&twl6030_irq->pm_nb);
396 return 0; 413 return 0;
397 414
398fail_irq: 415fail_irq:
399 irq_domain_remove(irq_domain); 416 irq_domain_remove(twl6030_irq->irq_domain);
400 return status; 417 return status;
401} 418}
402 419
403int twl6030_exit_irq(void) 420int twl6030_exit_irq(void)
404{ 421{
405 if (twl_irq) { 422 if (twl6030_irq && twl6030_irq->twl_irq) {
406 unregister_pm_notifier(&twl6030_irq_pm_notifier_block); 423 unregister_pm_notifier(&twl6030_irq->pm_nb);
407 free_irq(twl_irq, NULL); 424 free_irq(twl6030_irq->twl_irq, NULL);
408 /* 425 /*
409 * TODO: IRQ domain and allocated nested IRQ descriptors 426 * TODO: IRQ domain and allocated nested IRQ descriptors
410 * should be freed somehow here. Now It can't be done, because 427 * should be freed somehow here. Now It can't be done, because