1 /* 2 * Cypress APA trackpad with I2C interface 3 * 4 * Author: Dudley Du <dudl@cypress.com> 5 * 6 * Copyright (C) 2014 Cypress Semiconductor, Inc. 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file COPYING in the main directory of this archive for 10 * more details. 11 */ 12 13 #include <linux/delay.h> 14 #include <linux/i2c.h> 15 #include <linux/input.h> 16 #include <linux/input/mt.h> 17 #include <linux/mutex.h> 18 #include <linux/completion.h> 19 #include <linux/slab.h> 20 #include <linux/unaligned/access_ok.h> 21 #include "cyapa.h" 22 23 24 /* Macro of Gen5 */ 25 #define RECORD_EVENT_NONE 0 26 #define RECORD_EVENT_TOUCHDOWN 1 27 #define RECORD_EVENT_DISPLACE 2 28 #define RECORD_EVENT_LIFTOFF 3 29 30 #define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80 31 #define CYAPA_TSG_IMG_FW_HDR_SIZE 13 32 #define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE) 33 #define CYAPA_TSG_IMG_START_ROW_NUM 0x002e 34 #define CYAPA_TSG_IMG_END_ROW_NUM 0x01fe 35 #define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff 36 #define CYAPA_TSG_IMG_MAX_RECORDS (CYAPA_TSG_IMG_END_ROW_NUM - \ 37 CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1) 38 #define CYAPA_TSG_IMG_READ_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2) 39 #define CYAPA_TSG_START_OF_APPLICATION 0x1700 40 #define CYAPA_TSG_APP_INTEGRITY_SIZE 60 41 #define CYAPA_TSG_FLASH_MAP_METADATA_SIZE 60 42 #define CYAPA_TSG_BL_KEY_SIZE 8 43 44 #define CYAPA_TSG_MAX_CMD_SIZE 256 45 46 #define GEN5_BL_CMD_VERIFY_APP_INTEGRITY 0x31 47 #define GEN5_BL_CMD_GET_BL_INFO 0x38 48 #define GEN5_BL_CMD_PROGRAM_VERIFY_ROW 0x39 49 #define GEN5_BL_CMD_LAUNCH_APP 0x3b 50 #define GEN5_BL_CMD_INITIATE_BL 0x48 51 52 #define GEN5_HID_DESCRIPTOR_ADDR 0x0001 53 #define GEN5_REPORT_DESCRIPTOR_ADDR 0x0002 54 #define GEN5_INPUT_REPORT_ADDR 0x0003 55 #define GEN5_OUTPUT_REPORT_ADDR 0x0004 56 #define GEN5_CMD_DATA_ADDR 0x0006 57 58 #define GEN5_TOUCH_REPORT_HEAD_SIZE 7 59 #define GEN5_TOUCH_REPORT_MAX_SIZE 127 60 #define GEN5_BTN_REPORT_HEAD_SIZE 6 61 #define GEN5_BTN_REPORT_MAX_SIZE 14 62 #define GEN5_WAKEUP_EVENT_SIZE 4 63 #define GEN5_RAW_DATA_HEAD_SIZE 24 64 65 #define GEN5_BL_CMD_REPORT_ID 0x40 66 #define GEN5_BL_RESP_REPORT_ID 0x30 67 #define GEN5_APP_CMD_REPORT_ID 0x2f 68 #define GEN5_APP_RESP_REPORT_ID 0x1f 69 70 #define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0 71 #define GEN5_DEEP_SLEEP_RESP_LENGTH 5 72 73 #define GEN5_CMD_GET_PARAMETER 0x05 74 #define GEN5_CMD_SET_PARAMETER 0x06 75 #define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d 76 #define GEN5_PARAMETER_ACT_INTERVL_SIZE 1 77 #define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f 78 #define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2 79 #define GEN5_PARAMETER_LP_INTRVL_ID 0x4c 80 #define GEN5_PARAMETER_LP_INTRVL_SIZE 2 81 82 #define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08 83 84 #define GEN5_POWER_STATE_ACTIVE 0x01 85 #define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02 86 #define GEN5_POWER_STATE_READY 0x03 87 #define GEN5_POWER_STATE_IDLE 0x04 88 #define GEN5_POWER_STATE_BTN_ONLY 0x05 89 #define GEN5_POWER_STATE_OFF 0x06 90 91 #define GEN5_DEEP_SLEEP_STATE_MASK 0x03 92 #define GEN5_DEEP_SLEEP_STATE_ON 0x00 93 #define GEN5_DEEP_SLEEP_STATE_OFF 0x01 94 95 #define GEN5_DEEP_SLEEP_OPCODE 0x08 96 #define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f 97 98 #define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */ 99 #define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */ 100 101 #define GEN5_CMD_REPORT_ID_OFFSET 4 102 103 #define GEN5_RESP_REPORT_ID_OFFSET 2 104 #define GEN5_RESP_RSVD_OFFSET 3 105 #define GEN5_RESP_RSVD_KEY 0x00 106 #define GEN5_RESP_BL_SOP_OFFSET 4 107 #define GEN5_SOP_KEY 0x01 /* Start of Packet */ 108 #define GEN5_EOP_KEY 0x17 /* End of Packet */ 109 #define GEN5_RESP_APP_CMD_OFFSET 4 110 #define GET_GEN5_CMD_CODE(reg) ((reg) & 0x7f) 111 112 #define VALID_CMD_RESP_HEADER(resp, cmd) \ 113 (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \ 114 ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) && \ 115 (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd))) 116 117 #define GEN5_MIN_BL_CMD_LENGTH 13 118 #define GEN5_MIN_BL_RESP_LENGTH 11 119 #define GEN5_MIN_APP_CMD_LENGTH 7 120 #define GEN5_MIN_APP_RESP_LENGTH 5 121 #define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6 122 123 #define GEN5_RESP_LENGTH_OFFSET 0x00 124 #define GEN5_RESP_LENGTH_SIZE 2 125 126 #define GEN5_HID_DESCRIPTOR_SIZE 32 127 #define GEN5_BL_HID_REPORT_ID 0xff 128 #define GEN5_APP_HID_REPORT_ID 0xf7 129 #define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 130 #define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe 131 132 #define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d 133 #define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe 134 #define GEN5_APP_REPORT_DESCRIPTOR_SIZE 0xee 135 #define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa 136 #define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6 137 138 #define GEN5_TOUCH_REPORT_ID 0x01 139 #define GEN5_BTN_REPORT_ID 0x03 140 #define GEN5_WAKEUP_EVENT_REPORT_ID 0x04 141 #define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 142 #define GEN5_PUSH_BTN_REPORT_ID 0x06 143 144 #define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00) 145 146 #define GEN5_BL_INITIATE_RESP_LEN 11 147 #define GEN5_BL_FAIL_EXIT_RESP_LEN 11 148 #define GEN5_BL_FAIL_EXIT_STATUS_CODE 0x0c 149 #define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN 12 150 #define GEN5_BL_INTEGRITY_CHEKC_PASS 0x00 151 #define GEN5_BL_BLOCK_WRITE_RESP_LEN 11 152 #define GEN5_BL_READ_APP_INFO_RESP_LEN 31 153 #define GEN5_CMD_CALIBRATE 0x28 154 #define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE 0x00 155 #define CYAPA_SENSING_MODE_SELF_CAP 0x02 156 157 #define GEN5_CMD_RETRIEVE_DATA_STRUCTURE 0x24 158 #define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00 159 #define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01 160 161 #define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07 162 163 #define GEN5_CMD_EXECUTE_PANEL_SCAN 0x2a 164 #define GEN5_CMD_RETRIEVE_PANEL_SCAN 0x2b 165 #define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA 0x00 166 #define GEN5_PANEL_SCAN_MUTUAL_BASELINE 0x01 167 #define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT 0x02 168 #define GEN5_PANEL_SCAN_SELF_RAW_DATA 0x03 169 #define GEN5_PANEL_SCAN_SELF_BASELINE 0x04 170 #define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05 171 172 /* The offset only valid for reterive PWC and panel scan commands */ 173 #define GEN5_RESP_DATA_STRUCTURE_OFFSET 10 174 #define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07 175 176 #define GEN5_NUMBER_OF_TOUCH_OFFSET 5 177 #define GEN5_NUMBER_OF_TOUCH_MASK 0x1f 178 #define GEN5_BUTTONS_OFFSET 5 179 #define GEN5_BUTTONS_MASK 0x0f 180 #define GEN5_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03) 181 #define GEN5_GET_TOUCH_ID(reg) ((reg) & 0x1f) 182 183 #define GEN5_PRODUCT_FAMILY_MASK 0xf000 184 #define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000 185 186 #define TSG_INVALID_CMD 0xff 187 188 struct cyapa_gen5_touch_record { 189 /* 190 * Bit 7 - 3: reserved 191 * Bit 2 - 0: touch type; 192 * 0 : standard finger; 193 * 1 - 15 : reserved. 194 */ 195 u8 touch_type; 196 197 /* 198 * Bit 7: indicates touch liftoff status. 199 * 0 : touch is currently on the panel. 200 * 1 : touch record indicates a liftoff. 201 * Bit 6 - 5: indicates an event associated with this touch instance 202 * 0 : no event 203 * 1 : touchdown 204 * 2 : significant displacement (> active distance) 205 * 3 : liftoff (record reports last known coordinates) 206 * Bit 4 - 0: An arbitrary ID tag associated with a finger 207 * to allow tracking a touch as it moves around the panel. 208 */ 209 u8 touch_tip_event_id; 210 211 /* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */ 212 u8 x_lo; 213 214 /* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */ 215 u8 x_hi; 216 217 /* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */ 218 u8 y_lo; 219 220 /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */ 221 u8 y_hi; 222 223 /* Touch intensity in counts, pressure value. */ 224 u8 z; 225 226 /* 227 * The length of the major axis of the ellipse of contact between 228 * the finger and the panel (ABS_MT_TOUCH_MAJOR). 229 */ 230 u8 major_axis_len; 231 232 /* 233 * The length of the minor axis of the ellipse of contact between 234 * the finger and the panel (ABS_MT_TOUCH_MINOR). 235 */ 236 u8 minor_axis_len; 237 238 /* 239 * The length of the major axis of the approaching tool. 240 * (ABS_MT_WIDTH_MAJOR) 241 */ 242 u8 major_tool_len; 243 244 /* 245 * The length of the minor axis of the approaching tool. 246 * (ABS_MT_WIDTH_MINOR) 247 */ 248 u8 minor_tool_len; 249 250 /* 251 * The angle between the panel vertical axis and 252 * the major axis of the contact ellipse. This value is an 8-bit 253 * signed integer. The range is -127 to +127 (corresponding to 254 * -90 degree and +90 degree respectively). 255 * The positive direction is clockwise from the vertical axis. 256 * If the ellipse of contact degenerates into a circle, 257 * orientation is reported as 0. 258 */ 259 u8 orientation; 260 } __packed; 261 262 struct cyapa_gen5_report_data { 263 u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE]; 264 struct cyapa_gen5_touch_record touch_records[10]; 265 } __packed; 266 267 struct gen5_app_cmd_head { 268 __le16 addr; /* Output report register address, must be 0004h */ 269 /* Size of packet not including output report register address */ 270 __le16 length; 271 u8 report_id; /* Application output report id, must be 2Fh */ 272 u8 rsvd; /* Reserved, must be 0 */ 273 /* 274 * Bit 7: reserved, must be 0. 275 * Bit 6-0: command code. 276 */ 277 u8 cmd_code; 278 u8 parameter_data[0]; /* Parameter data variable based on cmd_code */ 279 } __packed; 280 281 /* Applicaton get/set parameter command data structure */ 282 struct gen5_app_set_parameter_data { 283 u8 parameter_id; 284 u8 parameter_size; 285 __le32 value; 286 } __packed; 287 288 struct gen5_app_get_parameter_data { 289 u8 parameter_id; 290 } __packed; 291 292 /* Variables to record latest gen5 trackpad power states. */ 293 #define GEN5_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s)) 294 #define GEN5_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode) 295 #define GEN5_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t)) 296 #define GEN5_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time) 297 #define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) \ 298 (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME) 299 300 static int cyapa_gen5_initialize(struct cyapa *cyapa) 301 { 302 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 303 304 init_completion(&gen5_pip->cmd_ready); 305 atomic_set(&gen5_pip->cmd_issued, 0); 306 mutex_init(&gen5_pip->cmd_lock); 307 308 gen5_pip->resp_sort_func = NULL; 309 gen5_pip->in_progress_cmd = TSG_INVALID_CMD; 310 gen5_pip->resp_data = NULL; 311 gen5_pip->resp_len = NULL; 312 313 cyapa->dev_pwr_mode = UNINIT_PWR_MODE; 314 cyapa->dev_sleep_time = UNINIT_SLEEP_TIME; 315 316 return 0; 317 } 318 319 /* Return negative errno, or else the number of bytes read. */ 320 static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) 321 { 322 int ret; 323 324 if (size == 0) 325 return 0; 326 327 if (!buf || size > CYAPA_REG_MAP_SIZE) 328 return -EINVAL; 329 330 ret = i2c_master_recv(cyapa->client, buf, size); 331 332 if (ret != size) 333 return (ret < 0) ? ret : -EIO; 334 335 return size; 336 } 337 338 /** 339 * Return a negative errno code else zero on success. 340 */ 341 static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) 342 { 343 int ret; 344 345 if (!buf || !size) 346 return -EINVAL; 347 348 ret = i2c_master_send(cyapa->client, buf, size); 349 350 if (ret != size) 351 return (ret < 0) ? ret : -EIO; 352 353 return 0; 354 } 355 356 /** 357 * This function is aimed to dump all not read data in Gen5 trackpad 358 * before send any command, otherwise, the interrupt line will be blocked. 359 */ 360 static int cyapa_empty_pip_output_data(struct cyapa *cyapa, 361 u8 *buf, int *len, cb_sort func) 362 { 363 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 364 int length; 365 int report_count; 366 int empty_count; 367 int buf_len; 368 int error; 369 370 buf_len = 0; 371 if (len) { 372 buf_len = (*len < CYAPA_REG_MAP_SIZE) ? 373 *len : CYAPA_REG_MAP_SIZE; 374 *len = 0; 375 } 376 377 report_count = 8; /* max 7 pending data before command response data */ 378 empty_count = 0; 379 do { 380 /* 381 * Depending on testing in cyapa driver, there are max 5 "02 00" 382 * packets between two valid buffered data report in firmware. 383 * So in order to dump all buffered data out and 384 * make interrupt line release for reassert again, 385 * we must set the empty_count check value bigger than 5 to 386 * make it work. Otherwise, in some situation, 387 * the interrupt line may unable to reactive again, 388 * which will cause trackpad device unable to 389 * report data any more. 390 * for example, it may happen in EFT and ESD testing. 391 */ 392 if (empty_count > 5) 393 return 0; 394 395 error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, 396 GEN5_RESP_LENGTH_SIZE); 397 if (error < 0) 398 return error; 399 400 length = get_unaligned_le16(gen5_pip->empty_buf); 401 if (length == GEN5_RESP_LENGTH_SIZE) { 402 empty_count++; 403 continue; 404 } else if (length > CYAPA_REG_MAP_SIZE) { 405 /* Should not happen */ 406 return -EINVAL; 407 } else if (length == 0) { 408 /* Application or bootloader launch data polled out. */ 409 length = GEN5_RESP_LENGTH_SIZE; 410 if (buf && buf_len && func && 411 func(cyapa, gen5_pip->empty_buf, length)) { 412 length = min(buf_len, length); 413 memcpy(buf, gen5_pip->empty_buf, length); 414 *len = length; 415 /* Response found, success. */ 416 return 0; 417 } 418 continue; 419 } 420 421 error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); 422 if (error < 0) 423 return error; 424 425 report_count--; 426 empty_count = 0; 427 length = get_unaligned_le16(gen5_pip->empty_buf); 428 if (length <= GEN5_RESP_LENGTH_SIZE) { 429 empty_count++; 430 } else if (buf && buf_len && func && 431 func(cyapa, gen5_pip->empty_buf, length)) { 432 length = min(buf_len, length); 433 memcpy(buf, gen5_pip->empty_buf, length); 434 *len = length; 435 /* Response found, success. */ 436 return 0; 437 } 438 439 error = -EINVAL; 440 } while (report_count); 441 442 return error; 443 } 444 445 static int cyapa_do_i2c_pip_cmd_irq_sync( 446 struct cyapa *cyapa, 447 u8 *cmd, size_t cmd_len, 448 unsigned long timeout) 449 { 450 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 451 int error; 452 453 /* Wait for interrupt to set ready completion */ 454 init_completion(&gen5_pip->cmd_ready); 455 456 atomic_inc(&gen5_pip->cmd_issued); 457 error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); 458 if (error) { 459 atomic_dec(&gen5_pip->cmd_issued); 460 return (error < 0) ? error : -EIO; 461 } 462 463 /* Wait for interrupt to indicate command is completed. */ 464 timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready, 465 msecs_to_jiffies(timeout)); 466 if (timeout == 0) { 467 atomic_dec(&gen5_pip->cmd_issued); 468 return -ETIMEDOUT; 469 } 470 471 return 0; 472 } 473 474 static int cyapa_do_i2c_pip_cmd_polling( 475 struct cyapa *cyapa, 476 u8 *cmd, size_t cmd_len, 477 u8 *resp_data, int *resp_len, 478 unsigned long timeout, 479 cb_sort func) 480 { 481 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 482 int tries; 483 int length; 484 int error; 485 486 atomic_inc(&gen5_pip->cmd_issued); 487 error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); 488 if (error) { 489 atomic_dec(&gen5_pip->cmd_issued); 490 return error < 0 ? error : -EIO; 491 } 492 493 length = resp_len ? *resp_len : 0; 494 if (resp_data && resp_len && length != 0 && func) { 495 tries = timeout / 5; 496 do { 497 usleep_range(3000, 5000); 498 *resp_len = length; 499 error = cyapa_empty_pip_output_data(cyapa, 500 resp_data, resp_len, func); 501 if (error || *resp_len == 0) 502 continue; 503 else 504 break; 505 } while (--tries > 0); 506 if ((error || *resp_len == 0) || tries <= 0) 507 error = error ? error : -ETIMEDOUT; 508 } 509 510 atomic_dec(&gen5_pip->cmd_issued); 511 return error; 512 } 513 514 static int cyapa_i2c_pip_cmd_irq_sync( 515 struct cyapa *cyapa, 516 u8 *cmd, int cmd_len, 517 u8 *resp_data, int *resp_len, 518 unsigned long timeout, 519 cb_sort func, 520 bool irq_mode) 521 { 522 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 523 int error; 524 525 if (!cmd || !cmd_len) 526 return -EINVAL; 527 528 /* Commands must be serialized. */ 529 error = mutex_lock_interruptible(&gen5_pip->cmd_lock); 530 if (error) 531 return error; 532 533 gen5_pip->resp_sort_func = func; 534 gen5_pip->resp_data = resp_data; 535 gen5_pip->resp_len = resp_len; 536 537 if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH && 538 cmd[4] == GEN5_APP_CMD_REPORT_ID) { 539 /* Application command */ 540 gen5_pip->in_progress_cmd = cmd[6] & 0x7f; 541 } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH && 542 cmd[4] == GEN5_BL_CMD_REPORT_ID) { 543 /* Bootloader command */ 544 gen5_pip->in_progress_cmd = cmd[7]; 545 } 546 547 /* Send command data, wait and read output response data's length. */ 548 if (irq_mode) { 549 gen5_pip->is_irq_mode = true; 550 error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, 551 timeout); 552 if (error == -ETIMEDOUT && resp_data && 553 resp_len && *resp_len != 0 && func) { 554 /* 555 * For some old version, there was no interrupt for 556 * the command response data, so need to poll here 557 * to try to get the response data. 558 */ 559 error = cyapa_empty_pip_output_data(cyapa, 560 resp_data, resp_len, func); 561 if (error || *resp_len == 0) 562 error = error ? error : -ETIMEDOUT; 563 } 564 } else { 565 gen5_pip->is_irq_mode = false; 566 error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len, 567 resp_data, resp_len, timeout, func); 568 } 569 570 gen5_pip->resp_sort_func = NULL; 571 gen5_pip->resp_data = NULL; 572 gen5_pip->resp_len = NULL; 573 gen5_pip->in_progress_cmd = TSG_INVALID_CMD; 574 575 mutex_unlock(&gen5_pip->cmd_lock); 576 return error; 577 } 578 579 static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, 580 u8 *data, int len) 581 { 582 if (!data || len < GEN5_MIN_BL_RESP_LENGTH) 583 return false; 584 585 /* Bootloader input report id 30h */ 586 if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID && 587 data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && 588 data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY) 589 return true; 590 591 return false; 592 } 593 594 static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, 595 u8 *data, int len) 596 { 597 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 598 int resp_len; 599 600 if (!data || len < GEN5_MIN_APP_RESP_LENGTH) 601 return false; 602 603 if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID && 604 data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) { 605 resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]); 606 if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 && 607 resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH && 608 data[5] == gen5_pip->in_progress_cmd) { 609 /* Unsupported command code */ 610 return false; 611 } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 612 gen5_pip->in_progress_cmd) { 613 /* Correct command response received */ 614 return true; 615 } 616 } 617 618 return false; 619 } 620 621 static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa, 622 u8 *buf, int len) 623 { 624 int resp_len; 625 int max_output_len; 626 627 /* Check hid descriptor. */ 628 if (len != GEN5_HID_DESCRIPTOR_SIZE) 629 return false; 630 631 resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]); 632 max_output_len = get_unaligned_le16(&buf[16]); 633 if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) { 634 if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID && 635 max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { 636 /* BL mode HID Descriptor */ 637 return true; 638 } else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] == 639 GEN5_APP_HID_REPORT_ID) && 640 max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { 641 /* APP mode HID Descriptor */ 642 return true; 643 } 644 } 645 646 return false; 647 } 648 649 static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa, 650 u8 *buf, int len) 651 { 652 if (len == GEN5_DEEP_SLEEP_RESP_LENGTH && 653 buf[GEN5_RESP_REPORT_ID_OFFSET] == 654 GEN5_APP_DEEP_SLEEP_REPORT_ID && 655 (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) == 656 GEN5_DEEP_SLEEP_OPCODE) 657 return true; 658 return false; 659 } 660 661 static int gen5_idle_state_parse(struct cyapa *cyapa) 662 { 663 u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE]; 664 int max_output_len; 665 int length; 666 u8 cmd[2]; 667 int ret; 668 int error; 669 670 /* 671 * Dump all buffered data firstly for the situation 672 * when the trackpad is just power on the cyapa go here. 673 */ 674 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); 675 676 memset(resp_data, 0, sizeof(resp_data)); 677 ret = cyapa_i2c_pip_read(cyapa, resp_data, 3); 678 if (ret != 3) 679 return ret < 0 ? ret : -EIO; 680 681 length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); 682 if (length == GEN5_RESP_LENGTH_SIZE) { 683 /* Normal state of Gen5 with no data to respose */ 684 cyapa->gen = CYAPA_GEN5; 685 686 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); 687 688 /* Read description from trackpad device */ 689 cmd[0] = 0x01; 690 cmd[1] = 0x00; 691 length = GEN5_HID_DESCRIPTOR_SIZE; 692 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 693 cmd, GEN5_RESP_LENGTH_SIZE, 694 resp_data, &length, 695 300, 696 cyapa_gen5_sort_hid_descriptor_data, 697 false); 698 if (error) 699 return error; 700 701 length = get_unaligned_le16( 702 &resp_data[GEN5_RESP_LENGTH_OFFSET]); 703 max_output_len = get_unaligned_le16(&resp_data[16]); 704 if ((length == GEN5_HID_DESCRIPTOR_SIZE || 705 length == GEN5_RESP_LENGTH_SIZE) && 706 (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == 707 GEN5_BL_HID_REPORT_ID) && 708 max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { 709 /* BL mode HID Description read */ 710 cyapa->state = CYAPA_STATE_GEN5_BL; 711 } else if ((length == GEN5_HID_DESCRIPTOR_SIZE || 712 length == GEN5_RESP_LENGTH_SIZE) && 713 (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == 714 GEN5_APP_HID_REPORT_ID) && 715 max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { 716 /* APP mode HID Description read */ 717 cyapa->state = CYAPA_STATE_GEN5_APP; 718 } else { 719 /* Should not happen!!! */ 720 cyapa->state = CYAPA_STATE_NO_DEVICE; 721 } 722 } 723 724 return 0; 725 } 726 727 static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data) 728 { 729 int length; 730 u8 resp_data[32]; 731 int max_output_len; 732 int ret; 733 734 /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header; 735 * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header. 736 * 737 * Must read HID Description content through out, 738 * otherwise Gen5 trackpad cannot response next command 739 * or report any touch or button data. 740 */ 741 ret = cyapa_i2c_pip_read(cyapa, resp_data, 742 GEN5_HID_DESCRIPTOR_SIZE); 743 if (ret != GEN5_HID_DESCRIPTOR_SIZE) 744 return ret < 0 ? ret : -EIO; 745 length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); 746 max_output_len = get_unaligned_le16(&resp_data[16]); 747 if (length == GEN5_RESP_LENGTH_SIZE) { 748 if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == 749 GEN5_BL_HID_REPORT_ID) { 750 /* 751 * BL mode HID Description has been previously 752 * read out. 753 */ 754 cyapa->gen = CYAPA_GEN5; 755 cyapa->state = CYAPA_STATE_GEN5_BL; 756 } else { 757 /* 758 * APP mode HID Description has been previously 759 * read out. 760 */ 761 cyapa->gen = CYAPA_GEN5; 762 cyapa->state = CYAPA_STATE_GEN5_APP; 763 } 764 } else if (length == GEN5_HID_DESCRIPTOR_SIZE && 765 resp_data[2] == GEN5_BL_HID_REPORT_ID && 766 max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { 767 /* BL mode HID Description read. */ 768 cyapa->gen = CYAPA_GEN5; 769 cyapa->state = CYAPA_STATE_GEN5_BL; 770 } else if (length == GEN5_HID_DESCRIPTOR_SIZE && 771 (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == 772 GEN5_APP_HID_REPORT_ID) && 773 max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { 774 /* APP mode HID Description read. */ 775 cyapa->gen = CYAPA_GEN5; 776 cyapa->state = CYAPA_STATE_GEN5_APP; 777 } else { 778 /* Should not happen!!! */ 779 cyapa->state = CYAPA_STATE_NO_DEVICE; 780 } 781 782 return 0; 783 } 784 785 static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data) 786 { 787 int length; 788 789 length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); 790 switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) { 791 case GEN5_TOUCH_REPORT_ID: 792 if (length < GEN5_TOUCH_REPORT_HEAD_SIZE || 793 length > GEN5_TOUCH_REPORT_MAX_SIZE) 794 return -EINVAL; 795 break; 796 case GEN5_BTN_REPORT_ID: 797 case GEN5_OLD_PUSH_BTN_REPORT_ID: 798 case GEN5_PUSH_BTN_REPORT_ID: 799 if (length < GEN5_BTN_REPORT_HEAD_SIZE || 800 length > GEN5_BTN_REPORT_MAX_SIZE) 801 return -EINVAL; 802 break; 803 case GEN5_WAKEUP_EVENT_REPORT_ID: 804 if (length != GEN5_WAKEUP_EVENT_SIZE) 805 return -EINVAL; 806 break; 807 default: 808 return -EINVAL; 809 } 810 811 cyapa->gen = CYAPA_GEN5; 812 cyapa->state = CYAPA_STATE_GEN5_APP; 813 return 0; 814 } 815 816 static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) 817 { 818 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 819 int length; 820 int ret; 821 822 /* 823 * Must read report data through out, 824 * otherwise Gen5 trackpad cannot response next command 825 * or report any touch or button data. 826 */ 827 length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); 828 ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); 829 if (ret != length) 830 return ret < 0 ? ret : -EIO; 831 832 if (length == GEN5_RESP_LENGTH_SIZE) { 833 /* Previous command has read the data through out. */ 834 if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == 835 GEN5_BL_RESP_REPORT_ID) { 836 /* Gen5 BL command response data detected */ 837 cyapa->gen = CYAPA_GEN5; 838 cyapa->state = CYAPA_STATE_GEN5_BL; 839 } else { 840 /* Gen5 APP command response data detected */ 841 cyapa->gen = CYAPA_GEN5; 842 cyapa->state = CYAPA_STATE_GEN5_APP; 843 } 844 } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == 845 GEN5_BL_RESP_REPORT_ID) && 846 (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == 847 GEN5_RESP_RSVD_KEY) && 848 (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] == 849 GEN5_SOP_KEY) && 850 (gen5_pip->empty_buf[length - 1] == 851 GEN5_EOP_KEY)) { 852 /* Gen5 BL command response data detected */ 853 cyapa->gen = CYAPA_GEN5; 854 cyapa->state = CYAPA_STATE_GEN5_BL; 855 } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == 856 GEN5_APP_RESP_REPORT_ID && 857 gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == 858 GEN5_RESP_RSVD_KEY) { 859 /* Gen5 APP command response data detected */ 860 cyapa->gen = CYAPA_GEN5; 861 cyapa->state = CYAPA_STATE_GEN5_APP; 862 } else { 863 /* Should not happen!!! */ 864 cyapa->state = CYAPA_STATE_NO_DEVICE; 865 } 866 867 return 0; 868 } 869 870 static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) 871 { 872 int length; 873 874 if (!reg_data || len < 3) 875 return -EINVAL; 876 877 cyapa->state = CYAPA_STATE_NO_DEVICE; 878 879 /* Parse based on Gen5 characteristic registers and bits */ 880 length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); 881 if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) { 882 gen5_idle_state_parse(cyapa); 883 } else if (length == GEN5_HID_DESCRIPTOR_SIZE && 884 (reg_data[2] == GEN5_BL_HID_REPORT_ID || 885 reg_data[2] == GEN5_APP_HID_REPORT_ID)) { 886 gen5_hid_description_header_parse(cyapa, reg_data); 887 } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE || 888 length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) && 889 reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) { 890 /* 0xEE 0x00 0xF6 is Gen5 APP report description header. */ 891 cyapa->gen = CYAPA_GEN5; 892 cyapa->state = CYAPA_STATE_GEN5_APP; 893 } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE && 894 reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) { 895 /* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */ 896 cyapa->gen = CYAPA_GEN5; 897 cyapa->state = CYAPA_STATE_GEN5_BL; 898 } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID || 899 reg_data[2] == GEN5_BTN_REPORT_ID || 900 reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID || 901 reg_data[2] == GEN5_PUSH_BTN_REPORT_ID || 902 reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) { 903 gen5_report_data_header_parse(cyapa, reg_data); 904 } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID || 905 reg_data[2] == GEN5_APP_RESP_REPORT_ID) { 906 gen5_cmd_resp_header_parse(cyapa, reg_data); 907 } 908 909 if (cyapa->gen == CYAPA_GEN5) { 910 /* 911 * Must read the content (e.g.: report description and so on) 912 * from trackpad device throughout. Otherwise, 913 * Gen5 trackpad cannot response to next command or 914 * report any touch or button data later. 915 */ 916 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); 917 918 if (cyapa->state == CYAPA_STATE_GEN5_APP || 919 cyapa->state == CYAPA_STATE_GEN5_BL) 920 return 0; 921 } 922 923 return -EAGAIN; 924 } 925 926 static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len) 927 { 928 if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) 929 return false; 930 931 if (buf[0] == 0 && buf[1] == 0) 932 return true; 933 934 /* Exit bootloader failed for some reason. */ 935 if (len == GEN5_BL_FAIL_EXIT_RESP_LEN && 936 buf[GEN5_RESP_REPORT_ID_OFFSET] == 937 GEN5_BL_RESP_REPORT_ID && 938 buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && 939 buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY && 940 buf[10] == GEN5_EOP_KEY) 941 return true; 942 943 return false; 944 } 945 946 static int cyapa_gen5_bl_exit(struct cyapa *cyapa) 947 { 948 949 u8 bl_gen5_bl_exit[] = { 0x04, 0x00, 950 0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00, 951 0x20, 0xc7, 0x17 952 }; 953 u8 resp_data[11]; 954 int resp_len; 955 int error; 956 957 resp_len = sizeof(resp_data); 958 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 959 bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit), 960 resp_data, &resp_len, 961 5000, cyapa_gen5_sort_bl_exit_data, false); 962 if (error) 963 return error; 964 965 if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN || 966 resp_data[GEN5_RESP_REPORT_ID_OFFSET] == 967 GEN5_BL_RESP_REPORT_ID) 968 return -EAGAIN; 969 970 if (resp_data[0] == 0x00 && resp_data[1] == 0x00) 971 return 0; 972 973 return -ENODEV; 974 } 975 976 static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state) 977 { 978 u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 }; 979 u8 resp_data[6]; 980 int resp_len; 981 int error; 982 983 cmd[7] = power_state; 984 resp_len = sizeof(resp_data); 985 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), 986 resp_data, &resp_len, 987 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); 988 if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) || 989 !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) 990 return error < 0 ? error : -EINVAL; 991 992 return 0; 993 } 994 995 static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, 996 u8 parameter_id, u16 interval_time) 997 { 998 struct gen5_app_cmd_head *app_cmd_head; 999 struct gen5_app_set_parameter_data *parameter_data; 1000 u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; 1001 int cmd_len; 1002 u8 resp_data[7]; 1003 int resp_len; 1004 u8 parameter_size; 1005 int error; 1006 1007 memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); 1008 app_cmd_head = (struct gen5_app_cmd_head *)cmd; 1009 parameter_data = (struct gen5_app_set_parameter_data *) 1010 app_cmd_head->parameter_data; 1011 cmd_len = sizeof(struct gen5_app_cmd_head) + 1012 sizeof(struct gen5_app_set_parameter_data); 1013 1014 switch (parameter_id) { 1015 case GEN5_PARAMETER_ACT_INTERVL_ID: 1016 parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE; 1017 break; 1018 case GEN5_PARAMETER_ACT_LFT_INTERVL_ID: 1019 parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE; 1020 break; 1021 case GEN5_PARAMETER_LP_INTRVL_ID: 1022 parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE; 1023 break; 1024 default: 1025 return -EINVAL; 1026 } 1027 1028 put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); 1029 /* 1030 * Don't include unused parameter value bytes and 1031 * 2 bytes register address. 1032 */ 1033 put_unaligned_le16(cmd_len - (4 - parameter_size) - 2, 1034 &app_cmd_head->length); 1035 app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; 1036 app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; 1037 parameter_data->parameter_id = parameter_id; 1038 parameter_data->parameter_size = parameter_size; 1039 put_unaligned_le32((u32)interval_time, ¶meter_data->value); 1040 resp_len = sizeof(resp_data); 1041 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, 1042 resp_data, &resp_len, 1043 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); 1044 if (error || resp_data[5] != parameter_id || 1045 resp_data[6] != parameter_size || 1046 !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER)) 1047 return error < 0 ? error : -EINVAL; 1048 1049 return 0; 1050 } 1051 1052 static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, 1053 u8 parameter_id, u16 *interval_time) 1054 { 1055 struct gen5_app_cmd_head *app_cmd_head; 1056 struct gen5_app_get_parameter_data *parameter_data; 1057 u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; 1058 int cmd_len; 1059 u8 resp_data[11]; 1060 int resp_len; 1061 u8 parameter_size; 1062 u16 mask, i; 1063 int error; 1064 1065 memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); 1066 app_cmd_head = (struct gen5_app_cmd_head *)cmd; 1067 parameter_data = (struct gen5_app_get_parameter_data *) 1068 app_cmd_head->parameter_data; 1069 cmd_len = sizeof(struct gen5_app_cmd_head) + 1070 sizeof(struct gen5_app_get_parameter_data); 1071 1072 *interval_time = 0; 1073 switch (parameter_id) { 1074 case GEN5_PARAMETER_ACT_INTERVL_ID: 1075 parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE; 1076 break; 1077 case GEN5_PARAMETER_ACT_LFT_INTERVL_ID: 1078 parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE; 1079 break; 1080 case GEN5_PARAMETER_LP_INTRVL_ID: 1081 parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE; 1082 break; 1083 default: 1084 return -EINVAL; 1085 } 1086 1087 put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); 1088 /* Don't include 2 bytes register address */ 1089 put_unaligned_le16(cmd_len - 2, &app_cmd_head->length); 1090 app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; 1091 app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER; 1092 parameter_data->parameter_id = parameter_id; 1093 1094 resp_len = sizeof(resp_data); 1095 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, 1096 resp_data, &resp_len, 1097 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); 1098 if (error || resp_data[5] != parameter_id || resp_data[6] == 0 || 1099 !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER)) 1100 return error < 0 ? error : -EINVAL; 1101 1102 mask = 0; 1103 for (i = 0; i < parameter_size; i++) 1104 mask |= (0xff << (i * 8)); 1105 *interval_time = get_unaligned_le16(&resp_data[7]) & mask; 1106 1107 return 0; 1108 } 1109 1110 static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) 1111 { 1112 struct gen5_app_cmd_head *app_cmd_head; 1113 u8 cmd[10]; 1114 u8 resp_data[7]; 1115 int resp_len; 1116 int error; 1117 1118 memset(cmd, 0, sizeof(cmd)); 1119 app_cmd_head = (struct gen5_app_cmd_head *)cmd; 1120 1121 put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); 1122 put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); 1123 app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; 1124 app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; 1125 app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT; 1126 app_cmd_head->parameter_data[1] = 0x01; 1127 app_cmd_head->parameter_data[2] = 0x01; 1128 resp_len = sizeof(resp_data); 1129 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), 1130 resp_data, &resp_len, 1131 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); 1132 if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT || 1133 !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) || 1134 resp_data[6] != 0x01) 1135 return error < 0 ? error : -EINVAL; 1136 1137 return 0; 1138 } 1139 1140 static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state) 1141 { 1142 u8 cmd[] = { 0x05, 0x00, 0x00, 0x08}; 1143 u8 resp_data[5]; 1144 int resp_len; 1145 int error; 1146 1147 cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK; 1148 resp_len = sizeof(resp_data); 1149 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), 1150 resp_data, &resp_len, 1151 500, cyapa_gen5_sort_deep_sleep_data, false); 1152 if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state)) 1153 return -EINVAL; 1154 1155 return 0; 1156 } 1157 1158 static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, 1159 u8 power_mode, u16 sleep_time) 1160 { 1161 struct device *dev = &cyapa->client->dev; 1162 u8 power_state; 1163 int error; 1164 1165 if (cyapa->state != CYAPA_STATE_GEN5_APP) 1166 return 0; 1167 1168 /* Dump all the report data before do power mode commmands. */ 1169 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); 1170 1171 if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { 1172 /* 1173 * Assume TP in deep sleep mode when driver is loaded, 1174 * avoid driver unload and reload command IO issue caused by TP 1175 * has been set into deep sleep mode when unloading. 1176 */ 1177 GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); 1178 } 1179 1180 if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) && 1181 GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) 1182 if (cyapa_gen5_get_interval_time(cyapa, 1183 GEN5_PARAMETER_LP_INTRVL_ID, 1184 &cyapa->dev_sleep_time) != 0) 1185 GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); 1186 1187 if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) { 1188 if (power_mode == PWR_MODE_OFF || 1189 power_mode == PWR_MODE_FULL_ACTIVE || 1190 power_mode == PWR_MODE_BTN_ONLY || 1191 GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { 1192 /* Has in correct power mode state, early return. */ 1193 return 0; 1194 } 1195 } 1196 1197 if (power_mode == PWR_MODE_OFF) { 1198 error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF); 1199 if (error) { 1200 dev_err(dev, "enter deep sleep fail: %d\n", error); 1201 return error; 1202 } 1203 1204 GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); 1205 return 0; 1206 } 1207 1208 /* 1209 * When trackpad in power off mode, it cannot change to other power 1210 * state directly, must be wake up from sleep firstly, then 1211 * continue to do next power sate change. 1212 */ 1213 if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { 1214 error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON); 1215 if (error) { 1216 dev_err(dev, "deep sleep wake fail: %d\n", error); 1217 return error; 1218 } 1219 } 1220 1221 if (power_mode == PWR_MODE_FULL_ACTIVE) { 1222 error = cyapa_gen5_change_power_state(cyapa, 1223 GEN5_POWER_STATE_ACTIVE); 1224 if (error) { 1225 dev_err(dev, "change to active fail: %d\n", error); 1226 return error; 1227 } 1228 1229 GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); 1230 } else if (power_mode == PWR_MODE_BTN_ONLY) { 1231 error = cyapa_gen5_change_power_state(cyapa, 1232 GEN5_POWER_STATE_BTN_ONLY); 1233 if (error) { 1234 dev_err(dev, "fail to button only mode: %d\n", error); 1235 return error; 1236 } 1237 1238 GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); 1239 } else { 1240 /* 1241 * Continue to change power mode even failed to set 1242 * interval time, it won't affect the power mode change. 1243 * except the sleep interval time is not correct. 1244 */ 1245 if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) || 1246 sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa)) 1247 if (cyapa_gen5_set_interval_time(cyapa, 1248 GEN5_PARAMETER_LP_INTRVL_ID, 1249 sleep_time) == 0) 1250 GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time); 1251 1252 if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME) 1253 power_state = GEN5_POWER_STATE_READY; 1254 else 1255 power_state = GEN5_POWER_STATE_IDLE; 1256 error = cyapa_gen5_change_power_state(cyapa, power_state); 1257 if (error) { 1258 dev_err(dev, "set power state to 0x%02x failed: %d\n", 1259 power_state, error); 1260 return error; 1261 } 1262 1263 /* 1264 * Disable pip report for a little time, firmware will 1265 * re-enable it automatically. It's used to fix the issue 1266 * that trackpad unable to report signal to wake system up 1267 * in the special situation that system is in suspending, and 1268 * at the same time, user touch trackpad to wake system up. 1269 * This function can avoid the data to be buffured when system 1270 * is suspending which may cause interrput line unable to be 1271 * asserted again. 1272 */ 1273 cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); 1274 cyapa_gen5_disable_pip_report(cyapa); 1275 1276 GEN5_DEV_SET_PWR_STATE(cyapa, 1277 cyapa_sleep_time_to_pwr_cmd(sleep_time)); 1278 } 1279 1280 return 0; 1281 } 1282 1283 static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa, 1284 u8 *buf, int len) 1285 { 1286 /* Check the report id and command code */ 1287 if (VALID_CMD_RESP_HEADER(buf, 0x02)) 1288 return true; 1289 1290 return false; 1291 } 1292 1293 static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) 1294 { 1295 u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, 1296 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17 1297 }; 1298 u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN]; 1299 int resp_len; 1300 int error; 1301 1302 resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN; 1303 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 1304 bl_query_data_cmd, sizeof(bl_query_data_cmd), 1305 resp_data, &resp_len, 1306 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false); 1307 if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN || 1308 !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) 1309 return error ? error : -EIO; 1310 1311 memcpy(&cyapa->product_id[0], &resp_data[8], 5); 1312 cyapa->product_id[5] = '-'; 1313 memcpy(&cyapa->product_id[6], &resp_data[13], 6); 1314 cyapa->product_id[12] = '-'; 1315 memcpy(&cyapa->product_id[13], &resp_data[19], 2); 1316 cyapa->product_id[15] = '\0'; 1317 1318 cyapa->fw_maj_ver = resp_data[22]; 1319 cyapa->fw_min_ver = resp_data[23]; 1320 1321 return 0; 1322 } 1323 1324 static int cyapa_gen5_get_query_data(struct cyapa *cyapa) 1325 { 1326 u8 get_system_information[] = { 1327 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 1328 }; 1329 u8 resp_data[71]; 1330 int resp_len; 1331 u16 product_family; 1332 int error; 1333 1334 resp_len = sizeof(resp_data); 1335 error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 1336 get_system_information, sizeof(get_system_information), 1337 resp_data, &resp_len, 1338 2000, cyapa_gen5_sort_system_info_data, false); 1339 if (error || resp_len < sizeof(resp_data)) 1340 return error ? error : -EIO; 1341 1342 product_family = get_unaligned_le16(&resp_data[7]); 1343 if ((product_family & GEN5_PRODUCT_FAMILY_MASK) != 1344 GEN5_PRODUCT_FAMILY_TRACKPAD) 1345 return -EINVAL; 1346 1347 cyapa->fw_maj_ver = resp_data[15]; 1348 cyapa->fw_min_ver = resp_data[16]; 1349 1350 cyapa->electrodes_x = resp_data[52]; 1351 cyapa->electrodes_y = resp_data[53]; 1352 1353 cyapa->physical_size_x = get_unaligned_le16(&resp_data[54]) / 100; 1354 cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100; 1355 1356 cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]); 1357 cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]); 1358 1359 cyapa->max_z = get_unaligned_le16(&resp_data[62]); 1360 1361 cyapa->x_origin = resp_data[64] & 0x01; 1362 cyapa->y_origin = resp_data[65] & 0x01; 1363 1364 cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK; 1365 1366 memcpy(&cyapa->product_id[0], &resp_data[33], 5); 1367 cyapa->product_id[5] = '-'; 1368 memcpy(&cyapa->product_id[6], &resp_data[38], 6); 1369 cyapa->product_id[12] = '-'; 1370 memcpy(&cyapa->product_id[13], &resp_data[44], 2); 1371 cyapa->product_id[15] = '\0'; 1372 1373 if (!cyapa->electrodes_x || !cyapa->electrodes_y || 1374 !cyapa->physical_size_x || !cyapa->physical_size_y || 1375 !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z) 1376 return -EINVAL; 1377 1378 return 0; 1379 } 1380 1381 static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) 1382 { 1383 struct device *dev = &cyapa->client->dev; 1384 int error; 1385 1386 if (cyapa->gen != CYAPA_GEN5) 1387 return -ENODEV; 1388 1389 switch (cyapa->state) { 1390 case CYAPA_STATE_GEN5_BL: 1391 error = cyapa_gen5_bl_exit(cyapa); 1392 if (error) { 1393 /* Rry to update trackpad product information. */ 1394 cyapa_gen5_bl_query_data(cyapa); 1395 goto out; 1396 } 1397 1398 cyapa->state = CYAPA_STATE_GEN5_APP; 1399 1400 case CYAPA_STATE_GEN5_APP: 1401 /* 1402 * If trackpad device in deep sleep mode, 1403 * the app command will fail. 1404 * So always try to reset trackpad device to full active when 1405 * the device state is requeried. 1406 */ 1407 error = cyapa_gen5_set_power_mode(cyapa, 1408 PWR_MODE_FULL_ACTIVE, 0); 1409 if (error) 1410 dev_warn(dev, "%s: failed to set power active mode.\n", 1411 __func__); 1412 1413 /* Get trackpad product information. */ 1414 error = cyapa_gen5_get_query_data(cyapa); 1415 if (error) 1416 goto out; 1417 /* Only support product ID starting with CYTRA */ 1418 if (memcmp(cyapa->product_id, product_id, 1419 strlen(product_id)) != 0) { 1420 dev_err(dev, "%s: unknown product ID (%s)\n", 1421 __func__, cyapa->product_id); 1422 error = -EINVAL; 1423 } 1424 break; 1425 default: 1426 error = -EINVAL; 1427 } 1428 1429 out: 1430 return error; 1431 } 1432 1433 /* 1434 * Return false, do not continue process 1435 * Return true, continue process. 1436 */ 1437 static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa) 1438 { 1439 struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; 1440 int length; 1441 1442 if (atomic_read(&gen5_pip->cmd_issued)) { 1443 /* Polling command response data. */ 1444 if (gen5_pip->is_irq_mode == false) 1445 return false; 1446 1447 /* 1448 * Read out all none command response data. 1449 * these output data may caused by user put finger on 1450 * trackpad when host waiting the command response. 1451 */ 1452 cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf, 1453 GEN5_RESP_LENGTH_SIZE); 1454 length = get_unaligned_le16(gen5_pip->irq_cmd_buf); 1455 length = (length <= GEN5_RESP_LENGTH_SIZE) ? 1456 GEN5_RESP_LENGTH_SIZE : length; 1457 if (length > GEN5_RESP_LENGTH_SIZE) 1458 cyapa_i2c_pip_read(cyapa, 1459 gen5_pip->irq_cmd_buf, length); 1460 1461 if (!(gen5_pip->resp_sort_func && 1462 gen5_pip->resp_sort_func(cyapa, 1463 gen5_pip->irq_cmd_buf, length))) { 1464 /* 1465 * Cover the Gen5 V1 firmware issue. 1466 * The issue is there is no interrut will be 1467 * asserted to notityf host to read a command 1468 * data out when always has finger touch on 1469 * trackpad during the command is issued to 1470 * trackad device. 1471 * This issue has the scenario is that, 1472 * user always has his fingers touched on 1473 * trackpad device when booting/rebooting 1474 * their chrome book. 1475 */ 1476 length = *gen5_pip->resp_len; 1477 cyapa_empty_pip_output_data(cyapa, 1478 gen5_pip->resp_data, 1479 &length, 1480 gen5_pip->resp_sort_func); 1481 if (gen5_pip->resp_len && length != 0) { 1482 *gen5_pip->resp_len = length; 1483 atomic_dec(&gen5_pip->cmd_issued); 1484 complete(&gen5_pip->cmd_ready); 1485 } 1486 return false; 1487 } 1488 1489 if (gen5_pip->resp_data && gen5_pip->resp_len) { 1490 *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ? 1491 *gen5_pip->resp_len : length; 1492 memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf, 1493 *gen5_pip->resp_len); 1494 } 1495 atomic_dec(&gen5_pip->cmd_issued); 1496 complete(&gen5_pip->cmd_ready); 1497 return false; 1498 } 1499 1500 return true; 1501 } 1502 1503 static void cyapa_gen5_report_buttons(struct cyapa *cyapa, 1504 const struct cyapa_gen5_report_data *report_data) 1505 { 1506 struct input_dev *input = cyapa->input; 1507 u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET]; 1508 1509 buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK; 1510 1511 if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) { 1512 input_report_key(input, BTN_LEFT, 1513 !!(buttons & CAPABILITY_LEFT_BTN_MASK)); 1514 } 1515 if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) { 1516 input_report_key(input, BTN_MIDDLE, 1517 !!(buttons & CAPABILITY_MIDDLE_BTN_MASK)); 1518 } 1519 if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) { 1520 input_report_key(input, BTN_RIGHT, 1521 !!(buttons & CAPABILITY_RIGHT_BTN_MASK)); 1522 } 1523 1524 input_sync(input); 1525 } 1526 1527 static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, 1528 const struct cyapa_gen5_touch_record *touch) 1529 { 1530 struct input_dev *input = cyapa->input; 1531 u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id); 1532 int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id); 1533 int x, y; 1534 1535 if (event_id == RECORD_EVENT_LIFTOFF) 1536 return; 1537 1538 input_mt_slot(input, slot); 1539 input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 1540 x = (touch->x_hi << 8) | touch->x_lo; 1541 if (cyapa->x_origin) 1542 x = cyapa->max_abs_x - x; 1543 input_report_abs(input, ABS_MT_POSITION_X, x); 1544 y = (touch->y_hi << 8) | touch->y_lo; 1545 if (cyapa->y_origin) 1546 y = cyapa->max_abs_y - y; 1547 input_report_abs(input, ABS_MT_POSITION_Y, y); 1548 input_report_abs(input, ABS_MT_PRESSURE, 1549 touch->z); 1550 input_report_abs(input, ABS_MT_TOUCH_MAJOR, 1551 touch->major_axis_len); 1552 input_report_abs(input, ABS_MT_TOUCH_MINOR, 1553 touch->minor_axis_len); 1554 1555 input_report_abs(input, ABS_MT_WIDTH_MAJOR, 1556 touch->major_tool_len); 1557 input_report_abs(input, ABS_MT_WIDTH_MINOR, 1558 touch->minor_tool_len); 1559 1560 input_report_abs(input, ABS_MT_ORIENTATION, 1561 touch->orientation); 1562 } 1563 1564 static void cyapa_gen5_report_touches(struct cyapa *cyapa, 1565 const struct cyapa_gen5_report_data *report_data) 1566 { 1567 struct input_dev *input = cyapa->input; 1568 unsigned int touch_num; 1569 int i; 1570 1571 touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] & 1572 GEN5_NUMBER_OF_TOUCH_MASK; 1573 1574 for (i = 0; i < touch_num; i++) 1575 cyapa_gen5_report_slot_data(cyapa, 1576 &report_data->touch_records[i]); 1577 1578 input_mt_sync_frame(input); 1579 input_sync(input); 1580 } 1581 1582 static int cyapa_gen5_irq_handler(struct cyapa *cyapa) 1583 { 1584 struct device *dev = &cyapa->client->dev; 1585 struct cyapa_gen5_report_data report_data; 1586 int ret; 1587 u8 report_id; 1588 unsigned int report_len; 1589 1590 if (cyapa->gen != CYAPA_GEN5 || 1591 cyapa->state != CYAPA_STATE_GEN5_APP) { 1592 dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n", 1593 cyapa->gen, cyapa->state); 1594 return -EINVAL; 1595 } 1596 1597 ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, 1598 GEN5_RESP_LENGTH_SIZE); 1599 if (ret != GEN5_RESP_LENGTH_SIZE) { 1600 dev_err(dev, "failed to read length bytes, (%d)\n", ret); 1601 return -EINVAL; 1602 } 1603 1604 report_len = get_unaligned_le16( 1605 &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]); 1606 if (report_len < GEN5_RESP_LENGTH_SIZE) { 1607 /* Invliad length or internal reset happened. */ 1608 dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n", 1609 report_len, report_data.report_head[0], 1610 report_data.report_head[1]); 1611 return -EINVAL; 1612 } 1613 1614 /* Idle, no data for report. */ 1615 if (report_len == GEN5_RESP_LENGTH_SIZE) 1616 return 0; 1617 1618 ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len); 1619 if (ret != report_len) { 1620 dev_err(dev, "failed to read %d bytes report data, (%d)\n", 1621 report_len, ret); 1622 return -EINVAL; 1623 } 1624 1625 report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET]; 1626 if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID && 1627 report_len == GEN5_WAKEUP_EVENT_SIZE) { 1628 /* 1629 * Device wake event from deep sleep mode for touch. 1630 * This interrupt event is used to wake system up. 1631 */ 1632 return 0; 1633 } else if (report_id != GEN5_TOUCH_REPORT_ID && 1634 report_id != GEN5_BTN_REPORT_ID && 1635 report_id != GEN5_OLD_PUSH_BTN_REPORT_ID && 1636 report_id != GEN5_PUSH_BTN_REPORT_ID) { 1637 /* Running in BL mode or unknown response data read. */ 1638 dev_err(dev, "invalid report_id=0x%02x\n", report_id); 1639 return -EINVAL; 1640 } 1641 1642 if (report_id == GEN5_TOUCH_REPORT_ID && 1643 (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE || 1644 report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) { 1645 /* Invalid report data length for finger packet. */ 1646 dev_err(dev, "invalid touch packet length=%d\n", report_len); 1647 return 0; 1648 } 1649 1650 if ((report_id == GEN5_BTN_REPORT_ID || 1651 report_id == GEN5_OLD_PUSH_BTN_REPORT_ID || 1652 report_id == GEN5_PUSH_BTN_REPORT_ID) && 1653 (report_len < GEN5_BTN_REPORT_HEAD_SIZE || 1654 report_len > GEN5_BTN_REPORT_MAX_SIZE)) { 1655 /* Invalid report data length of button packet. */ 1656 dev_err(dev, "invalid button packet length=%d\n", report_len); 1657 return 0; 1658 } 1659 1660 if (report_id == GEN5_TOUCH_REPORT_ID) 1661 cyapa_gen5_report_touches(cyapa, &report_data); 1662 else 1663 cyapa_gen5_report_buttons(cyapa, &report_data); 1664 1665 return 0; 1666 } 1667 1668 const struct cyapa_dev_ops cyapa_gen5_ops = { 1669 .initialize = cyapa_gen5_initialize, 1670 1671 .state_parse = cyapa_gen5_state_parse, 1672 .operational_check = cyapa_gen5_do_operational_check, 1673 1674 .irq_handler = cyapa_gen5_irq_handler, 1675 .irq_cmd_handler = cyapa_gen5_irq_cmd_handler, 1676 .sort_empty_output_data = cyapa_empty_pip_output_data, 1677 .set_power_mode = cyapa_gen5_set_power_mode, 1678 }; 1679