1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
2 | /* |
3 | * ILITEK Touch IC driver for 23XX, 25XX and Lego series |
4 | * |
5 | * Copyright (C) 2011 ILI Technology Corporation. |
6 | * Copyright (C) 2020 Luca Hsu <luca_hsu@ilitek.com> |
7 | * Copyright (C) 2021 Joe Hung <joe_hung@ilitek.com> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/input.h> |
13 | #include <linux/input/mt.h> |
14 | #include <linux/i2c.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/delay.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/gpio/consumer.h> |
19 | #include <linux/errno.h> |
20 | #include <linux/acpi.h> |
21 | #include <linux/input/touchscreen.h> |
22 | #include <linux/unaligned.h> |
23 | |
24 | |
25 | #define ILITEK_TS_NAME "ilitek_ts" |
26 | #define BL_V1_8 0x108 |
27 | #define BL_V1_7 0x107 |
28 | #define BL_V1_6 0x106 |
29 | |
30 | #define ILITEK_TP_CMD_GET_TP_RES 0x20 |
31 | #define ILITEK_TP_CMD_GET_SCRN_RES 0x21 |
32 | #define ILITEK_TP_CMD_SET_IC_SLEEP 0x30 |
33 | #define ILITEK_TP_CMD_SET_IC_WAKE 0x31 |
34 | #define ILITEK_TP_CMD_GET_FW_VER 0x40 |
35 | #define ILITEK_TP_CMD_GET_PRL_VER 0x42 |
36 | #define ILITEK_TP_CMD_GET_MCU_VER 0x61 |
37 | #define ILITEK_TP_CMD_GET_IC_MODE 0xC0 |
38 | |
39 | #define ILITEK_TP_I2C_REPORT_ID 0x48 |
40 | |
41 | #define REPORT_COUNT_ADDRESS 61 |
42 | #define ILITEK_SUPPORT_MAX_POINT 40 |
43 | |
44 | struct ilitek_protocol_info { |
45 | u16 ver; |
46 | u8 ver_major; |
47 | }; |
48 | |
49 | struct ilitek_ts_data { |
50 | struct i2c_client *client; |
51 | struct gpio_desc *reset_gpio; |
52 | struct input_dev *input_dev; |
53 | struct touchscreen_properties prop; |
54 | |
55 | const struct ilitek_protocol_map *ptl_cb_func; |
56 | struct ilitek_protocol_info ptl; |
57 | |
58 | char product_id[30]; |
59 | u16 mcu_ver; |
60 | u8 ic_mode; |
61 | u8 firmware_ver[8]; |
62 | |
63 | s32 reset_time; |
64 | s32 screen_max_x; |
65 | s32 screen_max_y; |
66 | s32 screen_min_x; |
67 | s32 screen_min_y; |
68 | s32 max_tp; |
69 | }; |
70 | |
71 | struct ilitek_protocol_map { |
72 | u16 cmd; |
73 | const char *name; |
74 | int (*func)(struct ilitek_ts_data *ts, u16 cmd, u8 *inbuf, u8 *outbuf); |
75 | }; |
76 | |
77 | enum ilitek_cmds { |
78 | /* common cmds */ |
79 | GET_PTL_VER = 0, |
80 | GET_FW_VER, |
81 | GET_SCRN_RES, |
82 | GET_TP_RES, |
83 | GET_IC_MODE, |
84 | GET_MCU_VER, |
85 | SET_IC_SLEEP, |
86 | SET_IC_WAKE, |
87 | |
88 | /* ALWAYS keep at the end */ |
89 | MAX_CMD_CNT |
90 | }; |
91 | |
92 | /* ILITEK I2C R/W APIs */ |
93 | static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts, |
94 | u8 *cmd, int write_len, int delay, |
95 | u8 *data, int read_len) |
96 | { |
97 | int error; |
98 | struct i2c_client *client = ts->client; |
99 | struct i2c_msg msgs[] = { |
100 | { |
101 | .addr = client->addr, |
102 | .flags = 0, |
103 | .len = write_len, |
104 | .buf = cmd, |
105 | }, |
106 | { |
107 | .addr = client->addr, |
108 | .flags = I2C_M_RD, |
109 | .len = read_len, |
110 | .buf = data, |
111 | }, |
112 | }; |
113 | |
114 | if (delay == 0 && write_len > 0 && read_len > 0) { |
115 | error = i2c_transfer(adap: client->adapter, msgs, ARRAY_SIZE(msgs)); |
116 | if (error < 0) |
117 | return error; |
118 | } else { |
119 | if (write_len > 0) { |
120 | error = i2c_transfer(adap: client->adapter, msgs, num: 1); |
121 | if (error < 0) |
122 | return error; |
123 | } |
124 | if (delay > 0) |
125 | mdelay(delay); |
126 | |
127 | if (read_len > 0) { |
128 | error = i2c_transfer(adap: client->adapter, msgs: msgs + 1, num: 1); |
129 | if (error < 0) |
130 | return error; |
131 | } |
132 | } |
133 | |
134 | return 0; |
135 | } |
136 | |
137 | /* ILITEK ISR APIs */ |
138 | static void ilitek_touch_down(struct ilitek_ts_data *ts, unsigned int id, |
139 | unsigned int x, unsigned int y) |
140 | { |
141 | struct input_dev *input = ts->input_dev; |
142 | |
143 | input_mt_slot(dev: input, slot: id); |
144 | input_mt_report_slot_state(dev: input, MT_TOOL_FINGER, active: true); |
145 | |
146 | touchscreen_report_pos(input, prop: &ts->prop, x, y, multitouch: true); |
147 | } |
148 | |
149 | static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts) |
150 | { |
151 | int error = 0; |
152 | u8 buf[512]; |
153 | int packet_len = 5; |
154 | int packet_max_point = 10; |
155 | int report_max_point; |
156 | int i, count; |
157 | struct input_dev *input = ts->input_dev; |
158 | struct device *dev = &ts->client->dev; |
159 | unsigned int x, y, status, id; |
160 | |
161 | error = ilitek_i2c_write_and_read(ts, NULL, write_len: 0, delay: 0, data: buf, read_len: 64); |
162 | if (error) { |
163 | dev_err(dev, "get touch info failed, err:%d\n", error); |
164 | return error; |
165 | } |
166 | |
167 | if (buf[0] != ILITEK_TP_I2C_REPORT_ID) { |
168 | dev_err(dev, "get touch info failed. Wrong id: 0x%02X\n", buf[0]); |
169 | return -EINVAL; |
170 | } |
171 | |
172 | report_max_point = buf[REPORT_COUNT_ADDRESS]; |
173 | if (report_max_point > ts->max_tp) { |
174 | dev_err(dev, "FW report max point:%d > panel info. max:%d\n", |
175 | report_max_point, ts->max_tp); |
176 | return -EINVAL; |
177 | } |
178 | |
179 | count = DIV_ROUND_UP(report_max_point, packet_max_point); |
180 | for (i = 1; i < count; i++) { |
181 | error = ilitek_i2c_write_and_read(ts, NULL, write_len: 0, delay: 0, |
182 | data: buf + i * 64, read_len: 64); |
183 | if (error) { |
184 | dev_err(dev, "get touch info. failed, cnt:%d, err:%d\n", |
185 | count, error); |
186 | return error; |
187 | } |
188 | } |
189 | |
190 | for (i = 0; i < report_max_point; i++) { |
191 | status = buf[i * packet_len + 1] & 0x40; |
192 | if (!status) |
193 | continue; |
194 | |
195 | id = buf[i * packet_len + 1] & 0x3F; |
196 | |
197 | x = get_unaligned_le16(p: buf + i * packet_len + 2); |
198 | y = get_unaligned_le16(p: buf + i * packet_len + 4); |
199 | |
200 | if (x > ts->screen_max_x || x < ts->screen_min_x || |
201 | y > ts->screen_max_y || y < ts->screen_min_y) { |
202 | dev_warn(dev, "invalid position, X[%d,%u,%d], Y[%d,%u,%d]\n", |
203 | ts->screen_min_x, x, ts->screen_max_x, |
204 | ts->screen_min_y, y, ts->screen_max_y); |
205 | continue; |
206 | } |
207 | |
208 | ilitek_touch_down(ts, id, x, y); |
209 | } |
210 | |
211 | input_mt_sync_frame(dev: input); |
212 | input_sync(dev: input); |
213 | |
214 | return 0; |
215 | } |
216 | |
217 | /* APIs of cmds for ILITEK Touch IC */ |
218 | static int api_protocol_set_cmd(struct ilitek_ts_data *ts, |
219 | u16 idx, u8 *inbuf, u8 *outbuf) |
220 | { |
221 | u16 cmd; |
222 | int error; |
223 | |
224 | if (idx >= MAX_CMD_CNT) |
225 | return -EINVAL; |
226 | |
227 | cmd = ts->ptl_cb_func[idx].cmd; |
228 | error = ts->ptl_cb_func[idx].func(ts, cmd, inbuf, outbuf); |
229 | if (error) |
230 | return error; |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | static int api_protocol_get_ptl_ver(struct ilitek_ts_data *ts, |
236 | u16 cmd, u8 *inbuf, u8 *outbuf) |
237 | { |
238 | int error; |
239 | u8 buf[64]; |
240 | |
241 | buf[0] = cmd; |
242 | error = ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 5, data: outbuf, read_len: 3); |
243 | if (error) |
244 | return error; |
245 | |
246 | ts->ptl.ver = get_unaligned_be16(p: outbuf); |
247 | ts->ptl.ver_major = outbuf[0]; |
248 | |
249 | return 0; |
250 | } |
251 | |
252 | static int api_protocol_get_mcu_ver(struct ilitek_ts_data *ts, |
253 | u16 cmd, u8 *inbuf, u8 *outbuf) |
254 | { |
255 | int error; |
256 | u8 buf[64]; |
257 | |
258 | buf[0] = cmd; |
259 | error = ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 5, data: outbuf, read_len: 32); |
260 | if (error) |
261 | return error; |
262 | |
263 | ts->mcu_ver = get_unaligned_le16(p: outbuf); |
264 | memset(ts->product_id, 0, sizeof(ts->product_id)); |
265 | memcpy(ts->product_id, outbuf + 6, 26); |
266 | |
267 | return 0; |
268 | } |
269 | |
270 | static int api_protocol_get_fw_ver(struct ilitek_ts_data *ts, |
271 | u16 cmd, u8 *inbuf, u8 *outbuf) |
272 | { |
273 | int error; |
274 | u8 buf[64]; |
275 | |
276 | buf[0] = cmd; |
277 | error = ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 5, data: outbuf, read_len: 8); |
278 | if (error) |
279 | return error; |
280 | |
281 | memcpy(ts->firmware_ver, outbuf, 8); |
282 | |
283 | return 0; |
284 | } |
285 | |
286 | static int api_protocol_get_scrn_res(struct ilitek_ts_data *ts, |
287 | u16 cmd, u8 *inbuf, u8 *outbuf) |
288 | { |
289 | int error; |
290 | u8 buf[64]; |
291 | |
292 | buf[0] = cmd; |
293 | error = ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 5, data: outbuf, read_len: 8); |
294 | if (error) |
295 | return error; |
296 | |
297 | ts->screen_min_x = get_unaligned_le16(p: outbuf); |
298 | ts->screen_min_y = get_unaligned_le16(p: outbuf + 2); |
299 | ts->screen_max_x = get_unaligned_le16(p: outbuf + 4); |
300 | ts->screen_max_y = get_unaligned_le16(p: outbuf + 6); |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | static int api_protocol_get_tp_res(struct ilitek_ts_data *ts, |
306 | u16 cmd, u8 *inbuf, u8 *outbuf) |
307 | { |
308 | int error; |
309 | u8 buf[64]; |
310 | |
311 | buf[0] = cmd; |
312 | error = ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 5, data: outbuf, read_len: 15); |
313 | if (error) |
314 | return error; |
315 | |
316 | ts->max_tp = outbuf[8]; |
317 | if (ts->max_tp > ILITEK_SUPPORT_MAX_POINT) { |
318 | dev_err(&ts->client->dev, "Invalid MAX_TP:%d from FW\n", |
319 | ts->max_tp); |
320 | return -EINVAL; |
321 | } |
322 | |
323 | return 0; |
324 | } |
325 | |
326 | static int api_protocol_get_ic_mode(struct ilitek_ts_data *ts, |
327 | u16 cmd, u8 *inbuf, u8 *outbuf) |
328 | { |
329 | int error; |
330 | u8 buf[64]; |
331 | |
332 | buf[0] = cmd; |
333 | error = ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 5, data: outbuf, read_len: 2); |
334 | if (error) |
335 | return error; |
336 | |
337 | ts->ic_mode = outbuf[0]; |
338 | return 0; |
339 | } |
340 | |
341 | static int api_protocol_set_ic_sleep(struct ilitek_ts_data *ts, |
342 | u16 cmd, u8 *inbuf, u8 *outbuf) |
343 | { |
344 | u8 buf[64]; |
345 | |
346 | buf[0] = cmd; |
347 | return ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 0, NULL, read_len: 0); |
348 | } |
349 | |
350 | static int api_protocol_set_ic_wake(struct ilitek_ts_data *ts, |
351 | u16 cmd, u8 *inbuf, u8 *outbuf) |
352 | { |
353 | u8 buf[64]; |
354 | |
355 | buf[0] = cmd; |
356 | return ilitek_i2c_write_and_read(ts, cmd: buf, write_len: 1, delay: 0, NULL, read_len: 0); |
357 | } |
358 | |
359 | static const struct ilitek_protocol_map ptl_func_map[] = { |
360 | /* common cmds */ |
361 | [GET_PTL_VER] = { |
362 | ILITEK_TP_CMD_GET_PRL_VER, "GET_PTL_VER", |
363 | api_protocol_get_ptl_ver |
364 | }, |
365 | [GET_FW_VER] = { |
366 | ILITEK_TP_CMD_GET_FW_VER, "GET_FW_VER", |
367 | api_protocol_get_fw_ver |
368 | }, |
369 | [GET_SCRN_RES] = { |
370 | ILITEK_TP_CMD_GET_SCRN_RES, "GET_SCRN_RES", |
371 | api_protocol_get_scrn_res |
372 | }, |
373 | [GET_TP_RES] = { |
374 | ILITEK_TP_CMD_GET_TP_RES, "GET_TP_RES", |
375 | api_protocol_get_tp_res |
376 | }, |
377 | [GET_IC_MODE] = { |
378 | ILITEK_TP_CMD_GET_IC_MODE, "GET_IC_MODE", |
379 | api_protocol_get_ic_mode |
380 | }, |
381 | [GET_MCU_VER] = { |
382 | ILITEK_TP_CMD_GET_MCU_VER, "GET_MOD_VER", |
383 | api_protocol_get_mcu_ver |
384 | }, |
385 | [SET_IC_SLEEP] = { |
386 | ILITEK_TP_CMD_SET_IC_SLEEP, "SET_IC_SLEEP", |
387 | api_protocol_set_ic_sleep |
388 | }, |
389 | [SET_IC_WAKE] = { |
390 | ILITEK_TP_CMD_SET_IC_WAKE, "SET_IC_WAKE", |
391 | api_protocol_set_ic_wake |
392 | }, |
393 | }; |
394 | |
395 | /* Probe APIs */ |
396 | static void ilitek_reset(struct ilitek_ts_data *ts, int delay) |
397 | { |
398 | if (ts->reset_gpio) { |
399 | gpiod_set_value(desc: ts->reset_gpio, value: 1); |
400 | mdelay(10); |
401 | gpiod_set_value(desc: ts->reset_gpio, value: 0); |
402 | mdelay(delay); |
403 | } |
404 | } |
405 | |
406 | static int ilitek_protocol_init(struct ilitek_ts_data *ts) |
407 | { |
408 | int error; |
409 | u8 outbuf[64]; |
410 | |
411 | ts->ptl_cb_func = ptl_func_map; |
412 | ts->reset_time = 600; |
413 | |
414 | error = api_protocol_set_cmd(ts, idx: GET_PTL_VER, NULL, outbuf); |
415 | if (error) |
416 | return error; |
417 | |
418 | /* Protocol v3 is not support currently */ |
419 | if (ts->ptl.ver_major == 0x3 || |
420 | ts->ptl.ver == BL_V1_6 || |
421 | ts->ptl.ver == BL_V1_7) |
422 | return -EINVAL; |
423 | |
424 | return 0; |
425 | } |
426 | |
427 | static int ilitek_read_tp_info(struct ilitek_ts_data *ts, bool boot) |
428 | { |
429 | u8 outbuf[256]; |
430 | int error; |
431 | |
432 | error = api_protocol_set_cmd(ts, idx: GET_PTL_VER, NULL, outbuf); |
433 | if (error) |
434 | return error; |
435 | |
436 | error = api_protocol_set_cmd(ts, idx: GET_MCU_VER, NULL, outbuf); |
437 | if (error) |
438 | return error; |
439 | |
440 | error = api_protocol_set_cmd(ts, idx: GET_FW_VER, NULL, outbuf); |
441 | if (error) |
442 | return error; |
443 | |
444 | if (boot) { |
445 | error = api_protocol_set_cmd(ts, idx: GET_SCRN_RES, NULL, |
446 | outbuf); |
447 | if (error) |
448 | return error; |
449 | } |
450 | |
451 | error = api_protocol_set_cmd(ts, idx: GET_TP_RES, NULL, outbuf); |
452 | if (error) |
453 | return error; |
454 | |
455 | error = api_protocol_set_cmd(ts, idx: GET_IC_MODE, NULL, outbuf); |
456 | if (error) |
457 | return error; |
458 | |
459 | return 0; |
460 | } |
461 | |
462 | static int ilitek_input_dev_init(struct device *dev, struct ilitek_ts_data *ts) |
463 | { |
464 | int error; |
465 | struct input_dev *input; |
466 | |
467 | input = devm_input_allocate_device(dev); |
468 | if (!input) |
469 | return -ENOMEM; |
470 | |
471 | ts->input_dev = input; |
472 | input->name = ILITEK_TS_NAME; |
473 | input->id.bustype = BUS_I2C; |
474 | |
475 | __set_bit(INPUT_PROP_DIRECT, input->propbit); |
476 | |
477 | input_set_abs_params(dev: input, ABS_MT_POSITION_X, |
478 | min: ts->screen_min_x, max: ts->screen_max_x, fuzz: 0, flat: 0); |
479 | input_set_abs_params(dev: input, ABS_MT_POSITION_Y, |
480 | min: ts->screen_min_y, max: ts->screen_max_y, fuzz: 0, flat: 0); |
481 | |
482 | touchscreen_parse_properties(input, multitouch: true, prop: &ts->prop); |
483 | |
484 | error = input_mt_init_slots(dev: input, num_slots: ts->max_tp, |
485 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); |
486 | if (error) { |
487 | dev_err(dev, "initialize MT slots failed, err:%d\n", error); |
488 | return error; |
489 | } |
490 | |
491 | error = input_register_device(input); |
492 | if (error) { |
493 | dev_err(dev, "register input device failed, err:%d\n", error); |
494 | return error; |
495 | } |
496 | |
497 | return 0; |
498 | } |
499 | |
500 | static irqreturn_t ilitek_i2c_isr(int irq, void *dev_id) |
501 | { |
502 | struct ilitek_ts_data *ts = dev_id; |
503 | int error; |
504 | |
505 | error = ilitek_process_and_report_v6(ts); |
506 | if (error < 0) { |
507 | dev_err(&ts->client->dev, "[%s] err:%d\n", __func__, error); |
508 | return IRQ_NONE; |
509 | } |
510 | |
511 | return IRQ_HANDLED; |
512 | } |
513 | |
514 | static ssize_t firmware_version_show(struct device *dev, |
515 | struct device_attribute *attr, char *buf) |
516 | { |
517 | struct i2c_client *client = to_i2c_client(dev); |
518 | struct ilitek_ts_data *ts = i2c_get_clientdata(client); |
519 | |
520 | return sysfs_emit(buf, |
521 | fmt: "fw version: [%02X%02X.%02X%02X.%02X%02X.%02X%02X]\n", |
522 | ts->firmware_ver[0], ts->firmware_ver[1], |
523 | ts->firmware_ver[2], ts->firmware_ver[3], |
524 | ts->firmware_ver[4], ts->firmware_ver[5], |
525 | ts->firmware_ver[6], ts->firmware_ver[7]); |
526 | } |
527 | static DEVICE_ATTR_RO(firmware_version); |
528 | |
529 | static ssize_t product_id_show(struct device *dev, |
530 | struct device_attribute *attr, char *buf) |
531 | { |
532 | struct i2c_client *client = to_i2c_client(dev); |
533 | struct ilitek_ts_data *ts = i2c_get_clientdata(client); |
534 | |
535 | return sysfs_emit(buf, fmt: "product id: [%04X], module: [%s]\n", |
536 | ts->mcu_ver, ts->product_id); |
537 | } |
538 | static DEVICE_ATTR_RO(product_id); |
539 | |
540 | static struct attribute *ilitek_sysfs_attrs[] = { |
541 | &dev_attr_firmware_version.attr, |
542 | &dev_attr_product_id.attr, |
543 | NULL |
544 | }; |
545 | ATTRIBUTE_GROUPS(ilitek_sysfs); |
546 | |
547 | static int ilitek_ts_i2c_probe(struct i2c_client *client) |
548 | { |
549 | struct ilitek_ts_data *ts; |
550 | struct device *dev = &client->dev; |
551 | int error; |
552 | |
553 | if (!i2c_check_functionality(adap: client->adapter, I2C_FUNC_I2C)) { |
554 | dev_err(dev, "i2c check functionality failed\n"); |
555 | return -ENXIO; |
556 | } |
557 | |
558 | ts = devm_kzalloc(dev, size: sizeof(*ts), GFP_KERNEL); |
559 | if (!ts) |
560 | return -ENOMEM; |
561 | |
562 | ts->client = client; |
563 | i2c_set_clientdata(client, data: ts); |
564 | |
565 | ts->reset_gpio = devm_gpiod_get_optional(dev, con_id: "reset", flags: GPIOD_OUT_LOW); |
566 | if (IS_ERR(ptr: ts->reset_gpio)) { |
567 | error = PTR_ERR(ptr: ts->reset_gpio); |
568 | dev_err(dev, "request gpiod failed: %d", error); |
569 | return error; |
570 | } |
571 | |
572 | ilitek_reset(ts, delay: 1000); |
573 | |
574 | error = ilitek_protocol_init(ts); |
575 | if (error) { |
576 | dev_err(dev, "protocol init failed: %d", error); |
577 | return error; |
578 | } |
579 | |
580 | error = ilitek_read_tp_info(ts, boot: true); |
581 | if (error) { |
582 | dev_err(dev, "read tp info failed: %d", error); |
583 | return error; |
584 | } |
585 | |
586 | error = ilitek_input_dev_init(dev, ts); |
587 | if (error) { |
588 | dev_err(dev, "input dev init failed: %d", error); |
589 | return error; |
590 | } |
591 | |
592 | error = devm_request_threaded_irq(dev, irq: ts->client->irq, |
593 | NULL, thread_fn: ilitek_i2c_isr, IRQF_ONESHOT, |
594 | devname: "ilitek_touch_irq", dev_id: ts); |
595 | if (error) { |
596 | dev_err(dev, "request threaded irq failed: %d\n", error); |
597 | return error; |
598 | } |
599 | |
600 | return 0; |
601 | } |
602 | |
603 | static int ilitek_suspend(struct device *dev) |
604 | { |
605 | struct i2c_client *client = to_i2c_client(dev); |
606 | struct ilitek_ts_data *ts = i2c_get_clientdata(client); |
607 | int error; |
608 | |
609 | disable_irq(irq: client->irq); |
610 | |
611 | if (!device_may_wakeup(dev)) { |
612 | error = api_protocol_set_cmd(ts, idx: SET_IC_SLEEP, NULL, NULL); |
613 | if (error) |
614 | return error; |
615 | } |
616 | |
617 | return 0; |
618 | } |
619 | |
620 | static int ilitek_resume(struct device *dev) |
621 | { |
622 | struct i2c_client *client = to_i2c_client(dev); |
623 | struct ilitek_ts_data *ts = i2c_get_clientdata(client); |
624 | int error; |
625 | |
626 | if (!device_may_wakeup(dev)) { |
627 | error = api_protocol_set_cmd(ts, idx: SET_IC_WAKE, NULL, NULL); |
628 | if (error) |
629 | return error; |
630 | |
631 | ilitek_reset(ts, delay: ts->reset_time); |
632 | } |
633 | |
634 | enable_irq(irq: client->irq); |
635 | |
636 | return 0; |
637 | } |
638 | |
639 | static DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume); |
640 | |
641 | static const struct i2c_device_id ilitek_ts_i2c_id[] = { |
642 | { ILITEK_TS_NAME }, |
643 | { } |
644 | }; |
645 | MODULE_DEVICE_TABLE(i2c, ilitek_ts_i2c_id); |
646 | |
647 | #ifdef CONFIG_ACPI |
648 | static const struct acpi_device_id ilitekts_acpi_id[] = { |
649 | { "ILTK0001", 0 }, |
650 | { }, |
651 | }; |
652 | MODULE_DEVICE_TABLE(acpi, ilitekts_acpi_id); |
653 | #endif |
654 | |
655 | #ifdef CONFIG_OF |
656 | static const struct of_device_id ilitek_ts_i2c_match[] = { |
657 | {.compatible = "ilitek,ili2130",}, |
658 | {.compatible = "ilitek,ili2131",}, |
659 | {.compatible = "ilitek,ili2132",}, |
660 | {.compatible = "ilitek,ili2316",}, |
661 | {.compatible = "ilitek,ili2322",}, |
662 | {.compatible = "ilitek,ili2323",}, |
663 | {.compatible = "ilitek,ili2326",}, |
664 | {.compatible = "ilitek,ili2520",}, |
665 | {.compatible = "ilitek,ili2521",}, |
666 | { }, |
667 | }; |
668 | MODULE_DEVICE_TABLE(of, ilitek_ts_i2c_match); |
669 | #endif |
670 | |
671 | static struct i2c_driver ilitek_ts_i2c_driver = { |
672 | .driver = { |
673 | .name = ILITEK_TS_NAME, |
674 | .dev_groups = ilitek_sysfs_groups, |
675 | .pm = pm_sleep_ptr(&ilitek_pm_ops), |
676 | .of_match_table = of_match_ptr(ilitek_ts_i2c_match), |
677 | .acpi_match_table = ACPI_PTR(ilitekts_acpi_id), |
678 | }, |
679 | .probe = ilitek_ts_i2c_probe, |
680 | .id_table = ilitek_ts_i2c_id, |
681 | }; |
682 | module_i2c_driver(ilitek_ts_i2c_driver); |
683 | |
684 | MODULE_AUTHOR("ILITEK"); |
685 | MODULE_DESCRIPTION("ILITEK I2C Touchscreen Driver"); |
686 | MODULE_LICENSE("GPL"); |
687 |
Definitions
- ilitek_protocol_info
- ilitek_ts_data
- ilitek_protocol_map
- ilitek_cmds
- ilitek_i2c_write_and_read
- ilitek_touch_down
- ilitek_process_and_report_v6
- api_protocol_set_cmd
- api_protocol_get_ptl_ver
- api_protocol_get_mcu_ver
- api_protocol_get_fw_ver
- api_protocol_get_scrn_res
- api_protocol_get_tp_res
- api_protocol_get_ic_mode
- api_protocol_set_ic_sleep
- api_protocol_set_ic_wake
- ptl_func_map
- ilitek_reset
- ilitek_protocol_init
- ilitek_read_tp_info
- ilitek_input_dev_init
- ilitek_i2c_isr
- firmware_version_show
- product_id_show
- ilitek_sysfs_attrs
- ilitek_ts_i2c_probe
- ilitek_suspend
- ilitek_resume
- ilitek_pm_ops
- ilitek_ts_i2c_id
- ilitekts_acpi_id
- ilitek_ts_i2c_match
Improve your Profiling and Debugging skills
Find out more