diff options
-rw-r--r-- | drivers/mfd/wm8350-irq.c | 155 | ||||
-rw-r--r-- | include/linux/mfd/wm8350/core.h | 44 |
2 files changed, 118 insertions, 81 deletions
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 655836bc69a0..f56c9adf9493 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/bug.h> | 18 | #include <linux/bug.h> |
19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/workqueue.h> | 21 | #include <linux/irq.h> |
22 | 22 | ||
23 | #include <linux/mfd/wm8350/core.h> | 23 | #include <linux/mfd/wm8350/core.h> |
24 | #include <linux/mfd/wm8350/audio.h> | 24 | #include <linux/mfd/wm8350/audio.h> |
@@ -29,8 +29,6 @@ | |||
29 | #include <linux/mfd/wm8350/supply.h> | 29 | #include <linux/mfd/wm8350/supply.h> |
30 | #include <linux/mfd/wm8350/wdt.h> | 30 | #include <linux/mfd/wm8350/wdt.h> |
31 | 31 | ||
32 | #define WM8350_NUM_IRQ_REGS 7 | ||
33 | |||
34 | #define WM8350_INT_OFFSET_1 0 | 32 | #define WM8350_INT_OFFSET_1 0 |
35 | #define WM8350_INT_OFFSET_2 1 | 33 | #define WM8350_INT_OFFSET_2 1 |
36 | #define WM8350_POWER_UP_INT_OFFSET 2 | 34 | #define WM8350_POWER_UP_INT_OFFSET 2 |
@@ -366,19 +364,10 @@ static struct wm8350_irq_data wm8350_irqs[] = { | |||
366 | }, | 364 | }, |
367 | }; | 365 | }; |
368 | 366 | ||
369 | static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) | 367 | static inline struct wm8350_irq_data *irq_to_wm8350_irq(struct wm8350 *wm8350, |
368 | int irq) | ||
370 | { | 369 | { |
371 | mutex_lock(&wm8350->irq_mutex); | 370 | return &wm8350_irqs[irq - wm8350->irq_base]; |
372 | |||
373 | if (wm8350->irq[irq].handler) | ||
374 | wm8350->irq[irq].handler(irq, wm8350->irq[irq].data); | ||
375 | else { | ||
376 | dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n", | ||
377 | irq); | ||
378 | wm8350_mask_irq(wm8350, irq); | ||
379 | } | ||
380 | |||
381 | mutex_unlock(&wm8350->irq_mutex); | ||
382 | } | 371 | } |
383 | 372 | ||
384 | /* | 373 | /* |
@@ -386,7 +375,9 @@ static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) | |||
386 | * interrupts are clear on read the IRQ line will be reasserted and | 375 | * interrupts are clear on read the IRQ line will be reasserted and |
387 | * the physical IRQ will be handled again if another interrupt is | 376 | * the physical IRQ will be handled again if another interrupt is |
388 | * asserted while we run - in the normal course of events this is a | 377 | * asserted while we run - in the normal course of events this is a |
389 | * rare occurrence so we save I2C/SPI reads. | 378 | * rare occurrence so we save I2C/SPI reads. We're also assuming that |
379 | * it's rare to get lots of interrupts firing simultaneously so try to | ||
380 | * minimise I/O. | ||
390 | */ | 381 | */ |
391 | static irqreturn_t wm8350_irq(int irq, void *irq_data) | 382 | static irqreturn_t wm8350_irq(int irq, void *irq_data) |
392 | { | 383 | { |
@@ -397,7 +388,6 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data) | |||
397 | struct wm8350_irq_data *data; | 388 | struct wm8350_irq_data *data; |
398 | int i; | 389 | int i; |
399 | 390 | ||
400 | /* TODO: Use block reads to improve performance? */ | ||
401 | level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) | 391 | level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS) |
402 | & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); | 392 | & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK); |
403 | 393 | ||
@@ -416,93 +406,101 @@ static irqreturn_t wm8350_irq(int irq, void *irq_data) | |||
416 | sub_reg[data->reg] = | 406 | sub_reg[data->reg] = |
417 | wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 + | 407 | wm8350_reg_read(wm8350, WM8350_INT_STATUS_1 + |
418 | data->reg); | 408 | data->reg); |
419 | sub_reg[data->reg] &= | 409 | sub_reg[data->reg] &= ~wm8350->irq_masks[data->reg]; |
420 | ~wm8350_reg_read(wm8350, | ||
421 | WM8350_INT_STATUS_1_MASK + | ||
422 | data->reg); | ||
423 | read_done[data->reg] = 1; | 410 | read_done[data->reg] = 1; |
424 | } | 411 | } |
425 | 412 | ||
426 | if (sub_reg[data->reg] & data->mask) | 413 | if (sub_reg[data->reg] & data->mask) |
427 | wm8350_irq_call_handler(wm8350, i); | 414 | handle_nested_irq(wm8350->irq_base + i); |
428 | } | 415 | } |
429 | 416 | ||
430 | return IRQ_HANDLED; | 417 | return IRQ_HANDLED; |
431 | } | 418 | } |
432 | 419 | ||
433 | int wm8350_register_irq(struct wm8350 *wm8350, int irq, | 420 | static void wm8350_irq_lock(unsigned int irq) |
434 | irq_handler_t handler, unsigned long flags, | ||
435 | const char *name, void *data) | ||
436 | { | 421 | { |
437 | if (irq < 0 || irq >= WM8350_NUM_IRQ || !handler) | 422 | struct wm8350 *wm8350 = get_irq_chip_data(irq); |
438 | return -EINVAL; | ||
439 | |||
440 | if (wm8350->irq[irq].handler) | ||
441 | return -EBUSY; | ||
442 | |||
443 | mutex_lock(&wm8350->irq_mutex); | ||
444 | wm8350->irq[irq].handler = handler; | ||
445 | wm8350->irq[irq].data = data; | ||
446 | mutex_unlock(&wm8350->irq_mutex); | ||
447 | |||
448 | wm8350_unmask_irq(wm8350, irq); | ||
449 | 423 | ||
450 | return 0; | 424 | mutex_lock(&wm8350->irq_lock); |
451 | } | 425 | } |
452 | EXPORT_SYMBOL_GPL(wm8350_register_irq); | ||
453 | 426 | ||
454 | int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) | 427 | static void wm8350_irq_sync_unlock(unsigned int irq) |
455 | { | 428 | { |
456 | if (irq < 0 || irq >= WM8350_NUM_IRQ) | 429 | struct wm8350 *wm8350 = get_irq_chip_data(irq); |
457 | return -EINVAL; | 430 | int i; |
458 | 431 | ||
459 | wm8350_mask_irq(wm8350, irq); | 432 | for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { |
433 | /* If there's been a change in the mask write it back | ||
434 | * to the hardware. */ | ||
435 | if (wm8350->irq_masks[i] != | ||
436 | wm8350->reg_cache[WM8350_INT_STATUS_1_MASK + i]) | ||
437 | WARN_ON(wm8350_reg_write(wm8350, | ||
438 | WM8350_INT_STATUS_1_MASK + i, | ||
439 | wm8350->irq_masks[i])); | ||
440 | } | ||
460 | 441 | ||
461 | mutex_lock(&wm8350->irq_mutex); | 442 | mutex_unlock(&wm8350->irq_lock); |
462 | wm8350->irq[irq].handler = NULL; | ||
463 | mutex_unlock(&wm8350->irq_mutex); | ||
464 | return 0; | ||
465 | } | 443 | } |
466 | EXPORT_SYMBOL_GPL(wm8350_free_irq); | ||
467 | 444 | ||
468 | int wm8350_mask_irq(struct wm8350 *wm8350, int irq) | 445 | static void wm8350_irq_enable(unsigned int irq) |
469 | { | 446 | { |
470 | return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK + | 447 | struct wm8350 *wm8350 = get_irq_chip_data(irq); |
471 | wm8350_irqs[irq].reg, | 448 | struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); |
472 | wm8350_irqs[irq].mask); | 449 | |
450 | wm8350->irq_masks[irq_data->reg] &= ~irq_data->mask; | ||
473 | } | 451 | } |
474 | EXPORT_SYMBOL_GPL(wm8350_mask_irq); | ||
475 | 452 | ||
476 | int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) | 453 | static void wm8350_irq_disable(unsigned int irq) |
477 | { | 454 | { |
478 | return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK + | 455 | struct wm8350 *wm8350 = get_irq_chip_data(irq); |
479 | wm8350_irqs[irq].reg, | 456 | struct wm8350_irq_data *irq_data = irq_to_wm8350_irq(wm8350, irq); |
480 | wm8350_irqs[irq].mask); | 457 | |
458 | wm8350->irq_masks[irq_data->reg] |= irq_data->mask; | ||
481 | } | 459 | } |
482 | EXPORT_SYMBOL_GPL(wm8350_unmask_irq); | 460 | |
461 | static struct irq_chip wm8350_irq_chip = { | ||
462 | .name = "wm8350", | ||
463 | .bus_lock = wm8350_irq_lock, | ||
464 | .bus_sync_unlock = wm8350_irq_sync_unlock, | ||
465 | .disable = wm8350_irq_disable, | ||
466 | .enable = wm8350_irq_enable, | ||
467 | }; | ||
483 | 468 | ||
484 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, | 469 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, |
485 | struct wm8350_platform_data *pdata) | 470 | struct wm8350_platform_data *pdata) |
486 | { | 471 | { |
487 | int ret; | 472 | int ret, cur_irq, i; |
488 | int flags = IRQF_ONESHOT; | 473 | int flags = IRQF_ONESHOT; |
489 | 474 | ||
490 | if (!irq) { | 475 | if (!irq) { |
491 | dev_err(wm8350->dev, "No IRQ configured\n"); | 476 | dev_warn(wm8350->dev, "No interrupt support, no core IRQ\n"); |
492 | return -EINVAL; | 477 | return 0; |
478 | } | ||
479 | |||
480 | if (!pdata || !pdata->irq_base) { | ||
481 | dev_warn(wm8350->dev, "No interrupt support, no IRQ base\n"); | ||
482 | return 0; | ||
493 | } | 483 | } |
494 | 484 | ||
485 | /* Mask top level interrupts */ | ||
495 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); | 486 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF); |
496 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF); | ||
497 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF); | ||
498 | wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF); | ||
499 | wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF); | ||
500 | wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF); | ||
501 | 487 | ||
502 | mutex_init(&wm8350->irq_mutex); | 488 | /* Mask all individual interrupts by default and cache the |
489 | * masks. We read the masks back since there are unwritable | ||
490 | * bits in the mask registers. */ | ||
491 | for (i = 0; i < ARRAY_SIZE(wm8350->irq_masks); i++) { | ||
492 | wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK + i, | ||
493 | 0xFFFF); | ||
494 | wm8350->irq_masks[i] = | ||
495 | wm8350_reg_read(wm8350, | ||
496 | WM8350_INT_STATUS_1_MASK + i); | ||
497 | } | ||
498 | |||
499 | mutex_init(&wm8350->irq_lock); | ||
503 | wm8350->chip_irq = irq; | 500 | wm8350->chip_irq = irq; |
501 | wm8350->irq_base = pdata->irq_base; | ||
504 | 502 | ||
505 | if (pdata && pdata->irq_high) { | 503 | if (pdata->irq_high) { |
506 | flags |= IRQF_TRIGGER_HIGH; | 504 | flags |= IRQF_TRIGGER_HIGH; |
507 | 505 | ||
508 | wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, | 506 | wm8350_set_bits(wm8350, WM8350_SYSTEM_CONTROL_1, |
@@ -514,11 +512,32 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq, | |||
514 | WM8350_IRQ_POL); | 512 | WM8350_IRQ_POL); |
515 | } | 513 | } |
516 | 514 | ||
515 | /* Register with genirq */ | ||
516 | for (cur_irq = wm8350->irq_base; | ||
517 | cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; | ||
518 | cur_irq++) { | ||
519 | set_irq_chip_data(cur_irq, wm8350); | ||
520 | set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip, | ||
521 | handle_edge_irq); | ||
522 | set_irq_nested_thread(cur_irq, 1); | ||
523 | |||
524 | /* ARM needs us to explicitly flag the IRQ as valid | ||
525 | * and will set them noprobe when we do so. */ | ||
526 | #ifdef CONFIG_ARM | ||
527 | set_irq_flags(cur_irq, IRQF_VALID); | ||
528 | #else | ||
529 | set_irq_noprobe(cur_irq); | ||
530 | #endif | ||
531 | } | ||
532 | |||
517 | ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, | 533 | ret = request_threaded_irq(irq, NULL, wm8350_irq, flags, |
518 | "wm8350", wm8350); | 534 | "wm8350", wm8350); |
519 | if (ret != 0) | 535 | if (ret != 0) |
520 | dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret); | 536 | dev_err(wm8350->dev, "Failed to request IRQ: %d\n", ret); |
521 | 537 | ||
538 | /* Allow interrupts to fire */ | ||
539 | wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0); | ||
540 | |||
522 | return ret; | 541 | return ret; |
523 | } | 542 | } |
524 | 543 | ||
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h index 8883125ddea1..04217a71f173 100644 --- a/include/linux/mfd/wm8350/core.h +++ b/include/linux/mfd/wm8350/core.h | |||
@@ -579,6 +579,8 @@ | |||
579 | 579 | ||
580 | #define WM8350_NUM_IRQ 63 | 580 | #define WM8350_NUM_IRQ 63 |
581 | 581 | ||
582 | #define WM8350_NUM_IRQ_REGS 7 | ||
583 | |||
582 | struct wm8350_reg_access { | 584 | struct wm8350_reg_access { |
583 | u16 readable; /* Mask of readable bits */ | 585 | u16 readable; /* Mask of readable bits */ |
584 | u16 writable; /* Mask of writable bits */ | 586 | u16 writable; /* Mask of writable bits */ |
@@ -600,11 +602,6 @@ extern const u16 wm8352_mode3_defaults[]; | |||
600 | 602 | ||
601 | struct wm8350; | 603 | struct wm8350; |
602 | 604 | ||
603 | struct wm8350_irq { | ||
604 | irq_handler_t handler; | ||
605 | void *data; | ||
606 | }; | ||
607 | |||
608 | struct wm8350_hwmon { | 605 | struct wm8350_hwmon { |
609 | struct platform_device *pdev; | 606 | struct platform_device *pdev; |
610 | struct device *classdev; | 607 | struct device *classdev; |
@@ -626,9 +623,10 @@ struct wm8350 { | |||
626 | struct mutex auxadc_mutex; | 623 | struct mutex auxadc_mutex; |
627 | 624 | ||
628 | /* Interrupt handling */ | 625 | /* Interrupt handling */ |
629 | struct mutex irq_mutex; /* IRQ table mutex */ | 626 | struct mutex irq_lock; |
630 | struct wm8350_irq irq[WM8350_NUM_IRQ]; | ||
631 | int chip_irq; | 627 | int chip_irq; |
628 | int irq_base; | ||
629 | u16 irq_masks[WM8350_NUM_IRQ_REGS]; | ||
632 | 630 | ||
633 | /* Client devices */ | 631 | /* Client devices */ |
634 | struct wm8350_codec codec; | 632 | struct wm8350_codec codec; |
@@ -677,13 +675,33 @@ int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src); | |||
677 | /* | 675 | /* |
678 | * WM8350 internal interrupts | 676 | * WM8350 internal interrupts |
679 | */ | 677 | */ |
680 | int wm8350_register_irq(struct wm8350 *wm8350, int irq, | 678 | static inline int wm8350_register_irq(struct wm8350 *wm8350, int irq, |
681 | irq_handler_t handler, unsigned long flags, | 679 | irq_handler_t handler, |
682 | const char *name, void *data); | 680 | unsigned long flags, |
683 | int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data); | 681 | const char *name, void *data) |
682 | { | ||
683 | if (!wm8350->irq_base) | ||
684 | return -ENODEV; | ||
685 | |||
686 | return request_threaded_irq(irq + wm8350->irq_base, NULL, | ||
687 | handler, flags, name, data); | ||
688 | } | ||
689 | |||
690 | static inline void wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) | ||
691 | { | ||
692 | free_irq(irq + wm8350->irq_base, data); | ||
693 | } | ||
694 | |||
695 | static inline void wm8350_mask_irq(struct wm8350 *wm8350, int irq) | ||
696 | { | ||
697 | disable_irq(irq + wm8350->irq_base); | ||
698 | } | ||
699 | |||
700 | static inline void wm8350_unmask_irq(struct wm8350 *wm8350, int irq) | ||
701 | { | ||
702 | enable_irq(irq + wm8350->irq_base); | ||
703 | } | ||
684 | 704 | ||
685 | int wm8350_mask_irq(struct wm8350 *wm8350, int irq); | ||
686 | int wm8350_unmask_irq(struct wm8350 *wm8350, int irq); | ||
687 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, | 705 | int wm8350_irq_init(struct wm8350 *wm8350, int irq, |
688 | struct wm8350_platform_data *pdata); | 706 | struct wm8350_platform_data *pdata); |
689 | int wm8350_irq_exit(struct wm8350 *wm8350); | 707 | int wm8350_irq_exit(struct wm8350 *wm8350); |