From 0378008a99243fc492e7f0c3aabfeee69a78398c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 19 Feb 2017 17:23:47 -0800 Subject: [PATCH] Input: eeti_ts - switch to using threaded interrupt Instead of having standard interrupt handler and manually firing work item to perform I2C reads, let's switch to threaded interrupts, which were designed specifically for this purpose. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 79 +++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index fc61dbe..ee6b87c 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -47,9 +47,8 @@ MODULE_PARM_DESC(flip_y, "flip y coordinate"); struct eeti_ts { struct i2c_client *client; struct input_dev *input; - struct work_struct work; - struct mutex mutex; int irq_gpio, irq_active_high; + bool running; }; #define EETI_TS_BITDEPTH (11) @@ -66,29 +65,11 @@ static inline int eeti_ts_irq_active(struct eeti_ts *eeti) return gpio_get_value_cansleep(eeti->irq_gpio) == eeti->irq_active_high; } -static void eeti_ts_read(struct work_struct *work) +static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) { - char buf[6]; - unsigned int x, y, res, pressed, to = 100; - struct eeti_ts *eeti = - container_of(work, struct eeti_ts, work); - - mutex_lock(&eeti->mutex); - - while (eeti_ts_irq_active(eeti) && --to) - i2c_master_recv(eeti->client, buf, sizeof(buf)); - - if (!to) { - dev_err(&eeti->client->dev, - "unable to clear IRQ - line stuck?\n"); - goto out; - } + unsigned int res; + u16 x, y; - /* drop non-report packets */ - if (!(buf[0] & 0x80)) - goto out; - - pressed = buf[0] & REPORT_BIT_PRESSED; res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); x = get_unaligned_be16(&buf[1]); @@ -109,35 +90,48 @@ static void eeti_ts_read(struct work_struct *work) input_report_abs(eeti->input, ABS_X, x); input_report_abs(eeti->input, ABS_Y, y); - input_report_key(eeti->input, BTN_TOUCH, !!pressed); + input_report_key(eeti->input, BTN_TOUCH, buf[0] & REPORT_BIT_PRESSED); input_sync(eeti->input); - -out: - mutex_unlock(&eeti->mutex); } static irqreturn_t eeti_ts_isr(int irq, void *dev_id) { struct eeti_ts *eeti = dev_id; + int len; + int error; + char buf[6]; - /* postpone I2C transactions as we are atomic */ - schedule_work(&eeti->work); + do { + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); + if (len != sizeof(buf)) { + error = len < 0 ? len : -EIO; + dev_err(&eeti->client->dev, + "failed to read touchscreen data: %d\n", + error); + break; + } + + if (buf[0] & 0x80) { + /* Motion packet */ + eeti_ts_report_event(eeti, buf); + } + } while (eeti->running && eeti_ts_irq_active(eeti)); return IRQ_HANDLED; } static void eeti_ts_start(struct eeti_ts *eeti) { + eeti->running = true; + wmb(); enable_irq(eeti->client->irq); - - /* Read the events once to arm the IRQ */ - eeti_ts_read(&eeti->work); } static void eeti_ts_stop(struct eeti_ts *eeti) { + eeti->running = false; + wmb(); disable_irq(eeti->client->irq); - cancel_work_sync(&eeti->work); } static int eeti_ts_open(struct input_dev *dev) @@ -179,8 +173,6 @@ static int eeti_ts_probe(struct i2c_client *client, return -ENOMEM; } - mutex_init(&eeti->mutex); - input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device.\n"); @@ -210,18 +202,15 @@ static int eeti_ts_probe(struct i2c_client *client, eeti->irq_active_high = pdata->irq_active_high; irq_flags = eeti->irq_active_high ? - IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW; - INIT_WORK(&eeti->work, eeti_ts_read); i2c_set_clientdata(client, eeti); input_set_drvdata(input, eeti); - error = input_register_device(input); - if (error) - return error; - - error = devm_request_irq(dev, client->irq, eeti_ts_isr, irq_flags, - client->name, eeti); + error = devm_request_threaded_irq(dev, client->irq, + NULL, eeti_ts_isr, + irq_flags | IRQF_ONESHOT, + client->name, eeti); if (error) { dev_err(dev, "Unable to request touchscreen IRQ: %d\n", error); @@ -234,6 +223,10 @@ static int eeti_ts_probe(struct i2c_client *client, */ eeti_ts_stop(eeti); + error = input_register_device(input); + if (error) + return error; + return 0; } -- 2.7.4