diff options
Diffstat (limited to 'drivers/mfd/wm831x-irq.c')
-rw-r--r-- | drivers/mfd/wm831x-irq.c | 148 |
1 files changed, 95 insertions, 53 deletions
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index bec4d0539160..804e56ec99eb 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) | |||
328 | static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, | 329 | static 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 | ||
334 | static void wm831x_irq_lock(struct irq_data *data) | 335 | static 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 */ |
@@ -412,22 +413,25 @@ static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) | |||
412 | * do the update here as we can be called with the bus lock | 413 | * do the update here as we can be called with the bus lock |
413 | * held. | 414 | * held. |
414 | */ | 415 | */ |
416 | wm831x->gpio_level_low[irq] = false; | ||
417 | wm831x->gpio_level_high[irq] = false; | ||
415 | switch (type) { | 418 | switch (type) { |
416 | case IRQ_TYPE_EDGE_BOTH: | 419 | case IRQ_TYPE_EDGE_BOTH: |
417 | wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_INT_MODE; | 420 | wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_INT_MODE; |
418 | wm831x->gpio_level[irq] = false; | ||
419 | break; | 421 | break; |
420 | case IRQ_TYPE_EDGE_RISING: | 422 | case IRQ_TYPE_EDGE_RISING: |
421 | wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL; | 423 | wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL; |
422 | wm831x->gpio_level[irq] = false; | ||
423 | break; | 424 | break; |
424 | case IRQ_TYPE_EDGE_FALLING: | 425 | case IRQ_TYPE_EDGE_FALLING: |
425 | wm831x->gpio_update[irq] = 0x10000; | 426 | wm831x->gpio_update[irq] = 0x10000; |
426 | wm831x->gpio_level[irq] = false; | ||
427 | break; | 427 | break; |
428 | case IRQ_TYPE_LEVEL_HIGH: | 428 | case IRQ_TYPE_LEVEL_HIGH: |
429 | wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL; | 429 | wm831x->gpio_update[irq] = 0x10000 | WM831X_GPN_POL; |
430 | wm831x->gpio_level[irq] = true; | 430 | wm831x->gpio_level_high[irq] = true; |
431 | break; | ||
432 | case IRQ_TYPE_LEVEL_LOW: | ||
433 | wm831x->gpio_update[irq] = 0x10000; | ||
434 | wm831x->gpio_level_low[irq] = true; | ||
431 | break; | 435 | break; |
432 | default: | 436 | default: |
433 | return -EINVAL; | 437 | return -EINVAL; |
@@ -469,9 +473,11 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
469 | * descriptors. | 473 | * descriptors. |
470 | */ | 474 | */ |
471 | if (primary & WM831X_TCHPD_INT) | 475 | if (primary & WM831X_TCHPD_INT) |
472 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); | 476 | handle_nested_irq(irq_find_mapping(wm831x->irq_domain, |
477 | WM831X_IRQ_TCHPD)); | ||
473 | if (primary & WM831X_TCHDATA_INT) | 478 | if (primary & WM831X_TCHDATA_INT) |
474 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); | 479 | handle_nested_irq(irq_find_mapping(wm831x->irq_domain, |
480 | WM831X_IRQ_TCHDATA)); | ||
475 | primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); | 481 | primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); |
476 | 482 | ||
477 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { | 483 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { |
@@ -507,16 +513,29 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
507 | } | 513 | } |
508 | 514 | ||
509 | if (*status & wm831x_irqs[i].mask) | 515 | if (*status & wm831x_irqs[i].mask) |
510 | handle_nested_irq(wm831x->irq_base + i); | 516 | handle_nested_irq(irq_find_mapping(wm831x->irq_domain, |
517 | i)); | ||
511 | 518 | ||
512 | /* Simulate an edge triggered IRQ by polling the input | 519 | /* Simulate an edge triggered IRQ by polling the input |
513 | * status. This is sucky but improves interoperability. | 520 | * status. This is sucky but improves interoperability. |
514 | */ | 521 | */ |
515 | if (primary == WM831X_GP_INT && | 522 | if (primary == WM831X_GP_INT && |
516 | wm831x->gpio_level[i - WM831X_IRQ_GPIO_1]) { | 523 | wm831x->gpio_level_high[i - WM831X_IRQ_GPIO_1]) { |
517 | ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL); | 524 | ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL); |
518 | while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) { | 525 | while (ret & 1 << (i - WM831X_IRQ_GPIO_1)) { |
519 | handle_nested_irq(wm831x->irq_base + i); | 526 | handle_nested_irq(irq_find_mapping(wm831x->irq_domain, |
527 | i)); | ||
528 | ret = wm831x_reg_read(wm831x, | ||
529 | WM831X_GPIO_LEVEL); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | if (primary == WM831X_GP_INT && | ||
534 | wm831x->gpio_level_low[i - WM831X_IRQ_GPIO_1]) { | ||
535 | ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL); | ||
536 | while (!(ret & 1 << (i - WM831X_IRQ_GPIO_1))) { | ||
537 | handle_nested_irq(irq_find_mapping(wm831x->irq_domain, | ||
538 | i)); | ||
520 | ret = wm831x_reg_read(wm831x, | 539 | ret = wm831x_reg_read(wm831x, |
521 | WM831X_GPIO_LEVEL); | 540 | WM831X_GPIO_LEVEL); |
522 | } | 541 | } |
@@ -527,10 +546,34 @@ out: | |||
527 | return IRQ_HANDLED; | 546 | return IRQ_HANDLED; |
528 | } | 547 | } |
529 | 548 | ||
549 | static int wm831x_irq_map(struct irq_domain *h, unsigned int virq, | ||
550 | irq_hw_number_t hw) | ||
551 | { | ||
552 | irq_set_chip_data(virq, h->host_data); | ||
553 | irq_set_chip_and_handler(virq, &wm831x_irq_chip, handle_edge_irq); | ||
554 | irq_set_nested_thread(virq, 1); | ||
555 | |||
556 | /* ARM needs us to explicitly flag the IRQ as valid | ||
557 | * and will set them noprobe when we do so. */ | ||
558 | #ifdef CONFIG_ARM | ||
559 | set_irq_flags(virq, IRQF_VALID); | ||
560 | #else | ||
561 | irq_set_noprobe(virq); | ||
562 | #endif | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static struct irq_domain_ops wm831x_irq_domain_ops = { | ||
568 | .map = wm831x_irq_map, | ||
569 | .xlate = irq_domain_xlate_twocell, | ||
570 | }; | ||
571 | |||
530 | int wm831x_irq_init(struct wm831x *wm831x, int irq) | 572 | int wm831x_irq_init(struct wm831x *wm831x, int irq) |
531 | { | 573 | { |
532 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; | 574 | struct wm831x_pdata *pdata = wm831x->dev->platform_data; |
533 | int i, cur_irq, ret; | 575 | struct irq_domain *domain; |
576 | int i, ret, irq_base; | ||
534 | 577 | ||
535 | mutex_init(&wm831x->irq_lock); | 578 | mutex_init(&wm831x->irq_lock); |
536 | 579 | ||
@@ -543,18 +586,33 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
543 | } | 586 | } |
544 | 587 | ||
545 | /* Try to dynamically allocate IRQs if no base is specified */ | 588 | /* Try to dynamically allocate IRQs if no base is specified */ |
546 | if (!pdata || !pdata->irq_base) | 589 | if (pdata && pdata->irq_base) { |
547 | wm831x->irq_base = -1; | 590 | irq_base = irq_alloc_descs(pdata->irq_base, 0, |
591 | WM831X_NUM_IRQS, 0); | ||
592 | if (irq_base < 0) { | ||
593 | dev_warn(wm831x->dev, "Failed to allocate IRQs: %d\n", | ||
594 | irq_base); | ||
595 | irq_base = 0; | ||
596 | } | ||
597 | } else { | ||
598 | irq_base = 0; | ||
599 | } | ||
600 | |||
601 | if (irq_base) | ||
602 | domain = irq_domain_add_legacy(wm831x->dev->of_node, | ||
603 | ARRAY_SIZE(wm831x_irqs), | ||
604 | irq_base, 0, | ||
605 | &wm831x_irq_domain_ops, | ||
606 | wm831x); | ||
548 | else | 607 | else |
549 | wm831x->irq_base = pdata->irq_base; | 608 | domain = irq_domain_add_linear(wm831x->dev->of_node, |
609 | ARRAY_SIZE(wm831x_irqs), | ||
610 | &wm831x_irq_domain_ops, | ||
611 | wm831x); | ||
550 | 612 | ||
551 | wm831x->irq_base = irq_alloc_descs(wm831x->irq_base, 0, | 613 | if (!domain) { |
552 | WM831X_NUM_IRQS, 0); | 614 | dev_warn(wm831x->dev, "Failed to allocate IRQ domain\n"); |
553 | if (wm831x->irq_base < 0) { | 615 | 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 | } | 616 | } |
559 | 617 | ||
560 | if (pdata && pdata->irq_cmos) | 618 | if (pdata && pdata->irq_cmos) |
@@ -565,38 +623,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
565 | wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, | 623 | wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, |
566 | WM831X_IRQ_OD, i); | 624 | WM831X_IRQ_OD, i); |
567 | 625 | ||
568 | /* Try to flag /IRQ as a wake source; there are a number of | ||
569 | * unconditional wake sources in the PMIC so this isn't | ||
570 | * conditional but we don't actually care *too* much if it | ||
571 | * fails. | ||
572 | */ | ||
573 | ret = enable_irq_wake(irq); | ||
574 | if (ret != 0) { | ||
575 | dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n", | ||
576 | ret); | ||
577 | } | ||
578 | |||
579 | wm831x->irq = irq; | 626 | wm831x->irq = irq; |
580 | 627 | wm831x->irq_domain = domain; | |
581 | /* Register them with genirq */ | ||
582 | for (cur_irq = wm831x->irq_base; | ||
583 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; | ||
584 | cur_irq++) { | ||
585 | irq_set_chip_data(cur_irq, wm831x); | ||
586 | irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip, | ||
587 | handle_edge_irq); | ||
588 | irq_set_nested_thread(cur_irq, 1); | ||
589 | |||
590 | /* ARM needs us to explicitly flag the IRQ as valid | ||
591 | * and will set them noprobe when we do so. */ | ||
592 | #ifdef CONFIG_ARM | ||
593 | set_irq_flags(cur_irq, IRQF_VALID); | ||
594 | #else | ||
595 | irq_set_noprobe(cur_irq); | ||
596 | #endif | ||
597 | } | ||
598 | 628 | ||
599 | if (irq) { | 629 | if (irq) { |
630 | /* Try to flag /IRQ as a wake source; there are a number of | ||
631 | * unconditional wake sources in the PMIC so this isn't | ||
632 | * conditional but we don't actually care *too* much if it | ||
633 | * fails. | ||
634 | */ | ||
635 | ret = enable_irq_wake(irq); | ||
636 | if (ret != 0) { | ||
637 | dev_warn(wm831x->dev, | ||
638 | "Can't enable IRQ as wake source: %d\n", | ||
639 | ret); | ||
640 | } | ||
641 | |||
600 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, | 642 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, |
601 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 643 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
602 | "wm831x", wm831x); | 644 | "wm831x", wm831x); |