Commit 499e6127 authored by Heiko Stübner's avatar Heiko Stübner Committed by Dmitry Torokhov

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: default avatarHeiko Stuebner <heiko@sntech.de>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 241ecf1c
...@@ -455,7 +455,18 @@ static void zforce_complete(struct zforce_ts *ts, int cmd, int result) ...@@ -455,7 +455,18 @@ static void zforce_complete(struct zforce_ts *ts, int cmd, int result)
} }
} }
static irqreturn_t zforce_interrupt(int irq, void *dev_id) static irqreturn_t zforce_irq(int irq, void *dev_id)
{
struct zforce_ts *ts = dev_id;
struct i2c_client *client = ts->client;
if (ts->suspended && device_may_wakeup(&client->dev))
pm_wakeup_event(&client->dev, 500);
return IRQ_WAKE_THREAD;
}
static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
{ {
struct zforce_ts *ts = dev_id; struct zforce_ts *ts = dev_id;
struct i2c_client *client = ts->client; struct i2c_client *client = ts->client;
...@@ -465,12 +476,10 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id) ...@@ -465,12 +476,10 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id)
u8 *payload; u8 *payload;
/* /*
* When suspended, emit a wakeup signal if necessary and return. * When still suspended, return.
* Due to the level-interrupt we will get re-triggered later. * Due to the level-interrupt we will get re-triggered later.
*/ */
if (ts->suspended) { if (ts->suspended) {
if (device_may_wakeup(&client->dev))
pm_wakeup_event(&client->dev, 500);
msleep(20); msleep(20);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -763,8 +772,8 @@ static int zforce_probe(struct i2c_client *client, ...@@ -763,8 +772,8 @@ static int zforce_probe(struct i2c_client *client,
* Therefore we can trigger the interrupt anytime it is low and do * Therefore we can trigger the interrupt anytime it is low and do
* not need to limit it to the interrupt edge. * not need to limit it to the interrupt edge.
*/ */
ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, ret = devm_request_threaded_irq(&client->dev, client->irq,
zforce_interrupt, zforce_irq, zforce_irq_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
input_dev->name, ts); input_dev->name, ts);
if (ret) { if (ret) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment