diff options
Diffstat (limited to 'drivers/mfd/wm8350-irq.c')
-rw-r--r-- | drivers/mfd/wm8350-irq.c | 155 |
1 files changed, 87 insertions, 68 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 | ||