bfb26e8f02850c09a99c7d7d3b701251d4cf2555
[openwrt/staging/ansuel.git] /
1 From 5e768fe3e14ce0026a297dffd0d3c28ae2f73e72 Mon Sep 17 00:00:00 2001
2 From: Dave Stevenson <dave.stevenson@raspberrypi.com>
3 Date: Fri, 6 Nov 2020 18:45:10 +0000
4 Subject: [PATCH 0262/1085] Input: edt-ft5x06: Poll the device if no interrupt
5 is configured.
6
7 Not all systems have the interrupt line wired up, so switch to
8 polling the touchscreen off a timer if no interrupt line is
9 configured.
10
11 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
12
13 input: edt-ft5x06: Handle unreliable TOUCH_UP events
14
15 The ft5x06 is unreliable in sending touch up events, so some
16 touch IDs can become stuck in the detected state.
17
18 Ensure that IDs that are unreported by the controller are
19 released.
20
21 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
22
23 input: edt-ft5x06: Only look at the number of points reported
24
25 Register 0x02 in the FT5x06 is TD_STATUS containing the number
26 of valid touch points being reported.
27
28 Iterate over that number of points rather than all that are
29 supported on the device.
30
31 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
32
33 input: edt-ft5x06: Only read data for number of points reported
34
35 Rather than always reading the maximum number of points supported
36 by the chip (which may be as high as 10), read the number of
37 active points first, and read data for just those.
38 In most cases this will result in less data on the I2C bus,
39 with only the maximum touch points taking more due to a second
40 read that has to configure the start address.
41
42 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
43
44 input: edt-ft5x06: Fix patch reading only the number of points reported
45
46 Fix bad conflict resolution from upstream updates. Need to read
47 from tsdata->tdata_offset bytes, not from tsdata->offset.
48 Also fix logging of i2c read errors to cover both transactions.
49
50 Fixes: 7216fcfe2e5f ("input: edt-ft5x06: Only read data for number of points reported")
51 Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
52 ---
53 drivers/input/touchscreen/edt-ft5x06.c | 93 ++++++++++++++++++++++----
54 1 file changed, 80 insertions(+), 13 deletions(-)
55
56 --- a/drivers/input/touchscreen/edt-ft5x06.c
57 +++ b/drivers/input/touchscreen/edt-ft5x06.c
58 @@ -80,6 +80,8 @@
59 #define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc)
60 #define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f)
61
62 +#define POLL_INTERVAL_MS 17 /* 17ms = 60fps */
63 +
64 enum edt_pmode {
65 EDT_PMODE_NOT_SUPPORTED,
66 EDT_PMODE_HIBERNATE,
67 @@ -139,6 +141,7 @@ struct edt_ft5x06_ts_data {
68 u8 tdata_cmd;
69 int tdata_len;
70 int tdata_offset;
71 + unsigned int known_ids;
72
73 char name[EDT_NAME_LEN];
74 char fw_version[EDT_NAME_LEN];
75 @@ -147,6 +150,9 @@ struct edt_ft5x06_ts_data {
76 enum edt_ver version;
77 unsigned int crc_errors;
78 unsigned int header_errors;
79 +
80 + struct timer_list timer;
81 + struct work_struct work_i2c_poll;
82 };
83
84 struct edt_i2c_chip_data {
85 @@ -303,17 +309,34 @@ static irqreturn_t edt_ft5x06_ts_isr(int
86 u8 rdbuf[63];
87 int i, type, x, y, id;
88 int error;
89 + int num_points;
90 + unsigned int active_ids = 0, known_ids = tsdata->known_ids;
91 + long released_ids;
92 + int b = 0;
93
94 memset(rdbuf, 0, sizeof(rdbuf));
95 error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf,
96 tsdata->tdata_len);
97 + if (tsdata->version == EDT_M06) {
98 + num_points = tsdata->max_support_points;
99 + } else {
100 + /* Register 2 is TD_STATUS, containing the number of touch
101 + * points.
102 + */
103 + num_points = min(rdbuf[2] & 0xf, tsdata->max_support_points);
104 + if (!error && num_points)
105 + error = regmap_bulk_read(tsdata->regmap,
106 + tsdata->tdata_offset,
107 + &rdbuf[tsdata->tdata_offset],
108 + tsdata->point_len * num_points);
109 + }
110 if (error) {
111 dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
112 error);
113 goto out;
114 }
115
116 - for (i = 0; i < tsdata->max_support_points; i++) {
117 + for (i = 0; i < num_points; i++) {
118 u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset];
119
120 type = buf[0] >> 6;
121 @@ -335,10 +358,25 @@ static irqreturn_t edt_ft5x06_ts_isr(int
122
123 input_mt_slot(tsdata->input, id);
124 if (input_mt_report_slot_state(tsdata->input, MT_TOOL_FINGER,
125 - type != TOUCH_EVENT_UP))
126 + type != TOUCH_EVENT_UP)) {
127 touchscreen_report_pos(tsdata->input, &tsdata->prop,
128 x, y, true);
129 + active_ids |= BIT(id);
130 + } else {
131 + known_ids &= ~BIT(id);
132 + }
133 + }
134 +
135 + /* One issue with the device is the TOUCH_UP message is not always
136 + * returned. Instead track which ids we know about and report when they
137 + * are no longer updated
138 + */
139 + released_ids = known_ids & ~active_ids;
140 + for_each_set_bit_from(b, &released_ids, tsdata->max_support_points) {
141 + input_mt_slot(tsdata->input, b);
142 + input_mt_report_slot_inactive(tsdata->input);
143 }
144 + tsdata->known_ids = active_ids;
145
146 input_mt_report_pointer_emulation(tsdata->input, true);
147 input_sync(tsdata->input);
148 @@ -347,6 +385,22 @@ out:
149 return IRQ_HANDLED;
150 }
151
152 +static void edt_ft5x06_ts_irq_poll_timer(struct timer_list *t)
153 +{
154 + struct edt_ft5x06_ts_data *tsdata = from_timer(tsdata, t, timer);
155 +
156 + schedule_work(&tsdata->work_i2c_poll);
157 + mod_timer(&tsdata->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS));
158 +}
159 +
160 +static void edt_ft5x06_ts_work_i2c_poll(struct work_struct *work)
161 +{
162 + struct edt_ft5x06_ts_data *tsdata = container_of(work,
163 + struct edt_ft5x06_ts_data, work_i2c_poll);
164 +
165 + edt_ft5x06_ts_isr(0, tsdata);
166 +}
167 +
168 struct edt_ft5x06_attribute {
169 struct device_attribute dattr;
170 size_t field_offset;
171 @@ -1053,20 +1107,23 @@ static void edt_ft5x06_ts_get_parameters
172 static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata)
173 {
174 int crclen;
175 + int points;
176
177 if (tsdata->version == EDT_M06) {
178 tsdata->tdata_cmd = 0xf9;
179 tsdata->tdata_offset = 5;
180 tsdata->point_len = 4;
181 crclen = 1;
182 + points = tsdata->max_support_points;
183 } else {
184 tsdata->tdata_cmd = 0x0;
185 tsdata->tdata_offset = 3;
186 tsdata->point_len = 6;
187 crclen = 0;
188 + points = 0;
189 }
190
191 - tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points +
192 + tsdata->tdata_len = tsdata->point_len * points +
193 tsdata->tdata_offset + crclen;
194 }
195
196 @@ -1317,17 +1374,27 @@ static int edt_ft5x06_ts_probe(struct i2
197 return error;
198 }
199
200 - irq_flags = irq_get_trigger_type(client->irq);
201 - if (irq_flags == IRQF_TRIGGER_NONE)
202 - irq_flags = IRQF_TRIGGER_FALLING;
203 - irq_flags |= IRQF_ONESHOT;
204 -
205 - error = devm_request_threaded_irq(&client->dev, client->irq,
206 - NULL, edt_ft5x06_ts_isr, irq_flags,
207 - client->name, tsdata);
208 - if (error) {
209 - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
210 - return error;
211 + if (client->irq) {
212 + irq_flags = irq_get_trigger_type(client->irq);
213 + if (irq_flags == IRQF_TRIGGER_NONE)
214 + irq_flags = IRQF_TRIGGER_FALLING;
215 + irq_flags |= IRQF_ONESHOT;
216 +
217 + error = devm_request_threaded_irq(&client->dev, client->irq,
218 + NULL, edt_ft5x06_ts_isr,
219 + irq_flags, client->name,
220 + tsdata);
221 + if (error) {
222 + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
223 + return error;
224 + }
225 + } else {
226 + INIT_WORK(&tsdata->work_i2c_poll,
227 + edt_ft5x06_ts_work_i2c_poll);
228 + timer_setup(&tsdata->timer, edt_ft5x06_ts_irq_poll_timer, 0);
229 + tsdata->timer.expires = jiffies +
230 + msecs_to_jiffies(POLL_INTERVAL_MS);
231 + add_timer(&tsdata->timer);
232 }
233
234 error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);