aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Fertser <fercerpav@gmail.com>2009-07-27 16:41:15 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2009-09-17 03:46:53 -0400
commited52e62ebec9e703eb0b69704feaf1b6e847d882 (patch)
tree71f81470bf569105a09f9b330bf68ba428236f06
parent9c3664ddcee8d56c54bc6a735bbc3cf77723d85d (diff)
mfd: use a dedicated workqueue for pcf50633 irq processing
Using the default kernel "events" workqueue causes problems with synchronous adc readings if initiated from some task on the same workqueue. I had a deadlock trying to use pcf50633_adc_sync_read from a power_supply class driver because the reading was initiated from the workqueue and it waited for the irq processing to complete (to get the result) and that was put on the same workqueue. Signed-off-by: Paul Fertser <fercerpav@gmail.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/mfd/pcf50633-core.c5
-rw-r--r--include/linux/mfd/pcf50633/core.h1
2 files changed, 5 insertions, 1 deletions
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index 8d3c38bf9714..d26d7747175e 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -444,7 +444,7 @@ static irqreturn_t pcf50633_irq(int irq, void *data)
444 444
445 get_device(pcf->dev); 445 get_device(pcf->dev);
446 disable_irq_nosync(pcf->irq); 446 disable_irq_nosync(pcf->irq);
447 schedule_work(&pcf->irq_work); 447 queue_work(pcf->work_queue, &pcf->irq_work);
448 448
449 return IRQ_HANDLED; 449 return IRQ_HANDLED;
450} 450}
@@ -575,6 +575,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
575 pcf->dev = &client->dev; 575 pcf->dev = &client->dev;
576 pcf->i2c_client = client; 576 pcf->i2c_client = client;
577 pcf->irq = client->irq; 577 pcf->irq = client->irq;
578 pcf->work_queue = create_singlethread_workqueue("pcf50633");
578 579
579 INIT_WORK(&pcf->irq_work, pcf50633_irq_worker); 580 INIT_WORK(&pcf->irq_work, pcf50633_irq_worker);
580 581
@@ -651,6 +652,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
651 return 0; 652 return 0;
652 653
653err: 654err:
655 destroy_workqueue(pcf->work_queue);
654 kfree(pcf); 656 kfree(pcf);
655 return ret; 657 return ret;
656} 658}
@@ -661,6 +663,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client)
661 int i; 663 int i;
662 664
663 free_irq(pcf->irq, pcf); 665 free_irq(pcf->irq, pcf);
666 destroy_workqueue(pcf->work_queue);
664 667
665 platform_device_unregister(pcf->input_pdev); 668 platform_device_unregister(pcf->input_pdev);
666 platform_device_unregister(pcf->rtc_pdev); 669 platform_device_unregister(pcf->rtc_pdev);
diff --git a/include/linux/mfd/pcf50633/core.h b/include/linux/mfd/pcf50633/core.h
index c8f51c3c0a72..9aba7b779fbc 100644
--- a/include/linux/mfd/pcf50633/core.h
+++ b/include/linux/mfd/pcf50633/core.h
@@ -136,6 +136,7 @@ struct pcf50633 {
136 int irq; 136 int irq;
137 struct pcf50633_irq irq_handler[PCF50633_NUM_IRQ]; 137 struct pcf50633_irq irq_handler[PCF50633_NUM_IRQ];
138 struct work_struct irq_work; 138 struct work_struct irq_work;
139 struct workqueue_struct *work_queue;
139 struct mutex lock; 140 struct mutex lock;
140 141
141 u8 mask_regs[5]; 142 u8 mask_regs[5];