diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/mfd/wm831x-irq.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/mfd/wm831x-irq.c')
-rw-r--r-- | drivers/mfd/wm831x-irq.c | 124 |
1 files changed, 78 insertions, 46 deletions
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 294183b6260b..42b928ec891e 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c | |||
@@ -26,15 +26,6 @@ | |||
26 | 26 | ||
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | 28 | ||
29 | /* | ||
30 | * Since generic IRQs don't currently support interrupt controllers on | ||
31 | * interrupt driven buses we don't use genirq but instead provide an | ||
32 | * interface that looks very much like the standard ones. This leads | ||
33 | * to some bodges, including storing interrupt handler information in | ||
34 | * the static irq_data table we use to look up the data for individual | ||
35 | * interrupts, but hopefully won't last too long. | ||
36 | */ | ||
37 | |||
38 | struct wm831x_irq_data { | 29 | struct wm831x_irq_data { |
39 | int primary; | 30 | int primary; |
40 | int reg; | 31 | int reg; |
@@ -345,22 +336,26 @@ static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x, | |||
345 | return &wm831x_irqs[irq - wm831x->irq_base]; | 336 | return &wm831x_irqs[irq - wm831x->irq_base]; |
346 | } | 337 | } |
347 | 338 | ||
348 | static void wm831x_irq_lock(unsigned int irq) | 339 | static void wm831x_irq_lock(struct irq_data *data) |
349 | { | 340 | { |
350 | struct wm831x *wm831x = get_irq_chip_data(irq); | 341 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
351 | 342 | ||
352 | mutex_lock(&wm831x->irq_lock); | 343 | mutex_lock(&wm831x->irq_lock); |
353 | } | 344 | } |
354 | 345 | ||
355 | static void wm831x_irq_sync_unlock(unsigned int irq) | 346 | static void wm831x_irq_sync_unlock(struct irq_data *data) |
356 | { | 347 | { |
357 | struct wm831x *wm831x = get_irq_chip_data(irq); | 348 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
358 | int i; | 349 | int i; |
359 | 350 | ||
360 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { | 351 | for (i = 0; i < ARRAY_SIZE(wm831x->irq_masks_cur); i++) { |
361 | /* If there's been a change in the mask write it back | 352 | /* If there's been a change in the mask write it back |
362 | * to the hardware. */ | 353 | * to the hardware. */ |
363 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { | 354 | if (wm831x->irq_masks_cur[i] != wm831x->irq_masks_cache[i]) { |
355 | dev_dbg(wm831x->dev, "IRQ mask sync: %x = %x\n", | ||
356 | WM831X_INTERRUPT_STATUS_1_MASK + i, | ||
357 | wm831x->irq_masks_cur[i]); | ||
358 | |||
364 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; | 359 | wm831x->irq_masks_cache[i] = wm831x->irq_masks_cur[i]; |
365 | wm831x_reg_write(wm831x, | 360 | wm831x_reg_write(wm831x, |
366 | WM831X_INTERRUPT_STATUS_1_MASK + i, | 361 | WM831X_INTERRUPT_STATUS_1_MASK + i, |
@@ -371,28 +366,30 @@ static void wm831x_irq_sync_unlock(unsigned int irq) | |||
371 | mutex_unlock(&wm831x->irq_lock); | 366 | mutex_unlock(&wm831x->irq_lock); |
372 | } | 367 | } |
373 | 368 | ||
374 | static void wm831x_irq_unmask(unsigned int irq) | 369 | static void wm831x_irq_enable(struct irq_data *data) |
375 | { | 370 | { |
376 | struct wm831x *wm831x = get_irq_chip_data(irq); | 371 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
377 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); | 372 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, |
373 | data->irq); | ||
378 | 374 | ||
379 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; | 375 | wm831x->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask; |
380 | } | 376 | } |
381 | 377 | ||
382 | static void wm831x_irq_mask(unsigned int irq) | 378 | static void wm831x_irq_disable(struct irq_data *data) |
383 | { | 379 | { |
384 | struct wm831x *wm831x = get_irq_chip_data(irq); | 380 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
385 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, irq); | 381 | struct wm831x_irq_data *irq_data = irq_to_wm831x_irq(wm831x, |
382 | data->irq); | ||
386 | 383 | ||
387 | wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; | 384 | wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask; |
388 | } | 385 | } |
389 | 386 | ||
390 | static int wm831x_irq_set_type(unsigned int irq, unsigned int type) | 387 | static int wm831x_irq_set_type(struct irq_data *data, unsigned int type) |
391 | { | 388 | { |
392 | struct wm831x *wm831x = get_irq_chip_data(irq); | 389 | struct wm831x *wm831x = irq_data_get_irq_chip_data(data); |
393 | int val; | 390 | int val, irq; |
394 | 391 | ||
395 | irq = irq - wm831x->irq_base; | 392 | irq = data->irq - wm831x->irq_base; |
396 | 393 | ||
397 | if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { | 394 | if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11) { |
398 | /* Ignore internal-only IRQs */ | 395 | /* Ignore internal-only IRQs */ |
@@ -421,12 +418,12 @@ static int wm831x_irq_set_type(unsigned int irq, unsigned int type) | |||
421 | } | 418 | } |
422 | 419 | ||
423 | static struct irq_chip wm831x_irq_chip = { | 420 | static struct irq_chip wm831x_irq_chip = { |
424 | .name = "wm831x", | 421 | .name = "wm831x", |
425 | .bus_lock = wm831x_irq_lock, | 422 | .irq_bus_lock = wm831x_irq_lock, |
426 | .bus_sync_unlock = wm831x_irq_sync_unlock, | 423 | .irq_bus_sync_unlock = wm831x_irq_sync_unlock, |
427 | .mask = wm831x_irq_mask, | 424 | .irq_disable = wm831x_irq_disable, |
428 | .unmask = wm831x_irq_unmask, | 425 | .irq_enable = wm831x_irq_enable, |
429 | .set_type = wm831x_irq_set_type, | 426 | .irq_set_type = wm831x_irq_set_type, |
430 | }; | 427 | }; |
431 | 428 | ||
432 | /* The processing of the primary interrupt occurs in a thread so that | 429 | /* The processing of the primary interrupt occurs in a thread so that |
@@ -447,6 +444,18 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
447 | goto out; | 444 | goto out; |
448 | } | 445 | } |
449 | 446 | ||
447 | /* The touch interrupts are visible in the primary register as | ||
448 | * an optimisation; open code this to avoid complicating the | ||
449 | * main handling loop and so we can also skip iterating the | ||
450 | * descriptors. | ||
451 | */ | ||
452 | if (primary & WM831X_TCHPD_INT) | ||
453 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD); | ||
454 | if (primary & WM831X_TCHDATA_INT) | ||
455 | handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA); | ||
456 | if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT)) | ||
457 | goto out; | ||
458 | |||
450 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { | 459 | for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) { |
451 | int offset = wm831x_irqs[i].reg - 1; | 460 | int offset = wm831x_irqs[i].reg - 1; |
452 | 461 | ||
@@ -479,6 +488,9 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data) | |||
479 | } | 488 | } |
480 | 489 | ||
481 | out: | 490 | out: |
491 | /* Touchscreen interrupts are handled specially in the driver */ | ||
492 | status_regs[0] &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT); | ||
493 | |||
482 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { | 494 | for (i = 0; i < ARRAY_SIZE(status_regs); i++) { |
483 | if (status_regs[i]) | 495 | if (status_regs[i]) |
484 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, | 496 | wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1 + i, |
@@ -503,18 +515,31 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
503 | 0xffff); | 515 | 0xffff); |
504 | } | 516 | } |
505 | 517 | ||
506 | if (!irq) { | ||
507 | dev_warn(wm831x->dev, | ||
508 | "No interrupt specified - functionality limited\n"); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | if (!pdata || !pdata->irq_base) { | 518 | if (!pdata || !pdata->irq_base) { |
513 | dev_err(wm831x->dev, | 519 | dev_err(wm831x->dev, |
514 | "No interrupt base specified, no interrupts\n"); | 520 | "No interrupt base specified, no interrupts\n"); |
515 | return 0; | 521 | return 0; |
516 | } | 522 | } |
517 | 523 | ||
524 | if (pdata->irq_cmos) | ||
525 | i = 0; | ||
526 | else | ||
527 | i = WM831X_IRQ_OD; | ||
528 | |||
529 | wm831x_set_bits(wm831x, WM831X_IRQ_CONFIG, | ||
530 | WM831X_IRQ_OD, i); | ||
531 | |||
532 | /* Try to flag /IRQ as a wake source; there are a number of | ||
533 | * unconditional wake sources in the PMIC so this isn't | ||
534 | * conditional but we don't actually care *too* much if it | ||
535 | * fails. | ||
536 | */ | ||
537 | ret = enable_irq_wake(irq); | ||
538 | if (ret != 0) { | ||
539 | dev_warn(wm831x->dev, "Can't enable IRQ as wake source: %d\n", | ||
540 | ret); | ||
541 | } | ||
542 | |||
518 | wm831x->irq = irq; | 543 | wm831x->irq = irq; |
519 | wm831x->irq_base = pdata->irq_base; | 544 | wm831x->irq_base = pdata->irq_base; |
520 | 545 | ||
@@ -522,29 +547,36 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) | |||
522 | for (cur_irq = wm831x->irq_base; | 547 | for (cur_irq = wm831x->irq_base; |
523 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; | 548 | cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; |
524 | cur_irq++) { | 549 | cur_irq++) { |
525 | set_irq_chip_data(cur_irq, wm831x); | 550 | irq_set_chip_data(cur_irq, wm831x); |
526 | set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip, | 551 | irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip, |
527 | handle_edge_irq); | 552 | handle_edge_irq); |
528 | set_irq_nested_thread(cur_irq, 1); | 553 | irq_set_nested_thread(cur_irq, 1); |
529 | 554 | ||
530 | /* ARM needs us to explicitly flag the IRQ as valid | 555 | /* ARM needs us to explicitly flag the IRQ as valid |
531 | * and will set them noprobe when we do so. */ | 556 | * and will set them noprobe when we do so. */ |
532 | #ifdef CONFIG_ARM | 557 | #ifdef CONFIG_ARM |
533 | set_irq_flags(cur_irq, IRQF_VALID); | 558 | set_irq_flags(cur_irq, IRQF_VALID); |
534 | #else | 559 | #else |
535 | set_irq_noprobe(cur_irq); | 560 | irq_set_noprobe(cur_irq); |
536 | #endif | 561 | #endif |
537 | } | 562 | } |
538 | 563 | ||
539 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, | 564 | if (irq) { |
540 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 565 | ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, |
541 | "wm831x", wm831x); | 566 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
542 | if (ret != 0) { | 567 | "wm831x", wm831x); |
543 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", | 568 | if (ret != 0) { |
544 | irq, ret); | 569 | dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", |
545 | return ret; | 570 | irq, ret); |
571 | return ret; | ||
572 | } | ||
573 | } else { | ||
574 | dev_warn(wm831x->dev, | ||
575 | "No interrupt specified - functionality limited\n"); | ||
546 | } | 576 | } |
547 | 577 | ||
578 | |||
579 | |||
548 | /* Enable top level interrupts, we mask at secondary level */ | 580 | /* Enable top level interrupts, we mask at secondary level */ |
549 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); | 581 | wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); |
550 | 582 | ||