aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/wm831x-irq.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-05-14 17:14:24 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-05-20 11:27:07 -0400
commitcd99758ba3bde64347a8ece381cbae2fb5c745b2 (patch)
treece74c5150978f1cd29861e33e8847bc5dd667ed7 /drivers/mfd/wm831x-irq.c
parent4492c4c3ff7bbb5fd400f021532643a3493f0723 (diff)
mfd: Convert wm831x to irq_domain
The modern idiom is to use irq_domain to allocate interrupts. This is useful partly to allow further infrastructure to be based on the domains and partly because it makes it much easier to allocate virtual interrupts to devices as we don't need to allocate a contiguous range of interrupt numbers. Convert the wm831x driver over to this infrastructure, using a legacy IRQ mapping if an irq_base is specified in platform data and otherwise using a linear mapping, always registering the interrupts even if they won't ever be used. Only boards which need to use the GPIOs as interrupts should need to use an irq_base. This means that we can't use the MFD irq_base management since the unless we're using an explicit irq_base from platform data we can't rely on a linear mapping of interrupts. Instead we need to map things via the irq_domain - provide a conveniencem function wm831x_irq() to save a small amount of typing when doing so. Looking at this I couldn't clearly see anything the MFD core could do to make this nicer. Since we're not supporting device tree yet there's no meaningful advantage if we don't do this conversion in one, the fact that the interrupt resources are used for repeated IP blocks makes accessor functions for the irq_domain more trouble to do than they're worth. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/wm831x-irq.c')
-rw-r--r--drivers/mfd/wm831x-irq.c101
1 files changed, 64 insertions, 37 deletions
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 2be9628074bd..ecc9d6d62fad 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -18,6 +18,7 @@
18#include <linux/irq.h> 18#include <linux/irq.h>
19#include <linux/mfd/core.h> 19#include <linux/mfd/core.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/irqdomain.h>
21 22
22#include <linux/mfd/wm831x/core.h> 23#include <linux/mfd/wm831x/core.h>
23#include <linux/mfd/wm831x/pdata.h> 24#include <linux/mfd/wm831x/pdata.h>
@@ -328,7 +329,7 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data)
328static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, 329static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
329 int irq) 330 int irq)
330{ 331{
331 return &wm831x_irqs[irq - wm831x->irq_base]; 332 return &wm831x_irqs[irq];
332} 333}
333 334
334static void wm831x_irq_lock(struct irq_data *data) 335static void wm831x_irq_lock(struct irq_data *data)
@@ -374,7 +375,7 @@ static void wm831x_irq_enable(struct irq_data *data)
374{ 375{
375 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 376 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
376 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, 377 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
377 data->irq); 378 data->hwirq);
378 379
379 wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; 380 wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
380} 381}
@@ -383,7 +384,7 @@ static void wm831x_irq_disable(struct irq_data *data)
383{ 384{
384 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 385 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
385 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, 386 struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x,
386 data->irq); 387 data->hwirq);
387 388
388 wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; 389 wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
389} 390}
@@ -393,7 +394,7 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type)
393 struct wm831x *wm831x = irq_data_get_irq_chip_data(data); 394 struct wm831x *wm831x = irq_data_get_irq_chip_data(data);
394 int irq; 395 int irq;
395 396
396 irq = data->irq - wm831x->irq_base; 397 irq = data->hwirq;
397 398
398 if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { 399 if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) {
399 /* Ignore internal-only IRQs */ 400 /* Ignore internal-only IRQs */
@@ -469,9 +470,11 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
469 * descriptors. 470 * descriptors.
470 */ 471 */
471 if (primary & WM831X_TCHPD_INT) 472 if (primary & WM831X_TCHPD_INT)
472 handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); 473 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
474 WM831X_IRQ_TCHPD));
473 if (primary & WM831X_TCHDATA_INT) 475 if (primary & WM831X_TCHDATA_INT)
474 handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); 476 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
477 WM831X_IRQ_TCHDATA));
475 primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); 478 primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
476 479
477 for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { 480 for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
@@ -507,7 +510,8 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
507 } 510 }
508 511
509 if (*status & wm831x_irqs[i].mask) 512 if (*status & wm831x_irqs[i].mask)
510 handle_nested_irq(wm831x->irq_base + i); 513 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
514 i));
511 515
512 /* Simulate an edge triggered IRQ by polling the input 516 /* Simulate an edge triggered IRQ by polling the input
513 * status. This is sucky but improves interoperability. 517 * status. This is sucky but improves interoperability.
@@ -516,7 +520,8 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
516 wm831x->gpio_level[i - WM831X_IRQ_GPIO_1]) { 520 wm831x->gpio_level[i - WM831X_IRQ_GPIO_1]) {
517 ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL); 521 ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL);
518 while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) { 522 while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) {
519 handle_nested_irq(wm831x->irq_base + i); 523 handle_nested_irq(irq_find_mapping(wm831x->irq_domain,
524 i));
520 ret = wm831x_reg_read(wm831x, 525 ret = wm831x_reg_read(wm831x,
521 WM831X_GPIO_LEVEL); 526 WM831X_GPIO_LEVEL);
522 } 527 }
@@ -527,10 +532,34 @@ out:
527 return IRQ_HANDLED; 532 return IRQ_HANDLED;
528} 533}
529 534
535static int wm831x_irq_map(struct irq_domain *h, unsigned int virq,
536 irq_hw_number_t hw)
537{
538 irq_set_chip_data(virq, h->host_data);
539 irq_set_chip_and_handler(virq, &wm831x_irq_chip, handle_edge_irq);
540 irq_set_nested_thread(virq, 1);
541
542 /* ARM needs us to explicitly flag the IRQ as valid
543 * and will set them noprobe when we do so. */
544#ifdef CONFIG_ARM
545 set_irq_flags(virq, IRQF_VALID);
546#else
547 irq_set_noprobe(virq);
548#endif
549
550 return 0;
551}
552
553static struct irq_domain_ops wm831x_irq_domain_ops = {
554 .map = wm831x_irq_map,
555 .xlate = irq_domain_xlate_twocell,
556};
557
530int wm831x_irq_init(struct wm831x *wm831x, int irq) 558int wm831x_irq_init(struct wm831x *wm831x, int irq)
531{ 559{
532 struct wm831x_pdata *pdata = wm831x->dev->platform_data; 560 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
533 int i, cur_irq, ret; 561 struct irq_domain *domain;
562 int i, ret, irq_base;
534 563
535 mutex_init(&wm831x->irq_lock); 564 mutex_init(&wm831x->irq_lock);
536 565
@@ -543,18 +572,33 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
543 } 572 }
544 573
545 /* Try to dynamically allocate IRQs if no base is specified */ 574 /* Try to dynamically allocate IRQs if no base is specified */
546 if (!pdata || !pdata->irq_base) 575 if (pdata && pdata->irq_base) {
547 wm831x->irq_base = -1; 576 irq_base = irq_alloc_descs(pdata->irq_base, 0,
577 WM831X_NUM_IRQS, 0);
578 if (irq_base < 0) {
579 dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
580 irq_base);
581 irq_base = 0;
582 }
583 } else {
584 irq_base = 0;
585 }
586
587 if (irq_base)
588 domain = irq_domain_add_legacy(wm831x->dev->of_node,
589 ARRAY_SIZE(wm831x_irqs),
590 irq_base, 0,
591 &wm831x_irq_domain_ops,
592 wm831x);
548 else 593 else
549 wm831x->irq_base = pdata->irq_base; 594 domain = irq_domain_add_linear(wm831x->dev->of_node,
595 ARRAY_SIZE(wm831x_irqs),
596 &wm831x_irq_domain_ops,
597 wm831x);
550 598
551 wm831x->irq_base = irq_alloc_descs(wm831x->irq_base, 0, 599 if (!domain) {
552 WM831X_NUM_IRQS, 0); 600 dev_warn(wm831x->dev, "Failed to allocate IRQ domain\n");
553 if (wm831x->irq_base < 0) { 601 return -EINVAL;
554 dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n",
555 wm831x->irq_base);
556 wm831x->irq_base = 0;
557 return 0;
558 } 602 }
559 603
560 if (pdata && pdata->irq_cmos) 604 if (pdata && pdata->irq_cmos)
@@ -566,24 +610,7 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
566 WM831X_IRQ_OD, i); 610 WM831X_IRQ_OD, i);
567 611
568 wm831x->irq = irq; 612 wm831x->irq = irq;
569 613 wm831x->irq_domain = domain;
570 /* Register them with genirq */
571 for (cur_irq = wm831x->irq_base;
572 cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base;
573 cur_irq++) {
574 irq_set_chip_data(cur_irq, wm831x);
575 irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip,
576 handle_edge_irq);
577 irq_set_nested_thread(cur_irq, 1);
578
579 /* ARM needs us to explicitly flag the IRQ as valid
580 * and will set them noprobe when we do so. */
581#ifdef CONFIG_ARM
582 set_irq_flags(cur_irq, IRQF_VALID);
583#else
584 irq_set_noprobe(cur_irq);
585#endif
586 }
587 614
588 if (irq) { 615 if (irq) {
589 /* Try to flag /IRQ as a wake source; there are a number of 616 /* Try to flag /IRQ as a wake source; there are a number of