aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mfd/twl6030-irq.c119
1 files changed, 69 insertions, 50 deletions
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index f7da2614de80..1b03ce9e9f15 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -86,11 +86,11 @@ static int twl6030_interrupt_mapping[24] = {
86}; 86};
87/*----------------------------------------------------------------------*/ 87/*----------------------------------------------------------------------*/
88 88
89static unsigned twl6030_irq_base;
90static int twl_irq; 89static int twl_irq;
91static bool twl_irq_wake_enabled; 90static bool twl_irq_wake_enabled;
92 91
93static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); 92static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
93struct irq_domain *irq_domain;
94 94
95static int twl6030_irq_pm_notifier(struct notifier_block *notifier, 95static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
96 unsigned long pm_event, void *unused) 96 unsigned long pm_event, void *unused)
@@ -138,6 +138,7 @@ static struct notifier_block twl6030_irq_pm_notifier_block = {
138static irqreturn_t twl6030_irq_thread(int irq, void *data) 138static irqreturn_t twl6030_irq_thread(int irq, void *data)
139{ 139{
140 int i, ret; 140 int i, ret;
141 struct irq_domain *irq_domain = (struct irq_domain *)data;
141 union { 142 union {
142 u8 bytes[4]; 143 u8 bytes[4];
143 u32 int_sts; 144 u32 int_sts;
@@ -161,9 +162,14 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
161 162
162 for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) 163 for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
163 if (sts.int_sts & 0x1) { 164 if (sts.int_sts & 0x1) {
164 int module_irq = twl6030_irq_base + 165 int module_irq =
165 twl6030_interrupt_mapping[i]; 166 irq_find_mapping(irq_domain,
166 handle_nested_irq(module_irq); 167 twl6030_interrupt_mapping[i]);
168 if (module_irq)
169 handle_nested_irq(module_irq);
170 else
171 pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n",
172 i);
167 pr_debug("twl6030_irq: PIH ISR %u, virq%u\n", 173 pr_debug("twl6030_irq: PIH ISR %u, virq%u\n",
168 i, module_irq); 174 i, module_irq);
169 } 175 }
@@ -186,19 +192,6 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data)
186 192
187/*----------------------------------------------------------------------*/ 193/*----------------------------------------------------------------------*/
188 194
189static inline void activate_irq(int irq)
190{
191#ifdef CONFIG_ARM
192 /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
193 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
194 */
195 set_irq_flags(irq, IRQF_VALID);
196#else
197 /* same effect on other architectures */
198 irq_set_noprobe(irq);
199#endif
200}
201
202static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) 195static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
203{ 196{
204 if (on) 197 if (on)
@@ -279,7 +272,7 @@ int twl6030_mmc_card_detect_config(void)
279 return ret; 272 return ret;
280 } 273 }
281 274
282 return twl6030_irq_base + MMCDETECT_INTR_OFFSET; 275 return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET);
283} 276}
284EXPORT_SYMBOL(twl6030_mmc_card_detect_config); 277EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
285 278
@@ -308,28 +301,54 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
308} 301}
309EXPORT_SYMBOL(twl6030_mmc_card_detect); 302EXPORT_SYMBOL(twl6030_mmc_card_detect);
310 303
304static struct irq_chip twl6030_irq_chip;
305
306static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
307 irq_hw_number_t hwirq)
308{
309 irq_set_chip_data(virq, &twl6030_irq_chip);
310 irq_set_chip_and_handler(virq, &twl6030_irq_chip, handle_simple_irq);
311 irq_set_nested_thread(virq, true);
312 irq_set_parent(virq, twl_irq);
313
314#ifdef CONFIG_ARM
315 /*
316 * ARM requires an extra step to clear IRQ_NOREQUEST, which it
317 * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE.
318 */
319 set_irq_flags(virq, IRQF_VALID);
320#else
321 /* same effect on other architectures */
322 irq_set_noprobe(virq);
323#endif
324
325 return 0;
326}
327
328static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq)
329{
330#ifdef CONFIG_ARM
331 set_irq_flags(virq, 0);
332#endif
333 irq_set_chip_and_handler(virq, NULL, NULL);
334 irq_set_chip_data(virq, NULL);
335}
336
337static struct irq_domain_ops twl6030_irq_domain_ops = {
338 .map = twl6030_irq_map,
339 .unmap = twl6030_irq_unmap,
340 .xlate = irq_domain_xlate_onetwocell,
341};
342
311int twl6030_init_irq(struct device *dev, int irq_num) 343int twl6030_init_irq(struct device *dev, int irq_num)
312{ 344{
313 struct device_node *node = dev->of_node; 345 struct device_node *node = dev->of_node;
314 int nr_irqs, irq_base, irq_end; 346 int nr_irqs;
315 static struct irq_chip twl6030_irq_chip;
316 int status; 347 int status;
317 int i;
318 u8 mask[3]; 348 u8 mask[3];
319 349
320 nr_irqs = TWL6030_NR_IRQS; 350 nr_irqs = TWL6030_NR_IRQS;
321 351
322 irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
323 if (IS_ERR_VALUE(irq_base)) {
324 dev_err(dev, "Fail to allocate IRQ descs\n");
325 return irq_base;
326 }
327
328 irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
329 &irq_domain_simple_ops, NULL);
330
331 irq_end = irq_base + nr_irqs;
332
333 mask[0] = 0xFF; 352 mask[0] = 0xFF;
334 mask[1] = 0xFF; 353 mask[1] = 0xFF;
335 mask[2] = 0xFF; 354 mask[2] = 0xFF;
@@ -346,8 +365,6 @@ int twl6030_init_irq(struct device *dev, int irq_num)
346 return status; 365 return status;
347 } 366 }
348 367
349 twl6030_irq_base = irq_base;
350
351 /* 368 /*
352 * install an irq handler for each of the modules; 369 * install an irq handler for each of the modules;
353 * clone dummy irq_chip since PIH can't *do* anything 370 * clone dummy irq_chip since PIH can't *do* anything
@@ -357,21 +374,18 @@ int twl6030_init_irq(struct device *dev, int irq_num)
357 twl6030_irq_chip.irq_set_type = NULL; 374 twl6030_irq_chip.irq_set_type = NULL;
358 twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake; 375 twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
359 376
360 for (i = irq_base; i < irq_end; i++) { 377 irq_domain = irq_domain_add_linear(node, nr_irqs,
361 irq_set_chip_and_handler(i, &twl6030_irq_chip, 378 &twl6030_irq_domain_ops, NULL);
362 handle_simple_irq); 379 if (!irq_domain) {
363 irq_set_chip_data(i, (void *)irq_num); 380 dev_err(dev, "Can't add irq_domain\n");
364 irq_set_nested_thread(i, true); 381 return -ENOMEM;
365 irq_set_parent(i, irq_num);
366 activate_irq(i);
367 } 382 }
368 383
369 dev_info(dev, "PIH (irq %d) nested IRQs %d..%d\n", 384 dev_info(dev, "PIH (irq %d) nested IRQs\n", irq_num);
370 irq_num, irq_base, irq_end);
371 385
372 /* install an irq handler to demultiplex the TWL6030 interrupt */ 386 /* install an irq handler to demultiplex the TWL6030 interrupt */
373 status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread, 387 status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
374 IRQF_ONESHOT, "TWL6030-PIH", NULL); 388 IRQF_ONESHOT, "TWL6030-PIH", irq_domain);
375 if (status < 0) { 389 if (status < 0) {
376 dev_err(dev, "could not claim irq %d: %d\n", irq_num, status); 390 dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
377 goto fail_irq; 391 goto fail_irq;
@@ -379,23 +393,28 @@ int twl6030_init_irq(struct device *dev, int irq_num)
379 393
380 twl_irq = irq_num; 394 twl_irq = irq_num;
381 register_pm_notifier(&twl6030_irq_pm_notifier_block); 395 register_pm_notifier(&twl6030_irq_pm_notifier_block);
382 return irq_base; 396 return 0;
383 397
384fail_irq: 398fail_irq:
385 for (i = irq_base; i < irq_end; i++) 399 irq_domain_remove(irq_domain);
386 irq_set_chip_and_handler(i, NULL, NULL);
387
388 return status; 400 return status;
389} 401}
390 402
391int twl6030_exit_irq(void) 403int twl6030_exit_irq(void)
392{ 404{
393
394 if (twl_irq) { 405 if (twl_irq) {
395 unregister_pm_notifier(&twl6030_irq_pm_notifier_block); 406 unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
396 free_irq(twl_irq, NULL); 407 free_irq(twl_irq, NULL);
408 /*
409 * TODO: IRQ domain and allocated nested IRQ descriptors
410 * should be freed somehow here. Now It can't be done, because
411 * child devices will not be deleted during removing of
412 * TWL Core driver and they will still contain allocated
413 * virt IRQs in their Resources tables.
414 * The same prevents us from using devm_request_threaded_irq()
415 * in this module.
416 */
397 } 417 }
398
399 return 0; 418 return 0;
400} 419}
401 420