]>
Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
71f8e38a DT |
2 | #include <linux/delay.h> |
3 | #include <linux/gpio/consumer.h> | |
5c6a7a62 | 4 | #include <linux/i2c.h> |
5c6a7a62 OS |
5 | #include <linux/input.h> |
6 | #include <linux/input/mt.h> | |
f67cc3e9 | 7 | #include <linux/input/touchscreen.h> |
71f8e38a DT |
8 | #include <linux/interrupt.h> |
9 | #include <linux/module.h> | |
49588917 | 10 | #include <linux/of_device.h> |
b32fbeae | 11 | #include <linux/sizes.h> |
71f8e38a | 12 | #include <linux/slab.h> |
e3559442 | 13 | #include <asm/unaligned.h> |
5c6a7a62 | 14 | |
71f8e38a | 15 | #define ILI2XXX_POLL_PERIOD 20 |
5c6a7a62 | 16 | |
ef536abd DT |
17 | #define ILI210X_DATA_SIZE 64 |
18 | #define ILI211X_DATA_SIZE 43 | |
19 | #define ILI251X_DATA_SIZE1 31 | |
20 | #define ILI251X_DATA_SIZE2 20 | |
21 | ||
5c6a7a62 OS |
22 | /* Touchscreen commands */ |
23 | #define REG_TOUCHDATA 0x10 | |
24 | #define REG_PANEL_INFO 0x20 | |
5c6a7a62 OS |
25 | #define REG_CALIBRATE 0xcc |
26 | ||
ef536abd DT |
27 | struct ili2xxx_chip { |
28 | int (*read_reg)(struct i2c_client *client, u8 reg, | |
29 | void *buf, size_t len); | |
30 | int (*get_touch_data)(struct i2c_client *client, u8 *data); | |
31 | bool (*parse_touch_data)(const u8 *data, unsigned int finger, | |
32 | unsigned int *x, unsigned int *y); | |
33 | bool (*continue_polling)(const u8 *data, bool touch); | |
34 | unsigned int max_touches; | |
b32fbeae | 35 | unsigned int resolution; |
cc12ba18 | 36 | bool has_calibrate_reg; |
49588917 MV |
37 | }; |
38 | ||
5c6a7a62 OS |
39 | struct ili210x { |
40 | struct i2c_client *client; | |
41 | struct input_dev *input; | |
201f3c80 | 42 | struct gpio_desc *reset_gpio; |
f67cc3e9 | 43 | struct touchscreen_properties prop; |
ef536abd | 44 | const struct ili2xxx_chip *chip; |
71f8e38a | 45 | bool stop; |
5c6a7a62 OS |
46 | }; |
47 | ||
ef536abd DT |
48 | static int ili210x_read_reg(struct i2c_client *client, |
49 | u8 reg, void *buf, size_t len) | |
5c6a7a62 | 50 | { |
ef536abd | 51 | struct i2c_msg msg[] = { |
5c6a7a62 OS |
52 | { |
53 | .addr = client->addr, | |
54 | .flags = 0, | |
55 | .len = 1, | |
56 | .buf = ®, | |
57 | }, | |
58 | { | |
59 | .addr = client->addr, | |
60 | .flags = I2C_M_RD, | |
61 | .len = len, | |
62 | .buf = buf, | |
63 | } | |
64 | }; | |
ef536abd | 65 | int error, ret; |
5c6a7a62 | 66 | |
ef536abd DT |
67 | ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); |
68 | if (ret != ARRAY_SIZE(msg)) { | |
69 | error = ret < 0 ? ret : -EIO; | |
70 | dev_err(&client->dev, "%s failed: %d\n", __func__, error); | |
71 | return error; | |
49588917 MV |
72 | } |
73 | ||
74 | return 0; | |
75 | } | |
76 | ||
ef536abd | 77 | static int ili210x_read_touch_data(struct i2c_client *client, u8 *data) |
49588917 | 78 | { |
ef536abd DT |
79 | return ili210x_read_reg(client, REG_TOUCHDATA, |
80 | data, ILI210X_DATA_SIZE); | |
5c6a7a62 OS |
81 | } |
82 | ||
ef536abd | 83 | static bool ili210x_touchdata_to_coords(const u8 *touchdata, |
e3559442 MV |
84 | unsigned int finger, |
85 | unsigned int *x, unsigned int *y) | |
86 | { | |
e3559442 MV |
87 | if (touchdata[0] & BIT(finger)) |
88 | return false; | |
89 | ||
90 | *x = get_unaligned_be16(touchdata + 1 + (finger * 4) + 0); | |
91 | *y = get_unaligned_be16(touchdata + 1 + (finger * 4) + 2); | |
92 | ||
93 | return true; | |
94 | } | |
95 | ||
ef536abd DT |
96 | static bool ili210x_check_continue_polling(const u8 *data, bool touch) |
97 | { | |
98 | return data[0] & 0xf3; | |
99 | } | |
100 | ||
101 | static const struct ili2xxx_chip ili210x_chip = { | |
102 | .read_reg = ili210x_read_reg, | |
103 | .get_touch_data = ili210x_read_touch_data, | |
104 | .parse_touch_data = ili210x_touchdata_to_coords, | |
105 | .continue_polling = ili210x_check_continue_polling, | |
106 | .max_touches = 2, | |
cc12ba18 | 107 | .has_calibrate_reg = true, |
ef536abd DT |
108 | }; |
109 | ||
110 | static int ili211x_read_touch_data(struct i2c_client *client, u8 *data) | |
111 | { | |
112 | s16 sum = 0; | |
113 | int error; | |
114 | int ret; | |
115 | int i; | |
116 | ||
117 | ret = i2c_master_recv(client, data, ILI211X_DATA_SIZE); | |
118 | if (ret != ILI211X_DATA_SIZE) { | |
119 | error = ret < 0 ? ret : -EIO; | |
120 | dev_err(&client->dev, "%s failed: %d\n", __func__, error); | |
121 | return error; | |
122 | } | |
123 | ||
124 | /* This chip uses custom checksum at the end of data */ | |
125 | for (i = 0; i < ILI211X_DATA_SIZE - 1; i++) | |
126 | sum = (sum + data[i]) & 0xff; | |
127 | ||
128 | if ((-sum & 0xff) != data[ILI211X_DATA_SIZE - 1]) { | |
129 | dev_err(&client->dev, | |
130 | "CRC error (crc=0x%02x expected=0x%02x)\n", | |
131 | sum, data[ILI211X_DATA_SIZE - 1]); | |
132 | return -EIO; | |
133 | } | |
134 | ||
135 | return 0; | |
136 | } | |
137 | ||
138 | static bool ili211x_touchdata_to_coords(const u8 *touchdata, | |
eb91ecc9 MV |
139 | unsigned int finger, |
140 | unsigned int *x, unsigned int *y) | |
141 | { | |
142 | u32 data; | |
143 | ||
eb91ecc9 MV |
144 | data = get_unaligned_be32(touchdata + 1 + (finger * 4) + 0); |
145 | if (data == 0xffffffff) /* Finger up */ | |
146 | return false; | |
147 | ||
148 | *x = ((touchdata[1 + (finger * 4) + 0] & 0xf0) << 4) | | |
149 | touchdata[1 + (finger * 4) + 1]; | |
150 | *y = ((touchdata[1 + (finger * 4) + 0] & 0x0f) << 8) | | |
151 | touchdata[1 + (finger * 4) + 2]; | |
152 | ||
153 | return true; | |
154 | } | |
155 | ||
ef536abd DT |
156 | static bool ili211x_decline_polling(const u8 *data, bool touch) |
157 | { | |
158 | return false; | |
159 | } | |
160 | ||
161 | static const struct ili2xxx_chip ili211x_chip = { | |
162 | .read_reg = ili210x_read_reg, | |
163 | .get_touch_data = ili211x_read_touch_data, | |
164 | .parse_touch_data = ili211x_touchdata_to_coords, | |
165 | .continue_polling = ili211x_decline_polling, | |
166 | .max_touches = 10, | |
b32fbeae | 167 | .resolution = 2048, |
ef536abd DT |
168 | }; |
169 | ||
d0c5e7d4 LW |
170 | static bool ili212x_touchdata_to_coords(const u8 *touchdata, |
171 | unsigned int finger, | |
172 | unsigned int *x, unsigned int *y) | |
173 | { | |
174 | u16 val; | |
175 | ||
176 | val = get_unaligned_be16(touchdata + 3 + (finger * 5) + 0); | |
177 | if (!(val & BIT(15))) /* Touch indication */ | |
178 | return false; | |
179 | ||
180 | *x = val & 0x3fff; | |
181 | *y = get_unaligned_be16(touchdata + 3 + (finger * 5) + 2); | |
182 | ||
183 | return true; | |
184 | } | |
185 | ||
186 | static bool ili212x_check_continue_polling(const u8 *data, bool touch) | |
187 | { | |
188 | return touch; | |
189 | } | |
190 | ||
191 | static const struct ili2xxx_chip ili212x_chip = { | |
192 | .read_reg = ili210x_read_reg, | |
193 | .get_touch_data = ili210x_read_touch_data, | |
194 | .parse_touch_data = ili212x_touchdata_to_coords, | |
195 | .continue_polling = ili212x_check_continue_polling, | |
196 | .max_touches = 10, | |
197 | .has_calibrate_reg = true, | |
198 | }; | |
199 | ||
ef536abd DT |
200 | static int ili251x_read_reg(struct i2c_client *client, |
201 | u8 reg, void *buf, size_t len) | |
202 | { | |
203 | int error; | |
204 | int ret; | |
205 | ||
206 | ret = i2c_master_send(client, ®, 1); | |
207 | if (ret == 1) { | |
208 | usleep_range(5000, 5500); | |
209 | ||
210 | ret = i2c_master_recv(client, buf, len); | |
211 | if (ret == len) | |
212 | return 0; | |
213 | } | |
214 | ||
215 | error = ret < 0 ? ret : -EIO; | |
216 | dev_err(&client->dev, "%s failed: %d\n", __func__, error); | |
217 | return ret; | |
218 | } | |
219 | ||
220 | static int ili251x_read_touch_data(struct i2c_client *client, u8 *data) | |
221 | { | |
222 | int error; | |
223 | ||
224 | error = ili251x_read_reg(client, REG_TOUCHDATA, | |
225 | data, ILI251X_DATA_SIZE1); | |
226 | if (!error && data[0] == 2) { | |
227 | error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1, | |
228 | ILI251X_DATA_SIZE2); | |
229 | if (error >= 0 && error != ILI251X_DATA_SIZE2) | |
230 | error = -EIO; | |
231 | } | |
232 | ||
233 | return error; | |
234 | } | |
235 | ||
236 | static bool ili251x_touchdata_to_coords(const u8 *touchdata, | |
49588917 MV |
237 | unsigned int finger, |
238 | unsigned int *x, unsigned int *y) | |
239 | { | |
ef536abd | 240 | u16 val; |
49588917 | 241 | |
ef536abd DT |
242 | val = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); |
243 | if (!(val & BIT(15))) /* Touch indication */ | |
49588917 MV |
244 | return false; |
245 | ||
ef536abd | 246 | *x = val & 0x3fff; |
49588917 MV |
247 | *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); |
248 | ||
249 | return true; | |
250 | } | |
251 | ||
ef536abd DT |
252 | static bool ili251x_check_continue_polling(const u8 *data, bool touch) |
253 | { | |
254 | return touch; | |
255 | } | |
256 | ||
257 | static const struct ili2xxx_chip ili251x_chip = { | |
258 | .read_reg = ili251x_read_reg, | |
259 | .get_touch_data = ili251x_read_touch_data, | |
260 | .parse_touch_data = ili251x_touchdata_to_coords, | |
261 | .continue_polling = ili251x_check_continue_polling, | |
262 | .max_touches = 10, | |
cc12ba18 | 263 | .has_calibrate_reg = true, |
ef536abd DT |
264 | }; |
265 | ||
e3559442 | 266 | static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) |
5c6a7a62 | 267 | { |
e3559442 | 268 | struct input_dev *input = priv->input; |
5c6a7a62 | 269 | int i; |
ef536abd | 270 | bool contact = false, touch; |
49588917 | 271 | unsigned int x = 0, y = 0; |
5c6a7a62 | 272 | |
ef536abd DT |
273 | for (i = 0; i < priv->chip->max_touches; i++) { |
274 | touch = priv->chip->parse_touch_data(touchdata, i, &x, &y); | |
49588917 | 275 | |
f67cc3e9 | 276 | input_mt_slot(input, i); |
ef536abd DT |
277 | if (input_mt_report_slot_state(input, MT_TOOL_FINGER, touch)) { |
278 | touchscreen_report_pos(input, &priv->prop, x, y, true); | |
279 | contact = true; | |
280 | } | |
5c6a7a62 OS |
281 | } |
282 | ||
283 | input_mt_report_pointer_emulation(input, false); | |
284 | input_sync(input); | |
e3559442 | 285 | |
49588917 | 286 | return contact; |
5c6a7a62 OS |
287 | } |
288 | ||
71f8e38a | 289 | static irqreturn_t ili210x_irq(int irq, void *irq_data) |
5c6a7a62 | 290 | { |
71f8e38a | 291 | struct ili210x *priv = irq_data; |
5c6a7a62 | 292 | struct i2c_client *client = priv->client; |
ef536abd DT |
293 | const struct ili2xxx_chip *chip = priv->chip; |
294 | u8 touchdata[ILI210X_DATA_SIZE] = { 0 }; | |
295 | bool keep_polling; | |
e3559442 | 296 | bool touch; |
71f8e38a DT |
297 | int error; |
298 | ||
299 | do { | |
ef536abd | 300 | error = chip->get_touch_data(client, touchdata); |
71f8e38a DT |
301 | if (error) { |
302 | dev_err(&client->dev, | |
ef536abd | 303 | "Unable to get touch data: %d\n", error); |
71f8e38a DT |
304 | break; |
305 | } | |
5c6a7a62 | 306 | |
71f8e38a | 307 | touch = ili210x_report_events(priv, touchdata); |
ef536abd DT |
308 | keep_polling = chip->continue_polling(touchdata, touch); |
309 | if (keep_polling) | |
71f8e38a | 310 | msleep(ILI2XXX_POLL_PERIOD); |
ef536abd | 311 | } while (!priv->stop && keep_polling); |
5c6a7a62 OS |
312 | |
313 | return IRQ_HANDLED; | |
314 | } | |
315 | ||
316 | static ssize_t ili210x_calibrate(struct device *dev, | |
317 | struct device_attribute *attr, | |
318 | const char *buf, size_t count) | |
319 | { | |
320 | struct i2c_client *client = to_i2c_client(dev); | |
321 | struct ili210x *priv = i2c_get_clientdata(client); | |
322 | unsigned long calibrate; | |
323 | int rc; | |
324 | u8 cmd = REG_CALIBRATE; | |
325 | ||
326 | if (kstrtoul(buf, 10, &calibrate)) | |
327 | return -EINVAL; | |
328 | ||
329 | if (calibrate > 1) | |
330 | return -EINVAL; | |
331 | ||
332 | if (calibrate) { | |
333 | rc = i2c_master_send(priv->client, &cmd, sizeof(cmd)); | |
334 | if (rc != sizeof(cmd)) | |
335 | return -EIO; | |
336 | } | |
337 | ||
338 | return count; | |
339 | } | |
b27c0d0c | 340 | static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate); |
5c6a7a62 OS |
341 | |
342 | static struct attribute *ili210x_attributes[] = { | |
343 | &dev_attr_calibrate.attr, | |
344 | NULL, | |
345 | }; | |
346 | ||
cc12ba18 SVA |
347 | static umode_t ili210x_calibrate_visible(struct kobject *kobj, |
348 | struct attribute *attr, int index) | |
349 | { | |
350 | struct device *dev = kobj_to_dev(kobj); | |
351 | struct i2c_client *client = to_i2c_client(dev); | |
352 | struct ili210x *priv = i2c_get_clientdata(client); | |
353 | ||
fbd1ec00 | 354 | return priv->chip->has_calibrate_reg ? attr->mode : 0; |
cc12ba18 SVA |
355 | } |
356 | ||
5c6a7a62 OS |
357 | static const struct attribute_group ili210x_attr_group = { |
358 | .attrs = ili210x_attributes, | |
cc12ba18 | 359 | .is_visible = ili210x_calibrate_visible, |
5c6a7a62 OS |
360 | }; |
361 | ||
201f3c80 MV |
362 | static void ili210x_power_down(void *data) |
363 | { | |
364 | struct gpio_desc *reset_gpio = data; | |
365 | ||
366 | gpiod_set_value_cansleep(reset_gpio, 1); | |
367 | } | |
368 | ||
71f8e38a | 369 | static void ili210x_stop(void *data) |
1bdec5d9 MV |
370 | { |
371 | struct ili210x *priv = data; | |
372 | ||
71f8e38a DT |
373 | /* Tell ISR to quit even if there is a contact. */ |
374 | priv->stop = true; | |
1bdec5d9 MV |
375 | } |
376 | ||
5298cc4c | 377 | static int ili210x_i2c_probe(struct i2c_client *client, |
ef536abd | 378 | const struct i2c_device_id *id) |
5c6a7a62 OS |
379 | { |
380 | struct device *dev = &client->dev; | |
ef536abd | 381 | const struct ili2xxx_chip *chip; |
5c6a7a62 | 382 | struct ili210x *priv; |
201f3c80 | 383 | struct gpio_desc *reset_gpio; |
5c6a7a62 | 384 | struct input_dev *input; |
5c6a7a62 | 385 | int error; |
b32fbeae | 386 | unsigned int max_xy; |
5c6a7a62 OS |
387 | |
388 | dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); | |
389 | ||
ef536abd DT |
390 | chip = device_get_match_data(dev); |
391 | if (!chip && id) | |
392 | chip = (const struct ili2xxx_chip *)id->driver_data; | |
393 | if (!chip) { | |
394 | dev_err(&client->dev, "unknown device model\n"); | |
395 | return -ENODEV; | |
396 | } | |
397 | ||
5c6a7a62 OS |
398 | if (client->irq <= 0) { |
399 | dev_err(dev, "No IRQ!\n"); | |
400 | return -EINVAL; | |
401 | } | |
402 | ||
201f3c80 MV |
403 | reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); |
404 | if (IS_ERR(reset_gpio)) | |
405 | return PTR_ERR(reset_gpio); | |
406 | ||
407 | if (reset_gpio) { | |
408 | error = devm_add_action_or_reset(dev, ili210x_power_down, | |
409 | reset_gpio); | |
410 | if (error) | |
411 | return error; | |
412 | ||
413 | usleep_range(50, 100); | |
414 | gpiod_set_value_cansleep(reset_gpio, 0); | |
415 | msleep(100); | |
416 | } | |
417 | ||
12294577 MV |
418 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
419 | if (!priv) | |
420 | return -ENOMEM; | |
421 | ||
422 | input = devm_input_allocate_device(dev); | |
423 | if (!input) | |
424 | return -ENOMEM; | |
425 | ||
426 | priv->client = client; | |
427 | priv->input = input; | |
12294577 | 428 | priv->reset_gpio = reset_gpio; |
ef536abd | 429 | priv->chip = chip; |
12294577 MV |
430 | i2c_set_clientdata(client, priv); |
431 | ||
5c6a7a62 OS |
432 | /* Setup input device */ |
433 | input->name = "ILI210x Touchscreen"; | |
434 | input->id.bustype = BUS_I2C; | |
5c6a7a62 | 435 | |
5c6a7a62 | 436 | /* Multi touch */ |
b32fbeae SVA |
437 | max_xy = (chip->resolution ?: SZ_64K) - 1; |
438 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0); | |
439 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0); | |
f67cc3e9 | 440 | touchscreen_parse_properties(input, true, &priv->prop); |
43f06a4c | 441 | |
ef536abd DT |
442 | error = input_mt_init_slots(input, priv->chip->max_touches, |
443 | INPUT_MT_DIRECT); | |
43f06a4c DT |
444 | if (error) { |
445 | dev_err(dev, "Unable to set up slots, err: %d\n", error); | |
446 | return error; | |
447 | } | |
5c6a7a62 | 448 | |
71f8e38a DT |
449 | error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq, |
450 | IRQF_ONESHOT, client->name, priv); | |
5c6a7a62 OS |
451 | if (error) { |
452 | dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", | |
453 | error); | |
1bdec5d9 | 454 | return error; |
5c6a7a62 OS |
455 | } |
456 | ||
71f8e38a DT |
457 | error = devm_add_action_or_reset(dev, ili210x_stop, priv); |
458 | if (error) | |
459 | return error; | |
460 | ||
576057bf | 461 | error = devm_device_add_group(dev, &ili210x_attr_group); |
5c6a7a62 OS |
462 | if (error) { |
463 | dev_err(dev, "Unable to create sysfs attributes, err: %d\n", | |
464 | error); | |
1bdec5d9 | 465 | return error; |
5c6a7a62 OS |
466 | } |
467 | ||
468 | error = input_register_device(priv->input); | |
469 | if (error) { | |
971bd8fa | 470 | dev_err(dev, "Cannot register input device, err: %d\n", error); |
576057bf | 471 | return error; |
5c6a7a62 OS |
472 | } |
473 | ||
5c6a7a62 | 474 | return 0; |
5c6a7a62 OS |
475 | } |
476 | ||
5c6a7a62 | 477 | static const struct i2c_device_id ili210x_i2c_id[] = { |
ef536abd DT |
478 | { "ili210x", (long)&ili210x_chip }, |
479 | { "ili2117", (long)&ili211x_chip }, | |
d0c5e7d4 | 480 | { "ili2120", (long)&ili212x_chip }, |
ef536abd | 481 | { "ili251x", (long)&ili251x_chip }, |
5c6a7a62 OS |
482 | { } |
483 | }; | |
484 | MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); | |
485 | ||
c5d0e4b5 | 486 | static const struct of_device_id ili210x_dt_ids[] = { |
ef536abd DT |
487 | { .compatible = "ilitek,ili210x", .data = &ili210x_chip }, |
488 | { .compatible = "ilitek,ili2117", .data = &ili211x_chip }, | |
d0c5e7d4 | 489 | { .compatible = "ilitek,ili2120", .data = &ili212x_chip }, |
ef536abd DT |
490 | { .compatible = "ilitek,ili251x", .data = &ili251x_chip }, |
491 | { } | |
c5d0e4b5 MV |
492 | }; |
493 | MODULE_DEVICE_TABLE(of, ili210x_dt_ids); | |
494 | ||
5c6a7a62 OS |
495 | static struct i2c_driver ili210x_ts_driver = { |
496 | .driver = { | |
497 | .name = "ili210x_i2c", | |
c5d0e4b5 | 498 | .of_match_table = ili210x_dt_ids, |
5c6a7a62 OS |
499 | }, |
500 | .id_table = ili210x_i2c_id, | |
501 | .probe = ili210x_i2c_probe, | |
5c6a7a62 OS |
502 | }; |
503 | ||
504 | module_i2c_driver(ili210x_ts_driver); | |
505 | ||
506 | MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>"); | |
507 | MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver"); | |
508 | MODULE_LICENSE("GPL"); |