From 3b2cef652da3a4ef94f21401df3714333d786e7d Mon Sep 17 00:00:00 2001 From: Mattias Walström Date: Thu, 21 Aug 2025 11:20:23 +0200 Subject: [PATCH 30/30] input:touchscreen:edt-ft5x06: Add polled mode Not all hardware has interrupts therefore we need to poll the touchscreen. --- drivers/input/touchscreen/edt-ft5x06.c | 74 ++++++++++++++++++++------ 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 85c6d8ce003f..e61519915137 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -77,6 +77,9 @@ #define EDT_DEFAULT_NUM_X 1024 #define EDT_DEFAULT_NUM_Y 1024 +#define FIRST_POLL_DELAY_MS 300 /* in addition to the above */ +#define POLL_INTERVAL_MS 17 /* 17ms = 60fps */ + #define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc) #define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f) @@ -139,6 +142,7 @@ struct edt_ft5x06_ts_data { u8 tdata_cmd; int tdata_len; int tdata_offset; + int init_td_status; char name[EDT_NAME_LEN]; char fw_version[EDT_NAME_LEN]; @@ -147,6 +151,9 @@ struct edt_ft5x06_ts_data { enum edt_ver version; unsigned int crc_errors; unsigned int header_errors; + + struct timer_list timer; + struct work_struct work_i2c_poll; }; struct edt_i2c_chip_data { @@ -582,6 +589,22 @@ static struct attribute *edt_ft5x06_attrs[] = { }; ATTRIBUTE_GROUPS(edt_ft5x06); +static void edt_ft5x06_ts_irq_poll_timer(struct timer_list *t) +{ + struct edt_ft5x06_ts_data *tsdata = from_timer(tsdata, t, timer); + + schedule_work(&tsdata->work_i2c_poll); + mod_timer(&tsdata->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS)); +} + +static void edt_ft5x06_ts_work_i2c_poll(struct work_struct *work) +{ + struct edt_ft5x06_ts_data *tsdata = container_of(work, + struct edt_ft5x06_ts_data, work_i2c_poll); + + edt_ft5x06_ts_isr(0, tsdata); +} + static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; @@ -614,7 +637,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) return -EINVAL; } - disable_irq(client->irq); + if (client->irq) { + disable_irq(client->irq); + } if (!tsdata->raw_buffer) { tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y * @@ -657,7 +682,8 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) kfree(tsdata->raw_buffer); tsdata->raw_buffer = NULL; tsdata->factory_mode = false; - enable_irq(client->irq); + if (client->irq) + enable_irq(client->irq); return error; } @@ -698,7 +724,8 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) tsdata->raw_buffer = NULL; edt_ft5x06_restore_reg_parameters(tsdata); - enable_irq(client->irq); + if (client->irq) + enable_irq(client->irq); return 0; } @@ -1331,18 +1358,27 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) dev_err(&client->dev, "Unable to init MT slots.\n"); return error; } - - 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; + if (client->irq) { + 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; + } + } else { + tsdata->init_td_status = -1; /* filter bogus initial data */ + INIT_WORK(&tsdata->work_i2c_poll, + edt_ft5x06_ts_work_i2c_poll); + timer_setup(&tsdata->timer, edt_ft5x06_ts_irq_poll_timer, 0); + tsdata->timer.expires = + jiffies + msecs_to_jiffies(FIRST_POLL_DELAY_MS); + add_timer(&tsdata->timer); } error = input_register_device(input); @@ -1364,6 +1400,11 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client) { struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + if (!client->irq) { + del_timer(&tsdata->timer); + cancel_work_sync(&tsdata->work_i2c_poll); + } + edt_ft5x06_ts_teardown_debugfs(tsdata); } @@ -1395,7 +1436,8 @@ static int edt_ft5x06_ts_suspend(struct device *dev) * settings. Disable the irq to avoid adjusting each host till the * device is back in a full functional state. */ - disable_irq(tsdata->client->irq); + if (tsdata->client->irq) + disable_irq(tsdata->client->irq); gpiod_set_value_cansleep(reset_gpio, 1); usleep_range(1000, 2000);