Some hardware configurations might pass on providing an interrupt line. In that case there is always the option to use a polled input approach. This patch adapts the driver for it. The polled approach is only triggered if no interrupt is provided by the firmware or platform data. Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@xxxxxxx> --- drivers/input/touchscreen/edt-ft5x06.c | 100 ++++++++++++++++++------- 1 file changed, 72 insertions(+), 28 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 702bfda7ee77..e58645c72c2f 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -39,6 +39,7 @@ #include <linux/gpio/consumer.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> +#include <linux/input-polldev.h> #include <linux/of_device.h> #define WORK_REGISTER_THRESHOLD 0x00 @@ -97,6 +98,7 @@ struct edt_reg_addr { struct edt_ft5x06_ts_data { struct i2c_client *client; struct input_dev *input; + struct input_polled_dev *poll_dev; struct touchscreen_properties prop; u16 num_x; u16 num_y; @@ -181,9 +183,8 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, return true; } -static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) +static void edt_ft5x06_process(struct edt_ft5x06_ts_data *tsdata) { - struct edt_ft5x06_ts_data *tsdata = dev_id; struct device *dev = &tsdata->client->dev; u8 cmd; u8 rdbuf[63]; @@ -210,7 +211,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) break; default: - goto out; + return; } memset(rdbuf, 0, sizeof(rdbuf)); @@ -222,7 +223,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) if (error) { dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", error); - goto out; + return; } /* M09/M12 does not send header or CRC */ @@ -232,11 +233,11 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) dev_err_ratelimited(dev, "Unexpected header: %02x%02x%02x!\n", rdbuf[0], rdbuf[1], rdbuf[2]); - goto out; + return; } if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) - goto out; + return; } for (i = 0; i < tsdata->max_support_points; i++) { @@ -273,11 +274,23 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) input_mt_report_pointer_emulation(tsdata->input, true); input_sync(tsdata->input); +} -out: +static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) +{ + struct edt_ft5x06_ts_data *tsdata = dev_id; + + edt_ft5x06_process(tsdata); return IRQ_HANDLED; } +static void edt_ft5x06_poll(struct input_polled_dev *dev) +{ + struct edt_ft5x06_ts_data *tsdata = dev->private; + + edt_ft5x06_process(tsdata); +} + static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, u8 addr, u8 value) { @@ -1059,7 +1072,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct edt_i2c_chip_data *chip_data; + struct input_polled_dev *poll_dev = NULL; struct edt_ft5x06_ts_data *tsdata; + bool polled = !(client->irq); struct input_dev *input; unsigned long irq_flags; int error; @@ -1112,15 +1127,38 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, msleep(300); } - input = devm_input_allocate_device(&client->dev); - if (!input) { - dev_err(&client->dev, "failed to allocate input device.\n"); - return -ENOMEM; + if (polled) { + poll_dev = devm_input_allocate_polled_device(&client->dev); + if (!poll_dev) { + dev_err(&client->dev, + "failed to allocate polled input device.\n"); + return -ENOMEM; + } + + poll_dev->poll = edt_ft5x06_poll; + poll_dev->private = tsdata; + + tsdata->poll_dev = poll_dev; + tsdata->input = poll_dev->input; + + input = poll_dev->input; + + device_property_read_u32(&client->dev, "poll-interval", + &poll_dev->poll_interval); + + } else { + input = devm_input_allocate_device(&client->dev); + if (!input) { + dev_err(&client->dev, + "failed to allocate input device.\n"); + return -ENOMEM; + } + + tsdata->input = input; } mutex_init(&tsdata->mutex); tsdata->client = client; - tsdata->input = input; tsdata->factory_mode = false; error = edt_ft5x06_ts_identify(client, tsdata, fw_version); @@ -1167,26 +1205,32 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, tsdata); - irq_flags = irq_get_trigger_type(client->irq); - if (irq_flags == IRQF_TRIGGER_NONE) - irq_flags = IRQF_TRIGGER_FALLING; - irq_flags |= IRQF_ONESHOT; - - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, edt_ft5x06_ts_isr, irq_flags, - client->name, tsdata); - if (error) { - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); - return error; - } - error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group); if (error) return error; - error = input_register_device(input); - if (error) - return error; + if (polled) { + error = input_register_polled_device(poll_dev); + if (error) + return error; + } else { + irq_flags = irq_get_trigger_type(client->irq); + if (irq_flags == IRQF_TRIGGER_NONE) + irq_flags = IRQF_TRIGGER_FALLING; + irq_flags |= IRQF_ONESHOT; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, edt_ft5x06_ts_isr, irq_flags, + client->name, tsdata); + if (error) { + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); + return error; + } + + error = input_register_device(input); + if (error) + return error; + } edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); device_init_wakeup(&client->dev, 1); -- 2.21.0