aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/twl4030-irq.c
diff options
context:
space:
mode:
authorFelipe Balbi <balbi@ti.com>2011-06-30 05:51:08 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2011-10-24 08:09:11 -0400
commit2f2a7d5ef76477f3d2a333663e7cf7a380aebd82 (patch)
tree131cb39fa704c169b034befa3aa3e38593d2ef9d /drivers/mfd/twl4030-irq.c
parent848684246fc180a9b96f1b373a1ad70bc3ee725f (diff)
mfd: Drop twl4030-irq's edge_work
... and do all the synchronization with the hardware during bus_sync_unlock. We can now remove all the workqueues. Signed-off-by: Felipe Balbi <balbi@ti.com> Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/twl4030-irq.c')
-rw-r--r--drivers/mfd/twl4030-irq.c124
1 files changed, 52 insertions, 72 deletions
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index bf62389fc7e5..1b9ab2f40d5b 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -422,8 +422,6 @@ static inline void activate_irq(int irq)
422 422
423/*----------------------------------------------------------------------*/ 423/*----------------------------------------------------------------------*/
424 424
425static struct workqueue_struct *wq;
426
427struct sih_agent { 425struct sih_agent {
428 int irq_base; 426 int irq_base;
429 const struct sih *sih; 427 const struct sih *sih;
@@ -432,68 +430,10 @@ struct sih_agent {
432 bool imr_change_pending; 430 bool imr_change_pending;
433 431
434 u32 edge_change; 432 u32 edge_change;
435 struct work_struct edge_work;
436 433
437 struct mutex irq_lock; 434 struct mutex irq_lock;
438}; 435};
439 436
440static void twl4030_sih_do_edge(struct work_struct *work)
441{
442 struct sih_agent *agent;
443 const struct sih *sih;
444 u8 bytes[6];
445 u32 edge_change;
446 int status;
447
448 agent = container_of(work, struct sih_agent, edge_work);
449
450 /* see what work we have */
451 edge_change = agent->edge_change;
452 agent->edge_change = 0;
453 sih = edge_change ? agent->sih : NULL;
454 if (!sih)
455 return;
456
457 /* Read, reserving first byte for write scratch. Yes, this
458 * could be cached for some speedup ... but be careful about
459 * any processor on the other IRQ line, EDR registers are
460 * shared.
461 */
462 status = twl_i2c_read(sih->module, bytes + 1,
463 sih->edr_offset, sih->bytes_edr);
464 if (status) {
465 pr_err("twl4030: %s, %s --> %d\n", __func__,
466 "read", status);
467 return;
468 }
469
470 /* Modify only the bits we know must change */
471 while (edge_change) {
472 int i = fls(edge_change) - 1;
473 struct irq_data *idata = irq_get_irq_data(i + agent->irq_base);
474 int byte = 1 + (i >> 2);
475 int off = (i & 0x3) * 2;
476 unsigned int type;
477
478 bytes[byte] &= ~(0x03 << off);
479
480 type = irqd_get_trigger_type(idata);
481 if (type & IRQ_TYPE_EDGE_RISING)
482 bytes[byte] |= BIT(off + 1);
483 if (type & IRQ_TYPE_EDGE_FALLING)
484 bytes[byte] |= BIT(off + 0);
485
486 edge_change &= ~BIT(i);
487 }
488
489 /* Write */
490 status = twl_i2c_write(sih->module, bytes,
491 sih->edr_offset, sih->bytes_edr);
492 if (status)
493 pr_err("twl4030: %s, %s --> %d\n", __func__,
494 "write", status);
495}
496
497/*----------------------------------------------------------------------*/ 437/*----------------------------------------------------------------------*/
498 438
499/* 439/*
@@ -526,10 +466,8 @@ static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)
526 if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) 466 if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
527 return -EINVAL; 467 return -EINVAL;
528 468
529 if (irqd_get_trigger_type(data) != trigger) { 469 if (irqd_get_trigger_type(data) != trigger)
530 agent->edge_change |= BIT(data->irq - agent->irq_base); 470 agent->edge_change |= BIT(data->irq - agent->irq_base);
531 queue_work(wq, &agent->edge_work);
532 }
533 471
534 return 0; 472 return 0;
535} 473}
@@ -566,6 +504,56 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
566 "write", status); 504 "write", status);
567 } 505 }
568 506
507 if (agent->edge_change) {
508 u32 edge_change;
509 u8 bytes[6];
510
511 edge_change = agent->edge_change;
512 agent->edge_change = 0;
513
514 /*
515 * Read, reserving first byte for write scratch. Yes, this
516 * could be cached for some speedup ... but be careful about
517 * any processor on the other IRQ line, EDR registers are
518 * shared.
519 */
520 status = twl_i2c_read(sih->module, bytes + 1,
521 sih->edr_offset, sih->bytes_edr);
522 if (status) {
523 pr_err("twl4030: %s, %s --> %d\n", __func__,
524 "read", status);
525 return;
526 }
527
528 /* Modify only the bits we know must change */
529 while (edge_change) {
530 int i = fls(edge_change) - 1;
531 struct irq_data *idata;
532 int byte = 1 + (i >> 2);
533 int off = (i & 0x3) * 2;
534 unsigned int type;
535
536 idata = irq_get_irq_data(i + agent->irq_base);
537
538 bytes[byte] &= ~(0x03 << off);
539
540 type = irqd_get_trigger_type(idata);
541 if (type & IRQ_TYPE_EDGE_RISING)
542 bytes[byte] |= BIT(off + 1);
543 if (type & IRQ_TYPE_EDGE_FALLING)
544 bytes[byte] |= BIT(off + 0);
545
546 edge_change &= ~BIT(i);
547 }
548
549 /* Write */
550 status = twl_i2c_write(sih->module, bytes,
551 sih->edr_offset, sih->bytes_edr);
552 if (status)
553 pr_err("twl4030: %s, %s --> %d\n", __func__,
554 "write", status);
555 }
556
569 mutex_unlock(&agent->irq_lock); 557 mutex_unlock(&agent->irq_lock);
570} 558}
571 559
@@ -672,7 +660,6 @@ int twl4030_sih_setup(int module)
672 agent->sih = sih; 660 agent->sih = sih;
673 agent->imr = ~0; 661 agent->imr = ~0;
674 mutex_init(&agent->irq_lock); 662 mutex_init(&agent->irq_lock);
675 INIT_WORK(&agent->edge_work, twl4030_sih_do_edge);
676 663
677 for (i = 0; i < sih->bits; i++) { 664 for (i = 0; i < sih->bits; i++) {
678 irq = irq_base + i; 665 irq = irq_base + i;
@@ -720,12 +707,6 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
720 if (status < 0) 707 if (status < 0)
721 return status; 708 return status;
722 709
723 wq = create_singlethread_workqueue("twl4030-irqchip");
724 if (!wq) {
725 pr_err("twl4030: workqueue FAIL\n");
726 return -ESRCH;
727 }
728
729 twl4030_irq_base = irq_base; 710 twl4030_irq_base = irq_base;
730 711
731 /* install an irq handler for each of the SIH modules; 712 /* install an irq handler for each of the SIH modules;
@@ -766,8 +747,7 @@ fail_rqirq:
766fail: 747fail:
767 for (i = irq_base; i < irq_end; i++) 748 for (i = irq_base; i < irq_end; i++)
768 irq_set_chip_and_handler(i, NULL, NULL); 749 irq_set_chip_and_handler(i, NULL, NULL);
769 destroy_workqueue(wq); 750
770 wq = NULL;
771 return status; 751 return status;
772} 752}
773 753