Commit 0378008a authored by Dmitry Torokhov's avatar Dmitry Torokhov

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: default avatarDaniel Mack <daniel@zonque.org>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 173e4d81
......@@ -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;
}
/* drop non-report packets */
if (!(buf[0] & 0x80))
goto out;
unsigned int res;
u16 x, y;
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,17 +202,14 @@ 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,
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",
......@@ -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;
}
......
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