aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Stübner <heiko@sntech.de>2013-12-14 04:41:55 -0500
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2013-12-15 05:53:13 -0500
commit499e61279d0f8dc6ecf46b75479118589df58b56 (patch)
tree2bef28475bf760c4b94779cf25ccc5ceda9dbafb
parent241ecf1ce528804d5ffc8fb386ff2a01b1f937c4 (diff)
Input: zforce - fix possible driver hang during suspend
handle_level_irq masks the interrupt before handling it, and only unmasks it after the handler is finished. So when a touch event happens after threads are suspended, but before the system is fully asleep the irq handler tries to wakeup the thread which will only happen on the next resume, resulting in the wakeup event never being sent and the driver not being able to wake the system from sleep due to the masked irq. Therefore move the wakeup_event to a small non-threaded handler. Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/touchscreen/zforce_ts.c21
1 files changed, 15 insertions, 6 deletions
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 75762d6ff3ba..aa127ba392a4 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -455,7 +455,18 @@ static void zforce_complete(struct zforce_ts *ts, int cmd, int result)
455 } 455 }
456} 456}
457 457
458static irqreturn_t zforce_interrupt(int irq, void *dev_id) 458static irqreturn_t zforce_irq(int irq, void *dev_id)
459{
460 struct zforce_ts *ts = dev_id;
461 struct i2c_client *client = ts->client;
462
463 if (ts->suspended && device_may_wakeup(&client->dev))
464 pm_wakeup_event(&client->dev, 500);
465
466 return IRQ_WAKE_THREAD;
467}
468
469static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
459{ 470{
460 struct zforce_ts *ts = dev_id; 471 struct zforce_ts *ts = dev_id;
461 struct i2c_client *client = ts->client; 472 struct i2c_client *client = ts->client;
@@ -465,12 +476,10 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id)
465 u8 *payload; 476 u8 *payload;
466 477
467 /* 478 /*
468 * When suspended, emit a wakeup signal if necessary and return. 479 * When still suspended, return.
469 * Due to the level-interrupt we will get re-triggered later. 480 * Due to the level-interrupt we will get re-triggered later.
470 */ 481 */
471 if (ts->suspended) { 482 if (ts->suspended) {
472 if (device_may_wakeup(&client->dev))
473 pm_wakeup_event(&client->dev, 500);
474 msleep(20); 483 msleep(20);
475 return IRQ_HANDLED; 484 return IRQ_HANDLED;
476 } 485 }
@@ -763,8 +772,8 @@ static int zforce_probe(struct i2c_client *client,
763 * Therefore we can trigger the interrupt anytime it is low and do 772 * Therefore we can trigger the interrupt anytime it is low and do
764 * not need to limit it to the interrupt edge. 773 * not need to limit it to the interrupt edge.
765 */ 774 */
766 ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, 775 ret = devm_request_threaded_irq(&client->dev, client->irq,
767 zforce_interrupt, 776 zforce_irq, zforce_irq_thread,
768 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 777 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
769 input_dev->name, ts); 778 input_dev->name, ts);
770 if (ret) { 779 if (ret) {