| .. | .. |
|---|
| 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) { |
|---|