From 933a2c3d1cba1eb4af8c1d493889bfb6e520a149 Mon Sep 17 00:00:00 2001 From: andreili Date: Sun, 27 Jul 2025 12:12:32 +0200 Subject: [PATCH] Add no-IRQ mode support for EDT touch. --- .../printer_edt_ft5x06_noIRQ_support.patch | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 patch/kernel/printer_edt_ft5x06_noIRQ_support.patch diff --git a/patch/kernel/printer_edt_ft5x06_noIRQ_support.patch b/patch/kernel/printer_edt_ft5x06_noIRQ_support.patch new file mode 100644 index 0000000..aaecf35 --- /dev/null +++ b/patch/kernel/printer_edt_ft5x06_noIRQ_support.patch @@ -0,0 +1,161 @@ +diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c +index 0d7bf18e2508..535e84de038e 100644 +--- a/drivers/input/touchscreen/edt-ft5x06.c ++++ b/drivers/input/touchscreen/edt-ft5x06.c +@@ -77,6 +77,10 @@ + #define EDT_DEFAULT_NUM_X 1024 + #define EDT_DEFAULT_NUM_Y 1024 + ++#define RESET_DELAY_MS 300 /* reset deassert to I2C */ ++#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) + +@@ -135,6 +139,7 @@ struct edt_ft5x06_ts_data { + int offset_y; + int report_rate; + int max_support_points; ++ unsigned int known_ids; + int point_len; + u8 tdata_cmd; + int tdata_len; +@@ -147,6 +152,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 { +@@ -303,6 +311,10 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) + u8 rdbuf[63]; + int i, type, x, y, id; + int error; ++ unsigned int active_ids = 0, known_ids = tsdata->known_ids; ++ long released_ids; ++ int b = 0; ++ unsigned int num_points; + + memset(rdbuf, 0, sizeof(rdbuf)); + error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf, +@@ -313,7 +325,16 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) + goto out; + } + +- for (i = 0; i < tsdata->max_support_points; i++) { ++ /* M09/M12 does not send header or CRC */ ++ if (tsdata->version == EDT_M06) { ++ num_points = tsdata->max_support_points; ++ } else { ++ /* Register 2 is TD_STATUS, containing the number of touch ++ * points. ++ */ ++ num_points = min(rdbuf[2] & 0xf, tsdata->max_support_points); ++ } ++ for (i = 0; i < num_points; i++) { + u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset]; + + type = buf[0] >> 6; +@@ -335,11 +356,26 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) + + input_mt_slot(tsdata->input, id); + if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER, +- type != TOUCH_EVENT_UP)) ++ type != TOUCH_EVENT_UP)) { + touchscreen_report_pos(tsdata->input, &tsdata->prop, + x, y, true); ++ active_ids |= BIT(id); ++ } else { ++ known_ids &= ~BIT(id); ++ } + } + ++ /* One issue with the device is the TOUCH_UP message is not always ++ * returned. Instead track which ids we know about and report when they ++ * are no longer updated ++ */ ++ released_ids = known_ids & ~active_ids; ++ for_each_set_bit_from(b, &released_ids, tsdata->max_support_points) { ++ input_mt_slot(tsdata->input, b); ++ input_mt_report_slot_inactive(tsdata->input); ++ } ++ tsdata->known_ids = active_ids; ++ + input_mt_report_pointer_emulation(tsdata->input, true); + input_sync(tsdata->input); + +@@ -347,6 +383,22 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) + return IRQ_HANDLED; + } + ++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); ++} ++ + struct edt_ft5x06_attribute { + struct device_attribute dattr; + size_t field_offset; +@@ -1332,17 +1384,26 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) + 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; ++ 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; ++ 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 { ++ 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 +1425,10 @@ 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); + } +