.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Elan Microelectronics touch panels with I2C interface |
---|
3 | 4 | * |
---|
.. | .. |
---|
10 | 11 | * Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> |
---|
11 | 12 | * Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France |
---|
12 | 13 | * |
---|
13 | | - * |
---|
14 | 14 | * This code is partly based on i2c-hid.c: |
---|
15 | 15 | * |
---|
16 | 16 | * Copyright (c) 2012 Benjamin Tissoires <benjamin.tissoires@gmail.com> |
---|
.. | .. |
---|
18 | 18 | * Copyright (c) 2012 Red Hat, Inc |
---|
19 | 19 | */ |
---|
20 | 20 | |
---|
21 | | -/* |
---|
22 | | - * This software is licensed under the terms of the GNU General Public |
---|
23 | | - * License version 2, as published by the Free Software Foundation, and |
---|
24 | | - * may be copied, distributed, and modified under those terms. |
---|
25 | | - */ |
---|
26 | 21 | |
---|
| 22 | +#include <linux/bits.h> |
---|
27 | 23 | #include <linux/module.h> |
---|
28 | 24 | #include <linux/input.h> |
---|
29 | 25 | #include <linux/interrupt.h> |
---|
.. | .. |
---|
37 | 33 | #include <linux/slab.h> |
---|
38 | 34 | #include <linux/firmware.h> |
---|
39 | 35 | #include <linux/input/mt.h> |
---|
| 36 | +#include <linux/input/touchscreen.h> |
---|
40 | 37 | #include <linux/acpi.h> |
---|
41 | 38 | #include <linux/of.h> |
---|
42 | 39 | #include <linux/gpio/consumer.h> |
---|
.. | .. |
---|
65 | 62 | #define CMD_HEADER_WRITE 0x54 |
---|
66 | 63 | #define CMD_HEADER_READ 0x53 |
---|
67 | 64 | #define CMD_HEADER_6B_READ 0x5B |
---|
| 65 | +#define CMD_HEADER_ROM_READ 0x96 |
---|
68 | 66 | #define CMD_HEADER_RESP 0x52 |
---|
69 | 67 | #define CMD_HEADER_6B_RESP 0x9B |
---|
| 68 | +#define CMD_HEADER_ROM_RESP 0x95 |
---|
70 | 69 | #define CMD_HEADER_HELLO 0x55 |
---|
71 | 70 | #define CMD_HEADER_REK 0x66 |
---|
72 | 71 | |
---|
.. | .. |
---|
77 | 76 | #define FW_POS_STATE 1 |
---|
78 | 77 | #define FW_POS_TOTAL 2 |
---|
79 | 78 | #define FW_POS_XY 3 |
---|
| 79 | +#define FW_POS_TOOL_TYPE 33 |
---|
80 | 80 | #define FW_POS_CHECKSUM 34 |
---|
81 | 81 | #define FW_POS_WIDTH 35 |
---|
82 | 82 | #define FW_POS_PRESSURE 45 |
---|
.. | .. |
---|
91 | 91 | /* FW read command, 0x53 0x?? 0x0, 0x01 */ |
---|
92 | 92 | #define E_ELAN_INFO_FW_VER 0x00 |
---|
93 | 93 | #define E_ELAN_INFO_BC_VER 0x10 |
---|
| 94 | +#define E_ELAN_INFO_REK 0xD0 |
---|
94 | 95 | #define E_ELAN_INFO_TEST_VER 0xE0 |
---|
95 | 96 | #define E_ELAN_INFO_FW_ID 0xF0 |
---|
96 | 97 | #define E_INFO_OSR 0xD6 |
---|
.. | .. |
---|
107 | 108 | |
---|
108 | 109 | #define ELAN_POWERON_DELAY_USEC 500 |
---|
109 | 110 | #define ELAN_RESET_DELAY_MSEC 20 |
---|
| 111 | + |
---|
| 112 | +/* FW boot code version */ |
---|
| 113 | +#define BC_VER_H_BYTE_FOR_EKTH3900x1_I2C 0x72 |
---|
| 114 | +#define BC_VER_H_BYTE_FOR_EKTH3900x2_I2C 0x82 |
---|
| 115 | +#define BC_VER_H_BYTE_FOR_EKTH3900x3_I2C 0x92 |
---|
| 116 | +#define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C 0x6D |
---|
| 117 | +#define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C 0x6E |
---|
| 118 | +#define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C 0x77 |
---|
| 119 | +#define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C 0x78 |
---|
| 120 | +#define BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB 0x67 |
---|
| 121 | +#define BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB 0x68 |
---|
| 122 | +#define BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB 0x74 |
---|
| 123 | +#define BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB 0x75 |
---|
110 | 124 | |
---|
111 | 125 | enum elants_state { |
---|
112 | 126 | ELAN_STATE_NORMAL, |
---|
.. | .. |
---|
134 | 148 | u8 bc_version; |
---|
135 | 149 | u8 iap_version; |
---|
136 | 150 | u16 hw_version; |
---|
| 151 | + u8 major_res; |
---|
137 | 152 | unsigned int x_res; /* resolution in units/mm */ |
---|
138 | 153 | unsigned int y_res; |
---|
139 | 154 | unsigned int x_max; |
---|
140 | 155 | unsigned int y_max; |
---|
| 156 | + struct touchscreen_properties prop; |
---|
141 | 157 | |
---|
142 | 158 | enum elants_state state; |
---|
143 | 159 | enum elants_iap_mode iap_mode; |
---|
.. | .. |
---|
148 | 164 | u8 cmd_resp[HEADER_SIZE]; |
---|
149 | 165 | struct completion cmd_done; |
---|
150 | 166 | |
---|
151 | | - u8 buf[MAX_PACKET_SIZE]; |
---|
152 | | - |
---|
153 | 167 | bool wake_irq_enabled; |
---|
154 | 168 | bool keep_power_in_suspend; |
---|
| 169 | + |
---|
| 170 | + /* Must be last to be used for DMA operations */ |
---|
| 171 | + u8 buf[MAX_PACKET_SIZE] ____cacheline_aligned; |
---|
155 | 172 | }; |
---|
156 | 173 | |
---|
157 | 174 | static int elants_i2c_send(struct i2c_client *client, |
---|
.. | .. |
---|
190 | 207 | |
---|
191 | 208 | static int elants_i2c_execute_command(struct i2c_client *client, |
---|
192 | 209 | const u8 *cmd, size_t cmd_size, |
---|
193 | | - u8 *resp, size_t resp_size) |
---|
| 210 | + u8 *resp, size_t resp_size, |
---|
| 211 | + int retries, const char *cmd_name) |
---|
194 | 212 | { |
---|
195 | 213 | struct i2c_msg msgs[2]; |
---|
196 | 214 | int ret; |
---|
.. | .. |
---|
205 | 223 | expected_response = CMD_HEADER_6B_RESP; |
---|
206 | 224 | break; |
---|
207 | 225 | |
---|
| 226 | + case CMD_HEADER_ROM_READ: |
---|
| 227 | + expected_response = CMD_HEADER_ROM_RESP; |
---|
| 228 | + break; |
---|
| 229 | + |
---|
208 | 230 | default: |
---|
209 | | - dev_err(&client->dev, "%s: invalid command %*ph\n", |
---|
210 | | - __func__, (int)cmd_size, cmd); |
---|
| 231 | + dev_err(&client->dev, "(%s): invalid command: %*ph\n", |
---|
| 232 | + cmd_name, (int)cmd_size, cmd); |
---|
211 | 233 | return -EINVAL; |
---|
212 | 234 | } |
---|
213 | 235 | |
---|
214 | | - msgs[0].addr = client->addr; |
---|
215 | | - msgs[0].flags = client->flags & I2C_M_TEN; |
---|
216 | | - msgs[0].len = cmd_size; |
---|
217 | | - msgs[0].buf = (u8 *)cmd; |
---|
| 236 | + for (;;) { |
---|
| 237 | + msgs[0].addr = client->addr; |
---|
| 238 | + msgs[0].flags = client->flags & I2C_M_TEN; |
---|
| 239 | + msgs[0].len = cmd_size; |
---|
| 240 | + msgs[0].buf = (u8 *)cmd; |
---|
218 | 241 | |
---|
219 | | - msgs[1].addr = client->addr; |
---|
220 | | - msgs[1].flags = client->flags & I2C_M_TEN; |
---|
221 | | - msgs[1].flags |= I2C_M_RD; |
---|
222 | | - msgs[1].len = resp_size; |
---|
223 | | - msgs[1].buf = resp; |
---|
| 242 | + msgs[1].addr = client->addr; |
---|
| 243 | + msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_RD; |
---|
| 244 | + msgs[1].flags |= I2C_M_RD; |
---|
| 245 | + msgs[1].len = resp_size; |
---|
| 246 | + msgs[1].buf = resp; |
---|
224 | 247 | |
---|
225 | | - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); |
---|
226 | | - if (ret < 0) |
---|
227 | | - return ret; |
---|
| 248 | + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); |
---|
| 249 | + if (ret < 0) { |
---|
| 250 | + if (--retries > 0) { |
---|
| 251 | + dev_dbg(&client->dev, |
---|
| 252 | + "(%s) I2C transfer failed: %pe (retrying)\n", |
---|
| 253 | + cmd_name, ERR_PTR(ret)); |
---|
| 254 | + continue; |
---|
| 255 | + } |
---|
228 | 256 | |
---|
229 | | - if (ret != ARRAY_SIZE(msgs) || resp[FW_HDR_TYPE] != expected_response) |
---|
230 | | - return -EIO; |
---|
| 257 | + dev_err(&client->dev, |
---|
| 258 | + "(%s) I2C transfer failed: %pe\n", |
---|
| 259 | + cmd_name, ERR_PTR(ret)); |
---|
| 260 | + return ret; |
---|
| 261 | + } |
---|
231 | 262 | |
---|
232 | | - return 0; |
---|
| 263 | + if (ret != ARRAY_SIZE(msgs) || |
---|
| 264 | + resp[FW_HDR_TYPE] != expected_response) { |
---|
| 265 | + if (--retries > 0) { |
---|
| 266 | + dev_dbg(&client->dev, |
---|
| 267 | + "(%s) unexpected response: %*ph (retrying)\n", |
---|
| 268 | + cmd_name, ret, resp); |
---|
| 269 | + continue; |
---|
| 270 | + } |
---|
| 271 | + |
---|
| 272 | + dev_err(&client->dev, |
---|
| 273 | + "(%s) unexpected response: %*ph\n", |
---|
| 274 | + cmd_name, ret, resp); |
---|
| 275 | + return -EIO; |
---|
| 276 | + } |
---|
| 277 | + |
---|
| 278 | + return 0; |
---|
| 279 | + } |
---|
233 | 280 | } |
---|
234 | 281 | |
---|
235 | 282 | static int elants_i2c_calibrate(struct elants_data *ts) |
---|
.. | .. |
---|
302 | 349 | static int elants_i2c_query_hw_version(struct elants_data *ts) |
---|
303 | 350 | { |
---|
304 | 351 | struct i2c_client *client = ts->client; |
---|
305 | | - int error, retry_cnt; |
---|
| 352 | + int retry_cnt = MAX_RETRIES; |
---|
306 | 353 | const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 }; |
---|
307 | 354 | u8 resp[HEADER_SIZE]; |
---|
| 355 | + int error; |
---|
308 | 356 | |
---|
309 | | - for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { |
---|
| 357 | + while (retry_cnt--) { |
---|
310 | 358 | error = elants_i2c_execute_command(client, cmd, sizeof(cmd), |
---|
311 | | - resp, sizeof(resp)); |
---|
312 | | - if (!error) { |
---|
313 | | - ts->hw_version = elants_i2c_parse_version(resp); |
---|
314 | | - if (ts->hw_version != 0xffff) |
---|
315 | | - return 0; |
---|
316 | | - } |
---|
| 359 | + resp, sizeof(resp), 1, |
---|
| 360 | + "read fw id"); |
---|
| 361 | + if (error) |
---|
| 362 | + return error; |
---|
317 | 363 | |
---|
318 | | - dev_dbg(&client->dev, "read fw id error=%d, buf=%*phC\n", |
---|
319 | | - error, (int)sizeof(resp), resp); |
---|
320 | | - } |
---|
321 | | - |
---|
322 | | - if (error) { |
---|
323 | | - dev_err(&client->dev, |
---|
324 | | - "Failed to read fw id: %d\n", error); |
---|
325 | | - return error; |
---|
| 364 | + ts->hw_version = elants_i2c_parse_version(resp); |
---|
| 365 | + if (ts->hw_version != 0xffff) |
---|
| 366 | + return 0; |
---|
326 | 367 | } |
---|
327 | 368 | |
---|
328 | 369 | dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version); |
---|
.. | .. |
---|
333 | 374 | static int elants_i2c_query_fw_version(struct elants_data *ts) |
---|
334 | 375 | { |
---|
335 | 376 | struct i2c_client *client = ts->client; |
---|
336 | | - int error, retry_cnt; |
---|
| 377 | + int retry_cnt = MAX_RETRIES; |
---|
337 | 378 | const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 }; |
---|
338 | 379 | u8 resp[HEADER_SIZE]; |
---|
| 380 | + int error; |
---|
339 | 381 | |
---|
340 | | - for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { |
---|
| 382 | + while (retry_cnt--) { |
---|
341 | 383 | error = elants_i2c_execute_command(client, cmd, sizeof(cmd), |
---|
342 | | - resp, sizeof(resp)); |
---|
343 | | - if (!error) { |
---|
344 | | - ts->fw_version = elants_i2c_parse_version(resp); |
---|
345 | | - if (ts->fw_version != 0x0000 && |
---|
346 | | - ts->fw_version != 0xffff) |
---|
347 | | - return 0; |
---|
348 | | - } |
---|
| 384 | + resp, sizeof(resp), 1, |
---|
| 385 | + "read fw version"); |
---|
| 386 | + if (error) |
---|
| 387 | + return error; |
---|
349 | 388 | |
---|
350 | | - dev_dbg(&client->dev, "read fw version error=%d, buf=%*phC\n", |
---|
351 | | - error, (int)sizeof(resp), resp); |
---|
| 389 | + ts->fw_version = elants_i2c_parse_version(resp); |
---|
| 390 | + if (ts->fw_version != 0x0000 && ts->fw_version != 0xffff) |
---|
| 391 | + return 0; |
---|
| 392 | + |
---|
| 393 | + dev_dbg(&client->dev, "(read fw version) resp %*phC\n", |
---|
| 394 | + (int)sizeof(resp), resp); |
---|
352 | 395 | } |
---|
353 | 396 | |
---|
354 | | - dev_err(&client->dev, |
---|
355 | | - "Failed to read fw version or fw version is invalid\n"); |
---|
| 397 | + dev_err(&client->dev, "Invalid fw ver: %#04x\n", ts->fw_version); |
---|
356 | 398 | |
---|
357 | 399 | return -EINVAL; |
---|
358 | 400 | } |
---|
.. | .. |
---|
360 | 402 | static int elants_i2c_query_test_version(struct elants_data *ts) |
---|
361 | 403 | { |
---|
362 | 404 | struct i2c_client *client = ts->client; |
---|
363 | | - int error, retry_cnt; |
---|
| 405 | + int error; |
---|
364 | 406 | u16 version; |
---|
365 | 407 | const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 }; |
---|
366 | 408 | u8 resp[HEADER_SIZE]; |
---|
367 | 409 | |
---|
368 | | - for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { |
---|
369 | | - error = elants_i2c_execute_command(client, cmd, sizeof(cmd), |
---|
370 | | - resp, sizeof(resp)); |
---|
371 | | - if (!error) { |
---|
372 | | - version = elants_i2c_parse_version(resp); |
---|
373 | | - ts->test_version = version >> 8; |
---|
374 | | - ts->solution_version = version & 0xff; |
---|
375 | | - |
---|
376 | | - return 0; |
---|
377 | | - } |
---|
378 | | - |
---|
379 | | - dev_dbg(&client->dev, |
---|
380 | | - "read test version error rc=%d, buf=%*phC\n", |
---|
381 | | - error, (int)sizeof(resp), resp); |
---|
| 410 | + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), |
---|
| 411 | + resp, sizeof(resp), MAX_RETRIES, |
---|
| 412 | + "read test version"); |
---|
| 413 | + if (error) { |
---|
| 414 | + dev_err(&client->dev, "Failed to read test version\n"); |
---|
| 415 | + return error; |
---|
382 | 416 | } |
---|
383 | 417 | |
---|
384 | | - dev_err(&client->dev, "Failed to read test version\n"); |
---|
| 418 | + version = elants_i2c_parse_version(resp); |
---|
| 419 | + ts->test_version = version >> 8; |
---|
| 420 | + ts->solution_version = version & 0xff; |
---|
385 | 421 | |
---|
386 | | - return -EINVAL; |
---|
| 422 | + return 0; |
---|
387 | 423 | } |
---|
388 | 424 | |
---|
389 | 425 | static int elants_i2c_query_bc_version(struct elants_data *ts) |
---|
.. | .. |
---|
395 | 431 | int error; |
---|
396 | 432 | |
---|
397 | 433 | error = elants_i2c_execute_command(client, cmd, sizeof(cmd), |
---|
398 | | - resp, sizeof(resp)); |
---|
399 | | - if (error) { |
---|
400 | | - dev_err(&client->dev, |
---|
401 | | - "read BC version error=%d, buf=%*phC\n", |
---|
402 | | - error, (int)sizeof(resp), resp); |
---|
| 434 | + resp, sizeof(resp), 1, |
---|
| 435 | + "read BC version"); |
---|
| 436 | + if (error) |
---|
403 | 437 | return error; |
---|
404 | | - } |
---|
405 | 438 | |
---|
406 | 439 | version = elants_i2c_parse_version(resp); |
---|
407 | 440 | ts->bc_version = version >> 8; |
---|
.. | .. |
---|
433 | 466 | error = elants_i2c_execute_command(client, |
---|
434 | 467 | get_resolution_cmd, |
---|
435 | 468 | sizeof(get_resolution_cmd), |
---|
436 | | - resp, sizeof(resp)); |
---|
437 | | - if (error) { |
---|
438 | | - dev_err(&client->dev, "get resolution command failed: %d\n", |
---|
439 | | - error); |
---|
| 469 | + resp, sizeof(resp), 1, |
---|
| 470 | + "get resolution"); |
---|
| 471 | + if (error) |
---|
440 | 472 | return error; |
---|
441 | | - } |
---|
442 | 473 | |
---|
443 | 474 | rows = resp[2] + resp[6] + resp[10]; |
---|
444 | 475 | cols = resp[3] + resp[7] + resp[11]; |
---|
445 | 476 | |
---|
| 477 | + /* Get report resolution value of ABS_MT_TOUCH_MAJOR */ |
---|
| 478 | + ts->major_res = resp[16]; |
---|
| 479 | + |
---|
446 | 480 | /* Process mm_to_pixel information */ |
---|
447 | 481 | error = elants_i2c_execute_command(client, |
---|
448 | 482 | get_osr_cmd, sizeof(get_osr_cmd), |
---|
449 | | - resp, sizeof(resp)); |
---|
450 | | - if (error) { |
---|
451 | | - dev_err(&client->dev, "get osr command failed: %d\n", |
---|
452 | | - error); |
---|
| 483 | + resp, sizeof(resp), 1, "get osr"); |
---|
| 484 | + if (error) |
---|
453 | 485 | return error; |
---|
454 | | - } |
---|
455 | 486 | |
---|
456 | 487 | osr = resp[3]; |
---|
457 | 488 | |
---|
458 | 489 | error = elants_i2c_execute_command(client, |
---|
459 | 490 | get_physical_scan_cmd, |
---|
460 | 491 | sizeof(get_physical_scan_cmd), |
---|
461 | | - resp, sizeof(resp)); |
---|
462 | | - if (error) { |
---|
463 | | - dev_err(&client->dev, "get physical scan command failed: %d\n", |
---|
464 | | - error); |
---|
| 492 | + resp, sizeof(resp), 1, |
---|
| 493 | + "get physical scan"); |
---|
| 494 | + if (error) |
---|
465 | 495 | return error; |
---|
466 | | - } |
---|
467 | 496 | |
---|
468 | 497 | phy_x = get_unaligned_be16(&resp[2]); |
---|
469 | 498 | |
---|
470 | 499 | error = elants_i2c_execute_command(client, |
---|
471 | 500 | get_physical_drive_cmd, |
---|
472 | 501 | sizeof(get_physical_drive_cmd), |
---|
473 | | - resp, sizeof(resp)); |
---|
474 | | - if (error) { |
---|
475 | | - dev_err(&client->dev, "get physical drive command failed: %d\n", |
---|
476 | | - error); |
---|
| 502 | + resp, sizeof(resp), 1, |
---|
| 503 | + "get physical drive"); |
---|
| 504 | + if (error) |
---|
477 | 505 | return error; |
---|
478 | | - } |
---|
479 | 506 | |
---|
480 | 507 | phy_y = get_unaligned_be16(&resp[2]); |
---|
481 | 508 | |
---|
.. | .. |
---|
561 | 588 | |
---|
562 | 589 | /* hw version is available even if device in recovery state */ |
---|
563 | 590 | error2 = elants_i2c_query_hw_version(ts); |
---|
| 591 | + if (!error2) |
---|
| 592 | + error2 = elants_i2c_query_bc_version(ts); |
---|
564 | 593 | if (!error) |
---|
565 | 594 | error = error2; |
---|
566 | 595 | |
---|
.. | .. |
---|
568 | 597 | error = elants_i2c_query_fw_version(ts); |
---|
569 | 598 | if (!error) |
---|
570 | 599 | error = elants_i2c_query_test_version(ts); |
---|
571 | | - if (!error) |
---|
572 | | - error = elants_i2c_query_bc_version(ts); |
---|
573 | 600 | if (!error) |
---|
574 | 601 | error = elants_i2c_query_ts_info(ts); |
---|
575 | 602 | |
---|
.. | .. |
---|
618 | 645 | return error; |
---|
619 | 646 | } |
---|
620 | 647 | |
---|
| 648 | +static int elants_i2c_validate_remark_id(struct elants_data *ts, |
---|
| 649 | + const struct firmware *fw) |
---|
| 650 | +{ |
---|
| 651 | + struct i2c_client *client = ts->client; |
---|
| 652 | + int error; |
---|
| 653 | + const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21 }; |
---|
| 654 | + u8 resp[6] = { 0 }; |
---|
| 655 | + u16 ts_remark_id = 0; |
---|
| 656 | + u16 fw_remark_id = 0; |
---|
| 657 | + |
---|
| 658 | + /* Compare TS Remark ID and FW Remark ID */ |
---|
| 659 | + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), |
---|
| 660 | + resp, sizeof(resp), |
---|
| 661 | + 1, "read Remark ID"); |
---|
| 662 | + if (error) |
---|
| 663 | + return error; |
---|
| 664 | + |
---|
| 665 | + ts_remark_id = get_unaligned_be16(&resp[3]); |
---|
| 666 | + |
---|
| 667 | + fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]); |
---|
| 668 | + |
---|
| 669 | + if (fw_remark_id != ts_remark_id) { |
---|
| 670 | + dev_err(&client->dev, |
---|
| 671 | + "Remark ID Mismatched: ts_remark_id=0x%04x, fw_remark_id=0x%04x.\n", |
---|
| 672 | + ts_remark_id, fw_remark_id); |
---|
| 673 | + return -EINVAL; |
---|
| 674 | + } |
---|
| 675 | + |
---|
| 676 | + return 0; |
---|
| 677 | +} |
---|
| 678 | + |
---|
| 679 | +static bool elants_i2c_should_check_remark_id(struct elants_data *ts) |
---|
| 680 | +{ |
---|
| 681 | + struct i2c_client *client = ts->client; |
---|
| 682 | + const u8 bootcode_version = ts->iap_version; |
---|
| 683 | + bool check; |
---|
| 684 | + |
---|
| 685 | + /* I2C eKTH3900 and eKTH5312 are NOT support Remark ID */ |
---|
| 686 | + if ((bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x1_I2C) || |
---|
| 687 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x2_I2C) || |
---|
| 688 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH3900x3_I2C) || |
---|
| 689 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C) || |
---|
| 690 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C) || |
---|
| 691 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C) || |
---|
| 692 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C) || |
---|
| 693 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x1_I2C_USB) || |
---|
| 694 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312x2_I2C_USB) || |
---|
| 695 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx1_I2C_USB) || |
---|
| 696 | + (bootcode_version == BC_VER_H_BYTE_FOR_EKTH5312cx2_I2C_USB)) { |
---|
| 697 | + dev_dbg(&client->dev, |
---|
| 698 | + "eKTH3900/eKTH5312(0x%02x) are not support remark id\n", |
---|
| 699 | + bootcode_version); |
---|
| 700 | + check = false; |
---|
| 701 | + } else if (bootcode_version >= 0x60) { |
---|
| 702 | + check = true; |
---|
| 703 | + } else { |
---|
| 704 | + check = false; |
---|
| 705 | + } |
---|
| 706 | + |
---|
| 707 | + return check; |
---|
| 708 | +} |
---|
| 709 | + |
---|
621 | 710 | static int elants_i2c_do_update_firmware(struct i2c_client *client, |
---|
622 | 711 | const struct firmware *fw, |
---|
623 | 712 | bool force) |
---|
624 | 713 | { |
---|
| 714 | + struct elants_data *ts = i2c_get_clientdata(client); |
---|
625 | 715 | const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; |
---|
626 | 716 | const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; |
---|
627 | 717 | const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; |
---|
628 | | - const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01}; |
---|
| 718 | + const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 }; |
---|
629 | 719 | u8 buf[HEADER_SIZE]; |
---|
630 | 720 | u16 send_id; |
---|
631 | 721 | int page, n_fw_pages; |
---|
632 | 722 | int error; |
---|
| 723 | + bool check_remark_id = elants_i2c_should_check_remark_id(ts); |
---|
633 | 724 | |
---|
634 | 725 | /* Recovery mode detection! */ |
---|
635 | 726 | if (force) { |
---|
636 | 727 | dev_dbg(&client->dev, "Recovery mode procedure\n"); |
---|
| 728 | + |
---|
| 729 | + if (check_remark_id) { |
---|
| 730 | + error = elants_i2c_validate_remark_id(ts, fw); |
---|
| 731 | + if (error) |
---|
| 732 | + return error; |
---|
| 733 | + } |
---|
| 734 | + |
---|
637 | 735 | error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); |
---|
| 736 | + if (error) { |
---|
| 737 | + dev_err(&client->dev, "failed to enter IAP mode: %d\n", |
---|
| 738 | + error); |
---|
| 739 | + return error; |
---|
| 740 | + } |
---|
638 | 741 | } else { |
---|
639 | 742 | /* Start IAP Procedure */ |
---|
640 | 743 | dev_dbg(&client->dev, "Normal IAP procedure\n"); |
---|
| 744 | + |
---|
641 | 745 | /* Close idle mode */ |
---|
642 | 746 | error = elants_i2c_send(client, close_idle, sizeof(close_idle)); |
---|
643 | 747 | if (error) |
---|
644 | 748 | dev_err(&client->dev, "Failed close idle: %d\n", error); |
---|
645 | 749 | msleep(60); |
---|
| 750 | + |
---|
646 | 751 | elants_i2c_sw_reset(client); |
---|
647 | 752 | msleep(20); |
---|
648 | | - error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); |
---|
649 | | - } |
---|
650 | 753 | |
---|
651 | | - if (error) { |
---|
652 | | - dev_err(&client->dev, "failed to enter IAP mode: %d\n", error); |
---|
653 | | - return error; |
---|
| 754 | + if (check_remark_id) { |
---|
| 755 | + error = elants_i2c_validate_remark_id(ts, fw); |
---|
| 756 | + if (error) |
---|
| 757 | + return error; |
---|
| 758 | + } |
---|
| 759 | + |
---|
| 760 | + error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); |
---|
| 761 | + if (error) { |
---|
| 762 | + dev_err(&client->dev, "failed to enter IAP mode: %d\n", |
---|
| 763 | + error); |
---|
| 764 | + return error; |
---|
| 765 | + } |
---|
654 | 766 | } |
---|
655 | 767 | |
---|
656 | 768 | msleep(20); |
---|
.. | .. |
---|
786 | 898 | { |
---|
787 | 899 | struct input_dev *input = ts->input; |
---|
788 | 900 | unsigned int n_fingers; |
---|
| 901 | + unsigned int tool_type; |
---|
789 | 902 | u16 finger_state; |
---|
790 | 903 | int i; |
---|
791 | 904 | |
---|
.. | .. |
---|
795 | 908 | |
---|
796 | 909 | dev_dbg(&ts->client->dev, |
---|
797 | 910 | "n_fingers: %u, state: %04x\n", n_fingers, finger_state); |
---|
| 911 | + |
---|
| 912 | + /* Note: all fingers have the same tool type */ |
---|
| 913 | + tool_type = buf[FW_POS_TOOL_TYPE] & BIT(0) ? |
---|
| 914 | + MT_TOOL_FINGER : MT_TOOL_PALM; |
---|
798 | 915 | |
---|
799 | 916 | for (i = 0; i < MAX_CONTACT_NUM && n_fingers; i++) { |
---|
800 | 917 | if (finger_state & 1) { |
---|
.. | .. |
---|
811 | 928 | i, x, y, p, w); |
---|
812 | 929 | |
---|
813 | 930 | input_mt_slot(input, i); |
---|
814 | | - input_mt_report_slot_state(input, MT_TOOL_FINGER, true); |
---|
815 | | - input_event(input, EV_ABS, ABS_MT_POSITION_X, x); |
---|
816 | | - input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); |
---|
| 931 | + input_mt_report_slot_state(input, tool_type, true); |
---|
| 932 | + touchscreen_report_pos(input, &ts->prop, x, y, true); |
---|
817 | 933 | input_event(input, EV_ABS, ABS_MT_PRESSURE, p); |
---|
818 | 934 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); |
---|
819 | 935 | |
---|
.. | .. |
---|
864 | 980 | int i; |
---|
865 | 981 | int len; |
---|
866 | 982 | |
---|
867 | | - len = i2c_master_recv(client, ts->buf, sizeof(ts->buf)); |
---|
| 983 | + len = i2c_master_recv_dmasafe(client, ts->buf, sizeof(ts->buf)); |
---|
868 | 984 | if (len < 0) { |
---|
869 | 985 | dev_err(&client->dev, "%s: failed to read data: %d\n", |
---|
870 | 986 | __func__, len); |
---|
.. | .. |
---|
888 | 1004 | break; |
---|
889 | 1005 | |
---|
890 | 1006 | ts->state = ELAN_STATE_NORMAL; |
---|
891 | | - /* fall through */ |
---|
| 1007 | + fallthrough; |
---|
892 | 1008 | |
---|
893 | 1009 | case ELAN_STATE_NORMAL: |
---|
894 | 1010 | |
---|
.. | .. |
---|
954 | 1070 | */ |
---|
955 | 1071 | static ssize_t calibrate_store(struct device *dev, |
---|
956 | 1072 | struct device_attribute *attr, |
---|
957 | | - const char *buf, size_t count) |
---|
| 1073 | + const char *buf, size_t count) |
---|
958 | 1074 | { |
---|
959 | 1075 | struct i2c_client *client = to_i2c_client(dev); |
---|
960 | 1076 | struct elants_data *ts = i2c_get_clientdata(client); |
---|
.. | .. |
---|
1000 | 1116 | "Normal" : "Recovery"); |
---|
1001 | 1117 | } |
---|
1002 | 1118 | |
---|
| 1119 | +static ssize_t show_calibration_count(struct device *dev, |
---|
| 1120 | + struct device_attribute *attr, char *buf) |
---|
| 1121 | +{ |
---|
| 1122 | + struct i2c_client *client = to_i2c_client(dev); |
---|
| 1123 | + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_REK, 0x00, 0x01 }; |
---|
| 1124 | + u8 resp[HEADER_SIZE]; |
---|
| 1125 | + u16 rek_count; |
---|
| 1126 | + int error; |
---|
| 1127 | + |
---|
| 1128 | + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), |
---|
| 1129 | + resp, sizeof(resp), 1, |
---|
| 1130 | + "read ReK status"); |
---|
| 1131 | + if (error) |
---|
| 1132 | + return sprintf(buf, "%d\n", error); |
---|
| 1133 | + |
---|
| 1134 | + rek_count = get_unaligned_be16(&resp[2]); |
---|
| 1135 | + return sprintf(buf, "0x%04x\n", rek_count); |
---|
| 1136 | +} |
---|
| 1137 | + |
---|
1003 | 1138 | static DEVICE_ATTR_WO(calibrate); |
---|
1004 | 1139 | static DEVICE_ATTR(iap_mode, S_IRUGO, show_iap_mode, NULL); |
---|
| 1140 | +static DEVICE_ATTR(calibration_count, S_IRUGO, show_calibration_count, NULL); |
---|
1005 | 1141 | static DEVICE_ATTR(update_fw, S_IWUSR, NULL, write_update_fw); |
---|
1006 | 1142 | |
---|
1007 | 1143 | struct elants_version_attribute { |
---|
.. | .. |
---|
1057 | 1193 | &dev_attr_calibrate.attr, |
---|
1058 | 1194 | &dev_attr_update_fw.attr, |
---|
1059 | 1195 | &dev_attr_iap_mode.attr, |
---|
| 1196 | + &dev_attr_calibration_count.attr, |
---|
1060 | 1197 | |
---|
1061 | 1198 | &elants_ver_attr_fw_version.dattr.attr, |
---|
1062 | 1199 | &elants_ver_attr_hw_version.dattr.attr, |
---|
.. | .. |
---|
1082 | 1219 | if (IS_ERR_OR_NULL(ts->reset_gpio)) |
---|
1083 | 1220 | return 0; |
---|
1084 | 1221 | |
---|
1085 | | - gpiod_set_value_cansleep(ts->reset_gpio, 1); |
---|
1086 | | - |
---|
1087 | 1222 | error = regulator_enable(ts->vcc33); |
---|
1088 | 1223 | if (error) { |
---|
1089 | 1224 | dev_err(&ts->client->dev, |
---|
1090 | 1225 | "failed to enable vcc33 regulator: %d\n", |
---|
1091 | 1226 | error); |
---|
1092 | | - goto release_reset_gpio; |
---|
| 1227 | + return error; |
---|
1093 | 1228 | } |
---|
1094 | 1229 | |
---|
1095 | 1230 | error = regulator_enable(ts->vccio); |
---|
.. | .. |
---|
1098 | 1233 | "failed to enable vccio regulator: %d\n", |
---|
1099 | 1234 | error); |
---|
1100 | 1235 | regulator_disable(ts->vcc33); |
---|
1101 | | - goto release_reset_gpio; |
---|
| 1236 | + return error; |
---|
1102 | 1237 | } |
---|
1103 | 1238 | |
---|
1104 | 1239 | /* |
---|
.. | .. |
---|
1107 | 1242 | */ |
---|
1108 | 1243 | udelay(ELAN_POWERON_DELAY_USEC); |
---|
1109 | 1244 | |
---|
1110 | | -release_reset_gpio: |
---|
1111 | 1245 | gpiod_set_value_cansleep(ts->reset_gpio, 0); |
---|
1112 | 1246 | if (error) |
---|
1113 | 1247 | return error; |
---|
.. | .. |
---|
1215 | 1349 | return error; |
---|
1216 | 1350 | } |
---|
1217 | 1351 | |
---|
1218 | | - ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW); |
---|
| 1352 | + ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); |
---|
1219 | 1353 | if (IS_ERR(ts->reset_gpio)) { |
---|
1220 | 1354 | error = PTR_ERR(ts->reset_gpio); |
---|
1221 | 1355 | |
---|
.. | .. |
---|
1266 | 1400 | ts->input->name = "Elan Touchscreen"; |
---|
1267 | 1401 | ts->input->id.bustype = BUS_I2C; |
---|
1268 | 1402 | |
---|
1269 | | - __set_bit(BTN_TOUCH, ts->input->keybit); |
---|
1270 | | - __set_bit(EV_ABS, ts->input->evbit); |
---|
1271 | | - __set_bit(EV_KEY, ts->input->evbit); |
---|
1272 | | - |
---|
1273 | | - /* Single touch input params setup */ |
---|
1274 | | - input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0); |
---|
1275 | | - input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0); |
---|
1276 | | - input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0); |
---|
1277 | | - input_abs_set_res(ts->input, ABS_X, ts->x_res); |
---|
1278 | | - input_abs_set_res(ts->input, ABS_Y, ts->y_res); |
---|
1279 | | - |
---|
1280 | 1403 | /* Multitouch input params setup */ |
---|
| 1404 | + |
---|
| 1405 | + input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); |
---|
| 1406 | + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); |
---|
| 1407 | + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); |
---|
| 1408 | + input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); |
---|
| 1409 | + input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE, |
---|
| 1410 | + 0, MT_TOOL_PALM, 0, 0); |
---|
| 1411 | + input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); |
---|
| 1412 | + input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); |
---|
| 1413 | + if (ts->major_res > 0) |
---|
| 1414 | + input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res); |
---|
| 1415 | + |
---|
| 1416 | + touchscreen_parse_properties(ts->input, true, &ts->prop); |
---|
| 1417 | + |
---|
1281 | 1418 | error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, |
---|
1282 | 1419 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); |
---|
1283 | 1420 | if (error) { |
---|
.. | .. |
---|
1285 | 1422 | "failed to initialize MT slots: %d\n", error); |
---|
1286 | 1423 | return error; |
---|
1287 | 1424 | } |
---|
1288 | | - |
---|
1289 | | - input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); |
---|
1290 | | - input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); |
---|
1291 | | - input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); |
---|
1292 | | - input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); |
---|
1293 | | - input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); |
---|
1294 | | - input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); |
---|
1295 | 1425 | |
---|
1296 | 1426 | error = input_register_device(ts->input); |
---|
1297 | 1427 | if (error) { |
---|