提交 0378008a 编写于 作者: D 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: NDaniel Mack <daniel@zonque.org>
Signed-off-by: NDmitry Torokhov <dmitry.torokhov@gmail.com>
上级 173e4d81
...@@ -47,9 +47,8 @@ MODULE_PARM_DESC(flip_y, "flip y coordinate"); ...@@ -47,9 +47,8 @@ MODULE_PARM_DESC(flip_y, "flip y coordinate");
struct eeti_ts { struct eeti_ts {
struct i2c_client *client; struct i2c_client *client;
struct input_dev *input; struct input_dev *input;
struct work_struct work;
struct mutex mutex;
int irq_gpio, irq_active_high; int irq_gpio, irq_active_high;
bool running;
}; };
#define EETI_TS_BITDEPTH (11) #define EETI_TS_BITDEPTH (11)
...@@ -66,29 +65,11 @@ static inline int eeti_ts_irq_active(struct eeti_ts *eeti) ...@@ -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; 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 res;
unsigned int x, y, res, pressed, to = 100; u16 x, y;
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;
pressed = buf[0] & REPORT_BIT_PRESSED;
res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1));
x = get_unaligned_be16(&buf[1]); x = get_unaligned_be16(&buf[1]);
...@@ -109,35 +90,48 @@ static void eeti_ts_read(struct work_struct *work) ...@@ -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_X, x);
input_report_abs(eeti->input, ABS_Y, y); 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); input_sync(eeti->input);
out:
mutex_unlock(&eeti->mutex);
} }
static irqreturn_t eeti_ts_isr(int irq, void *dev_id) static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
{ {
struct eeti_ts *eeti = dev_id; struct eeti_ts *eeti = dev_id;
int len;
int error;
char buf[6];
/* postpone I2C transactions as we are atomic */ do {
schedule_work(&eeti->work); 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; return IRQ_HANDLED;
} }
static void eeti_ts_start(struct eeti_ts *eeti) static void eeti_ts_start(struct eeti_ts *eeti)
{ {
eeti->running = true;
wmb();
enable_irq(eeti->client->irq); 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) static void eeti_ts_stop(struct eeti_ts *eeti)
{ {
eeti->running = false;
wmb();
disable_irq(eeti->client->irq); disable_irq(eeti->client->irq);
cancel_work_sync(&eeti->work);
} }
static int eeti_ts_open(struct input_dev *dev) static int eeti_ts_open(struct input_dev *dev)
...@@ -179,8 +173,6 @@ static int eeti_ts_probe(struct i2c_client *client, ...@@ -179,8 +173,6 @@ static int eeti_ts_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
} }
mutex_init(&eeti->mutex);
input = devm_input_allocate_device(dev); input = devm_input_allocate_device(dev);
if (!input) { if (!input) {
dev_err(dev, "Failed to allocate input device.\n"); dev_err(dev, "Failed to allocate input device.\n");
...@@ -210,17 +202,14 @@ static int eeti_ts_probe(struct i2c_client *client, ...@@ -210,17 +202,14 @@ static int eeti_ts_probe(struct i2c_client *client,
eeti->irq_active_high = pdata->irq_active_high; eeti->irq_active_high = pdata->irq_active_high;
irq_flags = eeti->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); i2c_set_clientdata(client, eeti);
input_set_drvdata(input, eeti); input_set_drvdata(input, eeti);
error = input_register_device(input); error = devm_request_threaded_irq(dev, client->irq,
if (error) NULL, eeti_ts_isr,
return error; irq_flags | IRQF_ONESHOT,
error = devm_request_irq(dev, client->irq, eeti_ts_isr, irq_flags,
client->name, eeti); client->name, eeti);
if (error) { if (error) {
dev_err(dev, "Unable to request touchscreen IRQ: %d\n", dev_err(dev, "Unable to request touchscreen IRQ: %d\n",
...@@ -234,6 +223,10 @@ static int eeti_ts_probe(struct i2c_client *client, ...@@ -234,6 +223,10 @@ static int eeti_ts_probe(struct i2c_client *client,
*/ */
eeti_ts_stop(eeti); eeti_ts_stop(eeti);
error = input_register_device(input);
if (error)
return error;
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册