aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/wm8350-irq.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-01-05 08:59:09 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2010-03-07 16:16:57 -0500
commit760e4518788df6762700e6bb9dd8692379f11168 (patch)
treed4fa27366ec331e9b120b4c5e3b8d62610c2b36a /drivers/mfd/wm8350-irq.c
parent29c71b138c83c8191f1f7e46fcc28b9d6bc8a5dd (diff)
mfd: Convert WM8350 to genirq
This gives us use of the diagnostic facilities genirq provides and will allow implementation of interrupt support for the WM8350 GPIOs. Stub functions are provided to ease the transition of the individual drivers, probably after additional work to pass the IRQ numbers via the struct devices. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/wm8350-irq.c')
-rw-r--r--drivers/mfd/wm8350-irq.c155
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
369static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq) 367static 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 */
391static irqreturn_t wm8350_irq(int irq, void *irq_data) 382static 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
433int wm8350_register_irq(struct wm8350 *wm8350, int irq, 420static 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}
452EXPORT_SYMBOL_GPL(wm8350_register_irq);
453 426
454int wm8350_free_irq(struct wm8350 *wm8350, int irq, void *data) 427static 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}
466EXPORT_SYMBOL_GPL(wm8350_free_irq);
467 444
468int wm8350_mask_irq(struct wm8350 *wm8350, int irq) 445static 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}
474EXPORT_SYMBOL_GPL(wm8350_mask_irq);
475 452
476int wm8350_unmask_irq(struct wm8350 *wm8350, int irq) 453static 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}
482EXPORT_SYMBOL_GPL(wm8350_unmask_irq); 460
461static 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
484int wm8350_irq_init(struct wm8350 *wm8350, int irq, 469int 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