summaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/eeti_ts.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2017-02-20 02:23:47 +0100
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2017-04-04 01:24:34 +0200
commit0378008a99243fc492e7f0c3aabfeee69a78398c (patch)
treef43e645db1a4fab36db247355b98d6f3ef8e0f9d /drivers/input/touchscreen/eeti_ts.c
parentInput: eeti_ts - use gpio_get_value_cansleep (diff)
downloadlinux-0378008a99243fc492e7f0c3aabfeee69a78398c.tar.xz
linux-0378008a99243fc492e7f0c3aabfeee69a78398c.zip
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 <daniel@zonque.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/touchscreen/eeti_ts.c')
-rw-r--r--drivers/input/touchscreen/eeti_ts.c79
1 files changed, 36 insertions, 43 deletions
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index fc61dbea4736..ee6b87c606ef 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;
}