linux/drivers/input/mouse/cyapa_gen5.c
<<
>>
Prefs
   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 <asm/unaligned.h>
  21#include <linux/crc-itu-t.h>
  22#include "cyapa.h"
  23
  24
  25/* Macro of Gen5 */
  26#define RECORD_EVENT_NONE        0
  27#define RECORD_EVENT_TOUCHDOWN   1
  28#define RECORD_EVENT_DISPLACE    2
  29#define RECORD_EVENT_LIFTOFF     3
  30
  31#define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE      0x80
  32#define CYAPA_TSG_IMG_FW_HDR_SIZE           13
  33#define CYAPA_TSG_FW_ROW_SIZE               (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE)
  34#define CYAPA_TSG_IMG_START_ROW_NUM         0x002e
  35#define CYAPA_TSG_IMG_END_ROW_NUM           0x01fe
  36#define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff
  37#define CYAPA_TSG_IMG_MAX_RECORDS           (CYAPA_TSG_IMG_END_ROW_NUM - \
  38                                CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1)
  39#define CYAPA_TSG_IMG_READ_SIZE             (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2)
  40#define CYAPA_TSG_START_OF_APPLICATION      0x1700
  41#define CYAPA_TSG_APP_INTEGRITY_SIZE        60
  42#define CYAPA_TSG_FLASH_MAP_METADATA_SIZE   60
  43#define CYAPA_TSG_BL_KEY_SIZE               8
  44
  45#define CYAPA_TSG_MAX_CMD_SIZE              256
  46
  47#define GEN5_BL_CMD_VERIFY_APP_INTEGRITY    0x31
  48#define GEN5_BL_CMD_GET_BL_INFO             0x38
  49#define GEN5_BL_CMD_PROGRAM_VERIFY_ROW      0x39
  50#define GEN5_BL_CMD_LAUNCH_APP              0x3b
  51#define GEN5_BL_CMD_INITIATE_BL             0x48
  52
  53#define GEN5_HID_DESCRIPTOR_ADDR        0x0001
  54#define GEN5_REPORT_DESCRIPTOR_ADDR     0x0002
  55#define GEN5_INPUT_REPORT_ADDR          0x0003
  56#define GEN5_OUTPUT_REPORT_ADDR         0x0004
  57#define GEN5_CMD_DATA_ADDR              0x0006
  58
  59#define GEN5_TOUCH_REPORT_HEAD_SIZE     7
  60#define GEN5_TOUCH_REPORT_MAX_SIZE      127
  61#define GEN5_BTN_REPORT_HEAD_SIZE       6
  62#define GEN5_BTN_REPORT_MAX_SIZE        14
  63#define GEN5_WAKEUP_EVENT_SIZE          4
  64#define GEN5_RAW_DATA_HEAD_SIZE         24
  65
  66#define GEN5_BL_CMD_REPORT_ID           0x40
  67#define GEN5_BL_RESP_REPORT_ID          0x30
  68#define GEN5_APP_CMD_REPORT_ID          0x2f
  69#define GEN5_APP_RESP_REPORT_ID         0x1f
  70
  71#define GEN5_APP_DEEP_SLEEP_REPORT_ID   0xf0
  72#define GEN5_DEEP_SLEEP_RESP_LENGTH     5
  73
  74#define GEN5_CMD_GET_PARAMETER               0x05
  75#define GEN5_CMD_SET_PARAMETER               0x06
  76#define GEN5_PARAMETER_ACT_INTERVL_ID        0x4d
  77#define GEN5_PARAMETER_ACT_INTERVL_SIZE      1
  78#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID    0x4f
  79#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE  2
  80#define GEN5_PARAMETER_LP_INTRVL_ID          0x4c
  81#define GEN5_PARAMETER_LP_INTRVL_SIZE        2
  82
  83#define GEN5_PARAMETER_DISABLE_PIP_REPORT    0x08
  84
  85#define GEN5_POWER_STATE_ACTIVE              0x01
  86#define GEN5_POWER_STATE_LOOK_FOR_TOUCH      0x02
  87#define GEN5_POWER_STATE_READY               0x03
  88#define GEN5_POWER_STATE_IDLE                0x04
  89#define GEN5_POWER_STATE_BTN_ONLY            0x05
  90#define GEN5_POWER_STATE_OFF                 0x06
  91
  92#define GEN5_DEEP_SLEEP_STATE_MASK  0x03
  93#define GEN5_DEEP_SLEEP_STATE_ON    0x00
  94#define GEN5_DEEP_SLEEP_STATE_OFF   0x01
  95
  96#define GEN5_DEEP_SLEEP_OPCODE      0x08
  97#define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f
  98
  99#define GEN5_POWER_READY_MAX_INTRVL_TIME  50   /* Unit: ms */
 100#define GEN5_POWER_IDLE_MAX_INTRVL_TIME   250  /* Unit: ms */
 101
 102#define GEN5_CMD_REPORT_ID_OFFSET       4
 103
 104#define GEN5_RESP_REPORT_ID_OFFSET      2
 105#define GEN5_RESP_RSVD_OFFSET           3
 106#define     GEN5_RESP_RSVD_KEY          0x00
 107#define GEN5_RESP_BL_SOP_OFFSET         4
 108#define     GEN5_SOP_KEY                0x01  /* Start of Packet */
 109#define     GEN5_EOP_KEY                0x17  /* End of Packet */
 110#define GEN5_RESP_APP_CMD_OFFSET        4
 111#define     GET_GEN5_CMD_CODE(reg)      ((reg) & 0x7f)
 112
 113#define VALID_CMD_RESP_HEADER(resp, cmd)                                    \
 114        (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \
 115        ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) &&            \
 116        (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd)))
 117
 118#define GEN5_MIN_BL_CMD_LENGTH           13
 119#define GEN5_MIN_BL_RESP_LENGTH          11
 120#define GEN5_MIN_APP_CMD_LENGTH          7
 121#define GEN5_MIN_APP_RESP_LENGTH         5
 122#define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6
 123
 124#define GEN5_RESP_LENGTH_OFFSET  0x00
 125#define GEN5_RESP_LENGTH_SIZE    2
 126
 127#define GEN5_HID_DESCRIPTOR_SIZE      32
 128#define GEN5_BL_HID_REPORT_ID         0xff
 129#define GEN5_APP_HID_REPORT_ID        0xf7
 130#define GEN5_BL_MAX_OUTPUT_LENGTH     0x0100
 131#define GEN5_APP_MAX_OUTPUT_LENGTH    0x00fe
 132
 133#define GEN5_BL_REPORT_DESCRIPTOR_SIZE            0x1d
 134#define GEN5_BL_REPORT_DESCRIPTOR_ID              0xfe
 135#define GEN5_APP_REPORT_DESCRIPTOR_SIZE           0xee
 136#define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE  0xfa
 137#define GEN5_APP_REPORT_DESCRIPTOR_ID             0xf6
 138
 139#define GEN5_TOUCH_REPORT_ID         0x01
 140#define GEN5_BTN_REPORT_ID           0x03
 141#define GEN5_WAKEUP_EVENT_REPORT_ID  0x04
 142#define GEN5_OLD_PUSH_BTN_REPORT_ID  0x05
 143#define GEN5_PUSH_BTN_REPORT_ID      0x06
 144
 145#define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00)
 146
 147#define GEN5_BL_INITIATE_RESP_LEN            11
 148#define GEN5_BL_FAIL_EXIT_RESP_LEN           11
 149#define GEN5_BL_FAIL_EXIT_STATUS_CODE        0x0c
 150#define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN    12
 151#define GEN5_BL_INTEGRITY_CHEKC_PASS         0x00
 152#define GEN5_BL_BLOCK_WRITE_RESP_LEN         11
 153#define GEN5_BL_READ_APP_INFO_RESP_LEN       31
 154#define GEN5_CMD_CALIBRATE                   0x28
 155#define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE   0x00
 156#define CYAPA_SENSING_MODE_SELF_CAP          0x02
 157
 158#define GEN5_CMD_RETRIEVE_DATA_STRUCTURE     0x24
 159#define GEN5_RETRIEVE_MUTUAL_PWC_DATA        0x00
 160#define GEN5_RETRIEVE_SELF_CAP_PWC_DATA      0x01
 161
 162#define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
 163
 164#define GEN5_CMD_EXECUTE_PANEL_SCAN          0x2a
 165#define GEN5_CMD_RETRIEVE_PANEL_SCAN         0x2b
 166#define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA      0x00
 167#define GEN5_PANEL_SCAN_MUTUAL_BASELINE      0x01
 168#define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT     0x02
 169#define GEN5_PANEL_SCAN_SELF_RAW_DATA        0x03
 170#define GEN5_PANEL_SCAN_SELF_BASELINE        0x04
 171#define GEN5_PANEL_SCAN_SELF_DIFFCOUNT       0x05
 172
 173/* The offset only valid for reterive PWC and panel scan commands */
 174#define GEN5_RESP_DATA_STRUCTURE_OFFSET      10
 175#define GEN5_PWC_DATA_ELEMENT_SIZE_MASK      0x07
 176
 177#define GEN5_NUMBER_OF_TOUCH_OFFSET  5
 178#define GEN5_NUMBER_OF_TOUCH_MASK    0x1f
 179#define GEN5_BUTTONS_OFFSET          5
 180#define GEN5_BUTTONS_MASK            0x0f
 181#define GEN5_GET_EVENT_ID(reg)       (((reg) >> 5) & 0x03)
 182#define GEN5_GET_TOUCH_ID(reg)       ((reg) & 0x1f)
 183
 184#define GEN5_PRODUCT_FAMILY_MASK        0xf000
 185#define GEN5_PRODUCT_FAMILY_TRACKPAD    0x1000
 186
 187#define TSG_INVALID_CMD   0xff
 188
 189struct cyapa_gen5_touch_record {
 190        /*
 191         * Bit 7 - 3: reserved
 192         * Bit 2 - 0: touch type;
 193         *            0 : standard finger;
 194         *            1 - 15 : reserved.
 195         */
 196        u8 touch_type;
 197
 198        /*
 199         * Bit 7: indicates touch liftoff status.
 200         *              0 : touch is currently on the panel.
 201         *              1 : touch record indicates a liftoff.
 202         * Bit 6 - 5: indicates an event associated with this touch instance
 203         *              0 : no event
 204         *              1 : touchdown
 205         *              2 : significant displacement (> active distance)
 206         *              3 : liftoff (record reports last known coordinates)
 207         * Bit 4 - 0: An arbitrary ID tag associated with a finger
 208         *              to allow tracking a touch as it moves around the panel.
 209         */
 210        u8 touch_tip_event_id;
 211
 212        /* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */
 213        u8 x_lo;
 214
 215        /* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */
 216        u8 x_hi;
 217
 218        /* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */
 219        u8 y_lo;
 220
 221        /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */
 222        u8 y_hi;
 223
 224        /* Touch intensity in counts, pressure value. */
 225        u8 z;
 226
 227        /*
 228         * The length of the major axis of the ellipse of contact between
 229         * the finger and the panel (ABS_MT_TOUCH_MAJOR).
 230         */
 231        u8 major_axis_len;
 232
 233        /*
 234         * The length of the minor axis of the ellipse of contact between
 235         * the finger and the panel (ABS_MT_TOUCH_MINOR).
 236         */
 237        u8 minor_axis_len;
 238
 239        /*
 240         * The length of the major axis of the approaching tool.
 241         * (ABS_MT_WIDTH_MAJOR)
 242         */
 243        u8 major_tool_len;
 244
 245        /*
 246         * The length of the minor axis of the approaching tool.
 247         * (ABS_MT_WIDTH_MINOR)
 248         */
 249        u8 minor_tool_len;
 250
 251        /*
 252         * The angle between the panel vertical axis and
 253         * the major axis of the contact ellipse. This value is an 8-bit
 254         * signed integer. The range is -127 to +127 (corresponding to
 255         * -90 degree and +90 degree respectively).
 256         * The positive direction is clockwise from the vertical axis.
 257         * If the ellipse of contact degenerates into a circle,
 258         * orientation is reported as 0.
 259         */
 260        u8 orientation;
 261} __packed;
 262
 263struct cyapa_gen5_report_data {
 264        u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE];
 265        struct cyapa_gen5_touch_record touch_records[10];
 266} __packed;
 267
 268struct cyapa_tsg_bin_image_head {
 269        u8 head_size;  /* Unit: bytes, including itself. */
 270        u8 ttda_driver_major_version;  /* Reserved as 0. */
 271        u8 ttda_driver_minor_version;  /* Reserved as 0. */
 272        u8 fw_major_version;
 273        u8 fw_minor_version;
 274        u8 fw_revision_control_number[8];
 275} __packed;
 276
 277struct cyapa_tsg_bin_image_data_record {
 278        u8 flash_array_id;
 279        __be16 row_number;
 280        /* The number of bytes of flash data contained in this record. */
 281        __be16 record_len;
 282        /* The flash program data. */
 283        u8 record_data[CYAPA_TSG_FW_ROW_SIZE];
 284} __packed;
 285
 286struct cyapa_tsg_bin_image {
 287        struct cyapa_tsg_bin_image_head image_head;
 288        struct cyapa_tsg_bin_image_data_record records[0];
 289} __packed;
 290
 291struct gen5_bl_packet_start {
 292        u8 sop;  /* Start of packet, must be 01h */
 293        u8 cmd_code;
 294        __le16 data_length;  /* Size of data parameter start from data[0] */
 295} __packed;
 296
 297struct gen5_bl_packet_end {
 298        __le16 crc;
 299        u8 eop;  /* End of packet, must be 17h */
 300} __packed;
 301
 302struct gen5_bl_cmd_head {
 303        __le16 addr;   /* Output report register address, must be 0004h */
 304        /* Size of packet not including output report register address */
 305        __le16 length;
 306        u8 report_id;  /* Bootloader output report id, must be 40h */
 307        u8 rsvd;  /* Reserved, must be 0 */
 308        struct gen5_bl_packet_start packet_start;
 309        u8 data[0];  /* Command data variable based on commands */
 310} __packed;
 311
 312/* Initiate bootload command data structure. */
 313struct gen5_bl_initiate_cmd_data {
 314        /* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */
 315        u8 key[CYAPA_TSG_BL_KEY_SIZE];
 316        u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE];
 317        __le16 metadata_crc;
 318} __packed;
 319
 320struct gen5_bl_metadata_row_params {
 321        __le16 size;
 322        __le16 maximum_size;
 323        __le32 app_start;
 324        __le16 app_len;
 325        __le16 app_crc;
 326        __le32 app_entry;
 327        __le32 upgrade_start;
 328        __le16 upgrade_len;
 329        __le16 entry_row_crc;
 330        u8 padding[36];  /* Padding data must be 0 */
 331        __le16 metadata_crc;  /* CRC starts at offset of 60 */
 332} __packed;
 333
 334/* Bootload program and verify row command data structure */
 335struct gen5_bl_flash_row_head {
 336        u8 flash_array_id;
 337        __le16 flash_row_id;
 338        u8 flash_data[0];
 339} __packed;
 340
 341struct gen5_app_cmd_head {
 342        __le16 addr;   /* Output report register address, must be 0004h */
 343        /* Size of packet not including output report register address */
 344        __le16 length;
 345        u8 report_id;  /* Application output report id, must be 2Fh */
 346        u8 rsvd;  /* Reserved, must be 0 */
 347        /*
 348         * Bit 7: reserved, must be 0.
 349         * Bit 6-0: command code.
 350         */
 351        u8 cmd_code;
 352        u8 parameter_data[0];  /* Parameter data variable based on cmd_code */
 353} __packed;
 354
 355/* Applicaton get/set parameter command data structure */
 356struct gen5_app_set_parameter_data {
 357        u8 parameter_id;
 358        u8 parameter_size;
 359        __le32 value;
 360} __packed;
 361
 362struct gen5_app_get_parameter_data {
 363        u8 parameter_id;
 364} __packed;
 365
 366struct gen5_retrieve_panel_scan_data {
 367        __le16 read_offset;
 368        __le16 read_elements;
 369        u8 data_id;
 370} __packed;
 371
 372/* Variables to record latest gen5 trackpad power states. */
 373#define GEN5_DEV_SET_PWR_STATE(cyapa, s)        ((cyapa)->dev_pwr_mode = (s))
 374#define GEN5_DEV_GET_PWR_STATE(cyapa)           ((cyapa)->dev_pwr_mode)
 375#define GEN5_DEV_SET_SLEEP_TIME(cyapa, t)       ((cyapa)->dev_sleep_time = (t))
 376#define GEN5_DEV_GET_SLEEP_TIME(cyapa)          ((cyapa)->dev_sleep_time)
 377#define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa)       \
 378                (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME)
 379
 380
 381static u8 cyapa_gen5_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03,
 382        0xff, 0xfe, 0xfd, 0x5a };
 383
 384static int cyapa_gen5_initialize(struct cyapa *cyapa)
 385{
 386        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
 387
 388        init_completion(&gen5_pip->cmd_ready);
 389        atomic_set(&gen5_pip->cmd_issued, 0);
 390        mutex_init(&gen5_pip->cmd_lock);
 391
 392        gen5_pip->resp_sort_func = NULL;
 393        gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
 394        gen5_pip->resp_data = NULL;
 395        gen5_pip->resp_len = NULL;
 396
 397        cyapa->dev_pwr_mode = UNINIT_PWR_MODE;
 398        cyapa->dev_sleep_time = UNINIT_SLEEP_TIME;
 399
 400        return 0;
 401}
 402
 403/* Return negative errno, or else the number of bytes read. */
 404static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
 405{
 406        int ret;
 407
 408        if (size == 0)
 409                return 0;
 410
 411        if (!buf || size > CYAPA_REG_MAP_SIZE)
 412                return -EINVAL;
 413
 414        ret = i2c_master_recv(cyapa->client, buf, size);
 415
 416        if (ret != size)
 417                return (ret < 0) ? ret : -EIO;
 418
 419        return size;
 420}
 421
 422/**
 423 * Return a negative errno code else zero on success.
 424 */
 425static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
 426{
 427        int ret;
 428
 429        if (!buf || !size)
 430                return -EINVAL;
 431
 432        ret = i2c_master_send(cyapa->client, buf, size);
 433
 434        if (ret != size)
 435                return (ret < 0) ? ret : -EIO;
 436
 437        return 0;
 438}
 439
 440/**
 441 * This function is aimed to dump all not read data in Gen5 trackpad
 442 * before send any command, otherwise, the interrupt line will be blocked.
 443 */
 444static int cyapa_empty_pip_output_data(struct cyapa *cyapa,
 445                u8 *buf, int *len, cb_sort func)
 446{
 447        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
 448        int length;
 449        int report_count;
 450        int empty_count;
 451        int buf_len;
 452        int error;
 453
 454        buf_len = 0;
 455        if (len) {
 456                buf_len = (*len < CYAPA_REG_MAP_SIZE) ?
 457                                *len : CYAPA_REG_MAP_SIZE;
 458                *len = 0;
 459        }
 460
 461        report_count = 8;  /* max 7 pending data before command response data */
 462        empty_count = 0;
 463        do {
 464                /*
 465                 * Depending on testing in cyapa driver, there are max 5 "02 00"
 466                 * packets between two valid buffered data report in firmware.
 467                 * So in order to dump all buffered data out and
 468                 * make interrupt line release for reassert again,
 469                 * we must set the empty_count check value bigger than 5 to
 470                 * make it work. Otherwise, in some situation,
 471                 * the interrupt line may unable to reactive again,
 472                 * which will cause trackpad device unable to
 473                 * report data any more.
 474                 * for example, it may happen in EFT and ESD testing.
 475                 */
 476                if (empty_count > 5)
 477                        return 0;
 478
 479                error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf,
 480                                GEN5_RESP_LENGTH_SIZE);
 481                if (error < 0)
 482                        return error;
 483
 484                length = get_unaligned_le16(gen5_pip->empty_buf);
 485                if (length == GEN5_RESP_LENGTH_SIZE) {
 486                        empty_count++;
 487                        continue;
 488                } else if (length > CYAPA_REG_MAP_SIZE) {
 489                        /* Should not happen */
 490                        return -EINVAL;
 491                } else if (length == 0) {
 492                        /* Application or bootloader launch data polled out. */
 493                        length = GEN5_RESP_LENGTH_SIZE;
 494                        if (buf && buf_len && func &&
 495                                func(cyapa, gen5_pip->empty_buf, length)) {
 496                                length = min(buf_len, length);
 497                                memcpy(buf, gen5_pip->empty_buf, length);
 498                                *len = length;
 499                                /* Response found, success. */
 500                                return 0;
 501                        }
 502                        continue;
 503                }
 504
 505                error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
 506                if (error < 0)
 507                        return error;
 508
 509                report_count--;
 510                empty_count = 0;
 511                length = get_unaligned_le16(gen5_pip->empty_buf);
 512                if (length <= GEN5_RESP_LENGTH_SIZE) {
 513                        empty_count++;
 514                } else if (buf && buf_len && func &&
 515                        func(cyapa, gen5_pip->empty_buf, length)) {
 516                        length = min(buf_len, length);
 517                        memcpy(buf, gen5_pip->empty_buf, length);
 518                        *len = length;
 519                        /* Response found, success. */
 520                        return 0;
 521                }
 522
 523                error = -EINVAL;
 524        } while (report_count);
 525
 526        return error;
 527}
 528
 529static int cyapa_do_i2c_pip_cmd_irq_sync(
 530                struct cyapa *cyapa,
 531                u8 *cmd, size_t cmd_len,
 532                unsigned long timeout)
 533{
 534        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
 535        int error;
 536
 537        /* Wait for interrupt to set ready completion */
 538        init_completion(&gen5_pip->cmd_ready);
 539
 540        atomic_inc(&gen5_pip->cmd_issued);
 541        error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
 542        if (error) {
 543                atomic_dec(&gen5_pip->cmd_issued);
 544                return (error < 0) ? error : -EIO;
 545        }
 546
 547        /* Wait for interrupt to indicate command is completed. */
 548        timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready,
 549                                msecs_to_jiffies(timeout));
 550        if (timeout == 0) {
 551                atomic_dec(&gen5_pip->cmd_issued);
 552                return -ETIMEDOUT;
 553        }
 554
 555        return 0;
 556}
 557
 558static int cyapa_do_i2c_pip_cmd_polling(
 559                struct cyapa *cyapa,
 560                u8 *cmd, size_t cmd_len,
 561                u8 *resp_data, int *resp_len,
 562                unsigned long timeout,
 563                cb_sort func)
 564{
 565        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
 566        int tries;
 567        int length;
 568        int error;
 569
 570        atomic_inc(&gen5_pip->cmd_issued);
 571        error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
 572        if (error) {
 573                atomic_dec(&gen5_pip->cmd_issued);
 574                return error < 0 ? error : -EIO;
 575        }
 576
 577        length = resp_len ? *resp_len : 0;
 578        if (resp_data && resp_len && length != 0 && func) {
 579                tries = timeout / 5;
 580                do {
 581                        usleep_range(3000, 5000);
 582                        *resp_len = length;
 583                        error = cyapa_empty_pip_output_data(cyapa,
 584                                        resp_data, resp_len, func);
 585                        if (error || *resp_len == 0)
 586                                continue;
 587                        else
 588                                break;
 589                } while (--tries > 0);
 590                if ((error || *resp_len == 0) || tries <= 0)
 591                        error = error ? error : -ETIMEDOUT;
 592        }
 593
 594        atomic_dec(&gen5_pip->cmd_issued);
 595        return error;
 596}
 597
 598static int cyapa_i2c_pip_cmd_irq_sync(
 599                struct cyapa *cyapa,
 600                u8 *cmd, int cmd_len,
 601                u8 *resp_data, int *resp_len,
 602                unsigned long timeout,
 603                cb_sort func,
 604                bool irq_mode)
 605{
 606        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
 607        int error;
 608
 609        if (!cmd || !cmd_len)
 610                return -EINVAL;
 611
 612        /* Commands must be serialized. */
 613        error = mutex_lock_interruptible(&gen5_pip->cmd_lock);
 614        if (error)
 615                return error;
 616
 617        gen5_pip->resp_sort_func = func;
 618        gen5_pip->resp_data = resp_data;
 619        gen5_pip->resp_len = resp_len;
 620
 621        if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH &&
 622                        cmd[4] == GEN5_APP_CMD_REPORT_ID) {
 623                /* Application command */
 624                gen5_pip->in_progress_cmd = cmd[6] & 0x7f;
 625        } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH &&
 626                        cmd[4] == GEN5_BL_CMD_REPORT_ID) {
 627                /* Bootloader command */
 628                gen5_pip->in_progress_cmd = cmd[7];
 629        }
 630
 631        /* Send command data, wait and read output response data's length. */
 632        if (irq_mode) {
 633                gen5_pip->is_irq_mode = true;
 634                error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
 635                                                        timeout);
 636                if (error == -ETIMEDOUT && resp_data &&
 637                                resp_len && *resp_len != 0 && func) {
 638                        /*
 639                         * For some old version, there was no interrupt for
 640                         * the command response data, so need to poll here
 641                         * to try to get the response data.
 642                         */
 643                        error = cyapa_empty_pip_output_data(cyapa,
 644                                        resp_data, resp_len, func);
 645                        if (error || *resp_len == 0)
 646                                error = error ? error : -ETIMEDOUT;
 647                }
 648        } else {
 649                gen5_pip->is_irq_mode = false;
 650                error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len,
 651                                resp_data, resp_len, timeout, func);
 652        }
 653
 654        gen5_pip->resp_sort_func = NULL;
 655        gen5_pip->resp_data = NULL;
 656        gen5_pip->resp_len = NULL;
 657        gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
 658
 659        mutex_unlock(&gen5_pip->cmd_lock);
 660        return error;
 661}
 662
 663static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa,
 664                u8 *data, int len)
 665{
 666        if (!data || len < GEN5_MIN_BL_RESP_LENGTH)
 667                return false;
 668
 669        /* Bootloader input report id 30h */
 670        if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID &&
 671                        data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
 672                        data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY)
 673                return true;
 674
 675        return false;
 676}
 677
 678static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa,
 679                u8 *data, int len)
 680{
 681        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
 682        int resp_len;
 683
 684        if (!data || len < GEN5_MIN_APP_RESP_LENGTH)
 685                return false;
 686
 687        if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID &&
 688                        data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) {
 689                resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]);
 690                if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 &&
 691                        resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH &&
 692                        data[5] == gen5_pip->in_progress_cmd) {
 693                        /* Unsupported command code */
 694                        return false;
 695                } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) ==
 696                                gen5_pip->in_progress_cmd) {
 697                        /* Correct command response received */
 698                        return true;
 699                }
 700        }
 701
 702        return false;
 703}
 704
 705static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa,
 706                u8 *buf, int len)
 707{
 708        if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
 709                return false;
 710
 711        /*
 712         * After reset or power on, trackpad device always sets to 0x00 0x00
 713         * to indicate a reset or power on event.
 714         */
 715        if (buf[0] == 0 && buf[1] == 0)
 716                return true;
 717
 718        return false;
 719}
 720
 721static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa,
 722                u8 *buf, int len)
 723{
 724        int resp_len;
 725        int max_output_len;
 726
 727        /* Check hid descriptor. */
 728        if (len != GEN5_HID_DESCRIPTOR_SIZE)
 729                return false;
 730
 731        resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]);
 732        max_output_len = get_unaligned_le16(&buf[16]);
 733        if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) {
 734                if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID &&
 735                                max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
 736                        /* BL mode HID Descriptor */
 737                        return true;
 738                } else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] ==
 739                                GEN5_APP_HID_REPORT_ID) &&
 740                                max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
 741                        /* APP mode HID Descriptor */
 742                        return true;
 743                }
 744        }
 745
 746        return false;
 747}
 748
 749static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa,
 750                u8 *buf, int len)
 751{
 752        if (len == GEN5_DEEP_SLEEP_RESP_LENGTH &&
 753                buf[GEN5_RESP_REPORT_ID_OFFSET] ==
 754                        GEN5_APP_DEEP_SLEEP_REPORT_ID &&
 755                (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) ==
 756                        GEN5_DEEP_SLEEP_OPCODE)
 757                return true;
 758        return false;
 759}
 760
 761static int gen5_idle_state_parse(struct cyapa *cyapa)
 762{
 763        u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE];
 764        int max_output_len;
 765        int length;
 766        u8 cmd[2];
 767        int ret;
 768        int error;
 769
 770        /*
 771         * Dump all buffered data firstly for the situation
 772         * when the trackpad is just power on the cyapa go here.
 773         */
 774        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
 775
 776        memset(resp_data, 0, sizeof(resp_data));
 777        ret = cyapa_i2c_pip_read(cyapa, resp_data, 3);
 778        if (ret != 3)
 779                return ret < 0 ? ret : -EIO;
 780
 781        length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
 782        if (length == GEN5_RESP_LENGTH_SIZE) {
 783                /* Normal state of Gen5 with no data to respose */
 784                cyapa->gen = CYAPA_GEN5;
 785
 786                cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
 787
 788                /* Read description from trackpad device */
 789                cmd[0] = 0x01;
 790                cmd[1] = 0x00;
 791                length = GEN5_HID_DESCRIPTOR_SIZE;
 792                error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
 793                                cmd, GEN5_RESP_LENGTH_SIZE,
 794                                resp_data, &length,
 795                                300,
 796                                cyapa_gen5_sort_hid_descriptor_data,
 797                                false);
 798                if (error)
 799                        return error;
 800
 801                length = get_unaligned_le16(
 802                                &resp_data[GEN5_RESP_LENGTH_OFFSET]);
 803                max_output_len = get_unaligned_le16(&resp_data[16]);
 804                if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
 805                                length == GEN5_RESP_LENGTH_SIZE) &&
 806                        (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
 807                                GEN5_BL_HID_REPORT_ID) &&
 808                        max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
 809                        /* BL mode HID Description read */
 810                        cyapa->state = CYAPA_STATE_GEN5_BL;
 811                } else if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
 812                                length == GEN5_RESP_LENGTH_SIZE) &&
 813                        (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
 814                                GEN5_APP_HID_REPORT_ID) &&
 815                        max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
 816                        /* APP mode HID Description read */
 817                        cyapa->state = CYAPA_STATE_GEN5_APP;
 818                } else {
 819                        /* Should not happen!!! */
 820                        cyapa->state = CYAPA_STATE_NO_DEVICE;
 821                }
 822        }
 823
 824        return 0;
 825}
 826
 827static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
 828{
 829        int length;
 830        u8 resp_data[32];
 831        int max_output_len;
 832        int ret;
 833
 834        /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
 835         * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
 836         *
 837         * Must read HID Description content through out,
 838         * otherwise Gen5 trackpad cannot response next command
 839         * or report any touch or button data.
 840         */
 841        ret = cyapa_i2c_pip_read(cyapa, resp_data,
 842                        GEN5_HID_DESCRIPTOR_SIZE);
 843        if (ret != GEN5_HID_DESCRIPTOR_SIZE)
 844                return ret < 0 ? ret : -EIO;
 845        length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
 846        max_output_len = get_unaligned_le16(&resp_data[16]);
 847        if (length == GEN5_RESP_LENGTH_SIZE) {
 848                if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
 849                                GEN5_BL_HID_REPORT_ID) {
 850                        /*
 851                         * BL mode HID Description has been previously
 852                         * read out.
 853                         */
 854                        cyapa->gen = CYAPA_GEN5;
 855                        cyapa->state = CYAPA_STATE_GEN5_BL;
 856                } else {
 857                        /*
 858                         * APP mode HID Description has been previously
 859                         * read out.
 860                         */
 861                        cyapa->gen = CYAPA_GEN5;
 862                        cyapa->state = CYAPA_STATE_GEN5_APP;
 863                }
 864        } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
 865                        resp_data[2] == GEN5_BL_HID_REPORT_ID &&
 866                        max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
 867                /* BL mode HID Description read. */
 868                cyapa->gen = CYAPA_GEN5;
 869                cyapa->state = CYAPA_STATE_GEN5_BL;
 870        } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
 871                        (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
 872                                GEN5_APP_HID_REPORT_ID) &&
 873                        max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
 874                /* APP mode HID Description read. */
 875                cyapa->gen = CYAPA_GEN5;
 876                cyapa->state = CYAPA_STATE_GEN5_APP;
 877        } else {
 878                /* Should not happen!!! */
 879                cyapa->state = CYAPA_STATE_NO_DEVICE;
 880        }
 881
 882        return 0;
 883}
 884
 885static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data)
 886{
 887        int length;
 888
 889        length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
 890        switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) {
 891        case GEN5_TOUCH_REPORT_ID:
 892                if (length < GEN5_TOUCH_REPORT_HEAD_SIZE ||
 893                        length > GEN5_TOUCH_REPORT_MAX_SIZE)
 894                        return -EINVAL;
 895                break;
 896        case GEN5_BTN_REPORT_ID:
 897        case GEN5_OLD_PUSH_BTN_REPORT_ID:
 898        case GEN5_PUSH_BTN_REPORT_ID:
 899                if (length < GEN5_BTN_REPORT_HEAD_SIZE ||
 900                        length > GEN5_BTN_REPORT_MAX_SIZE)
 901                        return -EINVAL;
 902                break;
 903        case GEN5_WAKEUP_EVENT_REPORT_ID:
 904                if (length != GEN5_WAKEUP_EVENT_SIZE)
 905                        return -EINVAL;
 906                break;
 907        default:
 908                return -EINVAL;
 909        }
 910
 911        cyapa->gen = CYAPA_GEN5;
 912        cyapa->state = CYAPA_STATE_GEN5_APP;
 913        return 0;
 914}
 915
 916static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data)
 917{
 918        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
 919        int length;
 920        int ret;
 921
 922        /*
 923         * Must read report data through out,
 924         * otherwise Gen5 trackpad cannot response next command
 925         * or report any touch or button data.
 926         */
 927        length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
 928        ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
 929        if (ret != length)
 930                return ret < 0 ? ret : -EIO;
 931
 932        if (length == GEN5_RESP_LENGTH_SIZE) {
 933                /* Previous command has read the data through out. */
 934                if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
 935                                GEN5_BL_RESP_REPORT_ID) {
 936                        /* Gen5 BL command response data detected */
 937                        cyapa->gen = CYAPA_GEN5;
 938                        cyapa->state = CYAPA_STATE_GEN5_BL;
 939                } else {
 940                        /* Gen5 APP command response data detected */
 941                        cyapa->gen = CYAPA_GEN5;
 942                        cyapa->state = CYAPA_STATE_GEN5_APP;
 943                }
 944        } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
 945                                GEN5_BL_RESP_REPORT_ID) &&
 946                        (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
 947                                GEN5_RESP_RSVD_KEY) &&
 948                        (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] ==
 949                                GEN5_SOP_KEY) &&
 950                        (gen5_pip->empty_buf[length - 1] ==
 951                                GEN5_EOP_KEY)) {
 952                /* Gen5 BL command response data detected */
 953                cyapa->gen = CYAPA_GEN5;
 954                cyapa->state = CYAPA_STATE_GEN5_BL;
 955        } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
 956                                GEN5_APP_RESP_REPORT_ID &&
 957                        gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
 958                                GEN5_RESP_RSVD_KEY) {
 959                /* Gen5 APP command response data detected */
 960                cyapa->gen = CYAPA_GEN5;
 961                cyapa->state = CYAPA_STATE_GEN5_APP;
 962        } else {
 963                /* Should not happen!!! */
 964                cyapa->state = CYAPA_STATE_NO_DEVICE;
 965        }
 966
 967        return 0;
 968}
 969
 970static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
 971{
 972        int length;
 973
 974        if (!reg_data || len < 3)
 975                return -EINVAL;
 976
 977        cyapa->state = CYAPA_STATE_NO_DEVICE;
 978
 979        /* Parse based on Gen5 characteristic registers and bits */
 980        length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
 981        if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) {
 982                gen5_idle_state_parse(cyapa);
 983        } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
 984                        (reg_data[2] == GEN5_BL_HID_REPORT_ID ||
 985                                reg_data[2] == GEN5_APP_HID_REPORT_ID)) {
 986                gen5_hid_description_header_parse(cyapa, reg_data);
 987        } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE ||
 988                        length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) &&
 989                        reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) {
 990                /* 0xEE 0x00 0xF6 is Gen5 APP report description header. */
 991                cyapa->gen = CYAPA_GEN5;
 992                cyapa->state = CYAPA_STATE_GEN5_APP;
 993        } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE &&
 994                        reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) {
 995                /* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */
 996                cyapa->gen = CYAPA_GEN5;
 997                cyapa->state = CYAPA_STATE_GEN5_BL;
 998        } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID ||
 999                        reg_data[2] == GEN5_BTN_REPORT_ID ||
1000                        reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID ||
1001                        reg_data[2] == GEN5_PUSH_BTN_REPORT_ID ||
1002                        reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) {
1003                gen5_report_data_header_parse(cyapa, reg_data);
1004        } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID ||
1005                        reg_data[2] == GEN5_APP_RESP_REPORT_ID) {
1006                gen5_cmd_resp_header_parse(cyapa, reg_data);
1007        }
1008
1009        if (cyapa->gen == CYAPA_GEN5) {
1010                /*
1011                 * Must read the content (e.g.: report description and so on)
1012                 * from trackpad device throughout. Otherwise,
1013                 * Gen5 trackpad cannot response to next command or
1014                 * report any touch or button data later.
1015                 */
1016                cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1017
1018                if (cyapa->state == CYAPA_STATE_GEN5_APP ||
1019                        cyapa->state == CYAPA_STATE_GEN5_BL)
1020                        return 0;
1021        }
1022
1023        return -EAGAIN;
1024}
1025
1026static int cyapa_gen5_bl_initiate(struct cyapa *cyapa,
1027                const struct firmware *fw)
1028{
1029        struct cyapa_tsg_bin_image *image;
1030        struct gen5_bl_cmd_head *bl_cmd_head;
1031        struct gen5_bl_packet_start *bl_packet_start;
1032        struct gen5_bl_initiate_cmd_data *cmd_data;
1033        struct gen5_bl_packet_end *bl_packet_end;
1034        u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1035        int cmd_len;
1036        u16 cmd_data_len;
1037        u16 cmd_crc = 0;
1038        u16 meta_data_crc = 0;
1039        u8 resp_data[11];
1040        int resp_len;
1041        int records_num;
1042        u8 *data;
1043        int error;
1044
1045        /* Try to dump all buffered report data before any send command. */
1046        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1047
1048        memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1049        bl_cmd_head = (struct gen5_bl_cmd_head *)cmd;
1050        cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE;
1051        cmd_len = sizeof(struct gen5_bl_cmd_head) + cmd_data_len +
1052                  sizeof(struct gen5_bl_packet_end);
1053
1054        put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
1055        put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
1056        bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID;
1057
1058        bl_packet_start = &bl_cmd_head->packet_start;
1059        bl_packet_start->sop = GEN5_SOP_KEY;
1060        bl_packet_start->cmd_code = GEN5_BL_CMD_INITIATE_BL;
1061        /* 8 key bytes and 128 bytes block size */
1062        put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length);
1063
1064        cmd_data = (struct gen5_bl_initiate_cmd_data *)bl_cmd_head->data;
1065        memcpy(cmd_data->key, cyapa_gen5_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE);
1066
1067        /* Copy 60 bytes Meta Data Row Parameters */
1068        image = (struct cyapa_tsg_bin_image *)fw->data;
1069        records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
1070                                sizeof(struct cyapa_tsg_bin_image_data_record);
1071        /* APP_INTEGRITY row is always the last row block */
1072        data = image->records[records_num - 1].record_data;
1073        memcpy(cmd_data->metadata_raw_parameter, data,
1074                CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
1075
1076        meta_data_crc = crc_itu_t(0xffff, cmd_data->metadata_raw_parameter,
1077                                CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
1078        put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc);
1079
1080        bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data +
1081                                cmd_data_len);
1082        cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
1083                sizeof(struct gen5_bl_packet_start) + cmd_data_len);
1084        put_unaligned_le16(cmd_crc, &bl_packet_end->crc);
1085        bl_packet_end->eop = GEN5_EOP_KEY;
1086
1087        resp_len = sizeof(resp_data);
1088        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1089                        cmd, cmd_len,
1090                        resp_data, &resp_len, 12000,
1091                        cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
1092        if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN ||
1093                        resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
1094                        !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1095                return error ? error : -EAGAIN;
1096
1097        return 0;
1098}
1099
1100static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
1101{
1102        if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
1103                return false;
1104
1105        if (buf[0] == 0 && buf[1] == 0)
1106                return true;
1107
1108        /* Exit bootloader failed for some reason. */
1109        if (len == GEN5_BL_FAIL_EXIT_RESP_LEN &&
1110                        buf[GEN5_RESP_REPORT_ID_OFFSET] ==
1111                                GEN5_BL_RESP_REPORT_ID &&
1112                        buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
1113                        buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY &&
1114                        buf[10] == GEN5_EOP_KEY)
1115                return true;
1116
1117        return false;
1118}
1119
1120static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
1121{
1122
1123        u8 bl_gen5_bl_exit[] = { 0x04, 0x00,
1124                0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00,
1125                0x20, 0xc7, 0x17
1126        };
1127        u8 resp_data[11];
1128        int resp_len;
1129        int error;
1130
1131        resp_len = sizeof(resp_data);
1132        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1133                        bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit),
1134                        resp_data, &resp_len,
1135                        5000, cyapa_gen5_sort_bl_exit_data, false);
1136        if (error)
1137                return error;
1138
1139        if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN ||
1140                        resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
1141                                GEN5_BL_RESP_REPORT_ID)
1142                return -EAGAIN;
1143
1144        if (resp_data[0] == 0x00 && resp_data[1] == 0x00)
1145                return 0;
1146
1147        return -ENODEV;
1148}
1149
1150static int cyapa_gen5_bl_enter(struct cyapa *cyapa)
1151{
1152        u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
1153        u8 resp_data[2];
1154        int resp_len;
1155        int error;
1156
1157        error = cyapa_poll_state(cyapa, 500);
1158        if (error < 0)
1159                return error;
1160        if (cyapa->gen != CYAPA_GEN5)
1161                return -EINVAL;
1162
1163        /* Already in Gen5 BL. Skipping exit. */
1164        if (cyapa->state == CYAPA_STATE_GEN5_BL)
1165                return 0;
1166
1167        if (cyapa->state != CYAPA_STATE_GEN5_APP)
1168                return -EAGAIN;
1169
1170        /* Try to dump all buffered report data before any send command. */
1171        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1172
1173        /*
1174         * Send bootloader enter command to trackpad device,
1175         * after enter bootloader, the response data is two bytes of 0x00 0x00.
1176         */
1177        resp_len = sizeof(resp_data);
1178        memset(resp_data, 0, resp_len);
1179        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1180                        cmd, sizeof(cmd),
1181                        resp_data, &resp_len,
1182                        5000, cyapa_gen5_sort_application_launch_data,
1183                        true);
1184        if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00)
1185                return error < 0 ? error : -EAGAIN;
1186
1187        cyapa->operational = false;
1188        cyapa->state = CYAPA_STATE_GEN5_BL;
1189        return 0;
1190}
1191
1192static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw)
1193{
1194        struct device *dev = &cyapa->client->dev;
1195        const struct cyapa_tsg_bin_image *image = (const void *)fw->data;
1196        const struct cyapa_tsg_bin_image_data_record *app_integrity;
1197        const struct gen5_bl_metadata_row_params *metadata;
1198        size_t flash_records_count;
1199        u32 fw_app_start, fw_upgrade_start;
1200        u16 fw_app_len, fw_upgrade_len;
1201        u16 app_crc;
1202        u16 app_integrity_crc;
1203        int record_index;
1204        int i;
1205
1206        flash_records_count = (fw->size -
1207                        sizeof(struct cyapa_tsg_bin_image_head)) /
1208                        sizeof(struct cyapa_tsg_bin_image_data_record);
1209
1210        /*
1211         * APP_INTEGRITY row is always the last row block,
1212         * and the row id must be 0x01ff.
1213         */
1214        app_integrity = &image->records[flash_records_count - 1];
1215
1216        if (app_integrity->flash_array_id != 0x00 ||
1217            get_unaligned_be16(&app_integrity->row_number) != 0x01ff) {
1218                dev_err(dev, "%s: invalid app_integrity data.\n", __func__);
1219                return -EINVAL;
1220        }
1221
1222        metadata = (const void *)app_integrity->record_data;
1223
1224        /* Verify app_integrity crc */
1225        app_integrity_crc = crc_itu_t(0xffff, app_integrity->record_data,
1226                                      CYAPA_TSG_APP_INTEGRITY_SIZE);
1227        if (app_integrity_crc != get_unaligned_le16(&metadata->metadata_crc)) {
1228                dev_err(dev, "%s: invalid app_integrity crc.\n", __func__);
1229                return -EINVAL;
1230        }
1231
1232        fw_app_start = get_unaligned_le32(&metadata->app_start);
1233        fw_app_len = get_unaligned_le16(&metadata->app_len);
1234        fw_upgrade_start = get_unaligned_le32(&metadata->upgrade_start);
1235        fw_upgrade_len = get_unaligned_le16(&metadata->upgrade_len);
1236
1237        if (fw_app_start % CYAPA_TSG_FW_ROW_SIZE ||
1238            fw_app_len % CYAPA_TSG_FW_ROW_SIZE ||
1239            fw_upgrade_start % CYAPA_TSG_FW_ROW_SIZE ||
1240            fw_upgrade_len % CYAPA_TSG_FW_ROW_SIZE) {
1241                dev_err(dev, "%s: invalid image alignment.\n", __func__);
1242                return -EINVAL;
1243        }
1244
1245        /*
1246         * Verify application image CRC
1247         */
1248        record_index = fw_app_start / CYAPA_TSG_FW_ROW_SIZE -
1249                                CYAPA_TSG_IMG_START_ROW_NUM;
1250        app_crc = 0xffffU;
1251        for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) {
1252                const u8 *data = image->records[record_index + i].record_data;
1253                app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE);
1254        }
1255
1256        if (app_crc != get_unaligned_le16(&metadata->app_crc)) {
1257                dev_err(dev, "%s: invalid firmware app crc check.\n", __func__);
1258                return -EINVAL;
1259        }
1260
1261        return 0;
1262}
1263
1264static int cyapa_gen5_write_fw_block(struct cyapa *cyapa,
1265                struct cyapa_tsg_bin_image_data_record *flash_record)
1266{
1267        struct gen5_bl_cmd_head *bl_cmd_head;
1268        struct gen5_bl_packet_start *bl_packet_start;
1269        struct gen5_bl_flash_row_head *flash_row_head;
1270        struct gen5_bl_packet_end *bl_packet_end;
1271        u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1272        u16 cmd_len;
1273        u8 flash_array_id;
1274        u16 flash_row_id;
1275        u16 record_len;
1276        u8 *record_data;
1277        u16 data_len;
1278        u16 crc;
1279        u8 resp_data[11];
1280        int resp_len;
1281        int error;
1282
1283        flash_array_id = flash_record->flash_array_id;
1284        flash_row_id = get_unaligned_be16(&flash_record->row_number);
1285        record_len = get_unaligned_be16(&flash_record->record_len);
1286        record_data = flash_record->record_data;
1287
1288        memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1289        bl_cmd_head = (struct gen5_bl_cmd_head *)cmd;
1290        bl_packet_start = &bl_cmd_head->packet_start;
1291        cmd_len = sizeof(struct gen5_bl_cmd_head) +
1292                  sizeof(struct gen5_bl_flash_row_head) +
1293                  CYAPA_TSG_FLASH_MAP_BLOCK_SIZE +
1294                  sizeof(struct gen5_bl_packet_end);
1295
1296        put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
1297        /* Don't include 2 bytes register address */
1298        put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
1299        bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID;
1300        bl_packet_start->sop = GEN5_SOP_KEY;
1301        bl_packet_start->cmd_code = GEN5_BL_CMD_PROGRAM_VERIFY_ROW;
1302
1303        /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
1304        data_len = sizeof(struct gen5_bl_flash_row_head) + record_len;
1305        put_unaligned_le16(data_len, &bl_packet_start->data_length);
1306
1307        flash_row_head = (struct gen5_bl_flash_row_head *)bl_cmd_head->data;
1308        flash_row_head->flash_array_id = flash_array_id;
1309        put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id);
1310        memcpy(flash_row_head->flash_data, record_data, record_len);
1311
1312        bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data +
1313                                                      data_len);
1314        crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
1315                sizeof(struct gen5_bl_packet_start) + data_len);
1316        put_unaligned_le16(crc, &bl_packet_end->crc);
1317        bl_packet_end->eop = GEN5_EOP_KEY;
1318
1319        resp_len = sizeof(resp_data);
1320        error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1321                        resp_data, &resp_len,
1322                        500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
1323        if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN ||
1324                        resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
1325                        !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1326                return error < 0 ? error : -EAGAIN;
1327
1328        return 0;
1329}
1330
1331static int cyapa_gen5_do_fw_update(struct cyapa *cyapa,
1332                const struct firmware *fw)
1333{
1334        struct device *dev = &cyapa->client->dev;
1335        struct cyapa_tsg_bin_image_data_record *flash_record;
1336        struct cyapa_tsg_bin_image *image =
1337                (struct cyapa_tsg_bin_image *)fw->data;
1338        int flash_records_count;
1339        int i;
1340        int error;
1341
1342        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1343
1344        flash_records_count =
1345                (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
1346                        sizeof(struct cyapa_tsg_bin_image_data_record);
1347        /*
1348         * The last flash row 0x01ff has been written through bl_initiate
1349         * command, so DO NOT write flash 0x01ff to trackpad device.
1350         */
1351        for (i = 0; i < (flash_records_count - 1); i++) {
1352                flash_record = &image->records[i];
1353                error = cyapa_gen5_write_fw_block(cyapa, flash_record);
1354                if (error) {
1355                        dev_err(dev, "%s: Gen5 FW update aborted: %d\n",
1356                                __func__, error);
1357                        return error;
1358                }
1359        }
1360
1361        return 0;
1362}
1363
1364static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
1365{
1366        u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
1367        u8 resp_data[6];
1368        int resp_len;
1369        int error;
1370
1371        cmd[7] = power_state;
1372        resp_len = sizeof(resp_data);
1373        error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1374                        resp_data, &resp_len,
1375                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1376        if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) ||
1377                        !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1378                return error < 0 ? error : -EINVAL;
1379
1380        return 0;
1381}
1382
1383static int cyapa_gen5_set_interval_time(struct cyapa *cyapa,
1384                u8 parameter_id, u16 interval_time)
1385{
1386        struct gen5_app_cmd_head *app_cmd_head;
1387        struct gen5_app_set_parameter_data *parameter_data;
1388        u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1389        int cmd_len;
1390        u8 resp_data[7];
1391        int resp_len;
1392        u8 parameter_size;
1393        int error;
1394
1395        memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1396        app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1397        parameter_data = (struct gen5_app_set_parameter_data *)
1398                         app_cmd_head->parameter_data;
1399        cmd_len = sizeof(struct gen5_app_cmd_head) +
1400                  sizeof(struct gen5_app_set_parameter_data);
1401
1402        switch (parameter_id) {
1403        case GEN5_PARAMETER_ACT_INTERVL_ID:
1404                parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1405                break;
1406        case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1407                parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1408                break;
1409        case GEN5_PARAMETER_LP_INTRVL_ID:
1410                parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1411                break;
1412        default:
1413                return -EINVAL;
1414        }
1415
1416        put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
1417        /*
1418         * Don't include unused parameter value bytes and
1419         * 2 bytes register address.
1420         */
1421        put_unaligned_le16(cmd_len - (4 - parameter_size) - 2,
1422                           &app_cmd_head->length);
1423        app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1424        app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1425        parameter_data->parameter_id = parameter_id;
1426        parameter_data->parameter_size = parameter_size;
1427        put_unaligned_le32((u32)interval_time, &parameter_data->value);
1428        resp_len = sizeof(resp_data);
1429        error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1430                        resp_data, &resp_len,
1431                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1432        if (error || resp_data[5] != parameter_id ||
1433                resp_data[6] != parameter_size ||
1434                !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER))
1435                return error < 0 ? error : -EINVAL;
1436
1437        return 0;
1438}
1439
1440static int cyapa_gen5_get_interval_time(struct cyapa *cyapa,
1441                u8 parameter_id, u16 *interval_time)
1442{
1443        struct gen5_app_cmd_head *app_cmd_head;
1444        struct gen5_app_get_parameter_data *parameter_data;
1445        u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
1446        int cmd_len;
1447        u8 resp_data[11];
1448        int resp_len;
1449        u8 parameter_size;
1450        u16 mask, i;
1451        int error;
1452
1453        memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
1454        app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1455        parameter_data = (struct gen5_app_get_parameter_data *)
1456                         app_cmd_head->parameter_data;
1457        cmd_len = sizeof(struct gen5_app_cmd_head) +
1458                  sizeof(struct gen5_app_get_parameter_data);
1459
1460        *interval_time = 0;
1461        switch (parameter_id) {
1462        case GEN5_PARAMETER_ACT_INTERVL_ID:
1463                parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
1464                break;
1465        case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
1466                parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
1467                break;
1468        case GEN5_PARAMETER_LP_INTRVL_ID:
1469                parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
1470                break;
1471        default:
1472                return -EINVAL;
1473        }
1474
1475        put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
1476        /* Don't include 2 bytes register address */
1477        put_unaligned_le16(cmd_len - 2, &app_cmd_head->length);
1478        app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1479        app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER;
1480        parameter_data->parameter_id = parameter_id;
1481
1482        resp_len = sizeof(resp_data);
1483        error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
1484                        resp_data, &resp_len,
1485                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1486        if (error || resp_data[5] != parameter_id || resp_data[6] == 0 ||
1487                !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER))
1488                return error < 0 ? error : -EINVAL;
1489
1490        mask = 0;
1491        for (i = 0; i < parameter_size; i++)
1492                mask |= (0xff << (i * 8));
1493        *interval_time = get_unaligned_le16(&resp_data[7]) & mask;
1494
1495        return 0;
1496}
1497
1498static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa)
1499{
1500        struct gen5_app_cmd_head *app_cmd_head;
1501        u8 cmd[10];
1502        u8 resp_data[7];
1503        int resp_len;
1504        int error;
1505
1506        memset(cmd, 0, sizeof(cmd));
1507        app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1508
1509        put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
1510        put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
1511        app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1512        app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
1513        app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT;
1514        app_cmd_head->parameter_data[1] = 0x01;
1515        app_cmd_head->parameter_data[2] = 0x01;
1516        resp_len = sizeof(resp_data);
1517        error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1518                        resp_data, &resp_len,
1519                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
1520        if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT ||
1521                !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) ||
1522                resp_data[6] != 0x01)
1523                return error < 0 ? error : -EINVAL;
1524
1525        return 0;
1526}
1527
1528static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state)
1529{
1530        u8 cmd[] = { 0x05, 0x00, 0x00, 0x08};
1531        u8 resp_data[5];
1532        int resp_len;
1533        int error;
1534
1535        cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK;
1536        resp_len = sizeof(resp_data);
1537        error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
1538                        resp_data, &resp_len,
1539                        500, cyapa_gen5_sort_deep_sleep_data, false);
1540        if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state))
1541                return -EINVAL;
1542
1543        return 0;
1544}
1545
1546static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
1547                u8 power_mode, u16 sleep_time)
1548{
1549        struct device *dev = &cyapa->client->dev;
1550        u8 power_state;
1551        int error;
1552
1553        if (cyapa->state != CYAPA_STATE_GEN5_APP)
1554                return 0;
1555
1556        /* Dump all the report data before do power mode commmands. */
1557        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1558
1559        if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
1560                /*
1561                 * Assume TP in deep sleep mode when driver is loaded,
1562                 * avoid driver unload and reload command IO issue caused by TP
1563                 * has been set into deep sleep mode when unloading.
1564                 */
1565                GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
1566        }
1567
1568        if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) &&
1569                        GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
1570                if (cyapa_gen5_get_interval_time(cyapa,
1571                                GEN5_PARAMETER_LP_INTRVL_ID,
1572                                &cyapa->dev_sleep_time) != 0)
1573                        GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
1574
1575        if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) {
1576                if (power_mode == PWR_MODE_OFF ||
1577                        power_mode == PWR_MODE_FULL_ACTIVE ||
1578                        power_mode == PWR_MODE_BTN_ONLY ||
1579                        GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
1580                        /* Has in correct power mode state, early return. */
1581                        return 0;
1582                }
1583        }
1584
1585        if (power_mode == PWR_MODE_OFF) {
1586                error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF);
1587                if (error) {
1588                        dev_err(dev, "enter deep sleep fail: %d\n", error);
1589                        return error;
1590                }
1591
1592                GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
1593                return 0;
1594        }
1595
1596        /*
1597         * When trackpad in power off mode, it cannot change to other power
1598         * state directly, must be wake up from sleep firstly, then
1599         * continue to do next power sate change.
1600         */
1601        if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
1602                error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON);
1603                if (error) {
1604                        dev_err(dev, "deep sleep wake fail: %d\n", error);
1605                        return error;
1606                }
1607        }
1608
1609        if (power_mode == PWR_MODE_FULL_ACTIVE) {
1610                error = cyapa_gen5_change_power_state(cyapa,
1611                                GEN5_POWER_STATE_ACTIVE);
1612                if (error) {
1613                        dev_err(dev, "change to active fail: %d\n", error);
1614                        return error;
1615                }
1616
1617                GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
1618        } else if (power_mode == PWR_MODE_BTN_ONLY) {
1619                error = cyapa_gen5_change_power_state(cyapa,
1620                                GEN5_POWER_STATE_BTN_ONLY);
1621                if (error) {
1622                        dev_err(dev, "fail to button only mode: %d\n", error);
1623                        return error;
1624                }
1625
1626                GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
1627        } else {
1628                /*
1629                 * Continue to change power mode even failed to set
1630                 * interval time, it won't affect the power mode change.
1631                 * except the sleep interval time is not correct.
1632                 */
1633                if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) ||
1634                                sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa))
1635                        if (cyapa_gen5_set_interval_time(cyapa,
1636                                        GEN5_PARAMETER_LP_INTRVL_ID,
1637                                        sleep_time) == 0)
1638                                GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
1639
1640                if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME)
1641                        power_state = GEN5_POWER_STATE_READY;
1642                else
1643                        power_state = GEN5_POWER_STATE_IDLE;
1644                error = cyapa_gen5_change_power_state(cyapa, power_state);
1645                if (error) {
1646                        dev_err(dev, "set power state to 0x%02x failed: %d\n",
1647                                power_state, error);
1648                        return error;
1649                }
1650
1651                /*
1652                 * Disable pip report for a little time, firmware will
1653                 * re-enable it automatically. It's used to fix the issue
1654                 * that trackpad unable to report signal to wake system up
1655                 * in the special situation that system is in suspending, and
1656                 * at the same time, user touch trackpad to wake system up.
1657                 * This function can avoid the data to be buffured when system
1658                 * is suspending which may cause interrput line unable to be
1659                 * asserted again.
1660                 */
1661                cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1662                cyapa_gen5_disable_pip_report(cyapa);
1663
1664                GEN5_DEV_SET_PWR_STATE(cyapa,
1665                        cyapa_sleep_time_to_pwr_cmd(sleep_time));
1666        }
1667
1668        return 0;
1669}
1670
1671static int cyapa_gen5_resume_scanning(struct cyapa *cyapa)
1672{
1673        u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
1674        u8 resp_data[6];
1675        int resp_len;
1676        int error;
1677
1678        /* Try to dump all buffered data before doing command. */
1679        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1680
1681        resp_len = sizeof(resp_data);
1682        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1683                        cmd, sizeof(cmd),
1684                        resp_data, &resp_len,
1685                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
1686        if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04))
1687                return -EINVAL;
1688
1689        /* Try to dump all buffered data when resuming scanning. */
1690        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1691
1692        return 0;
1693}
1694
1695static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
1696{
1697        u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
1698        u8 resp_data[6];
1699        int resp_len;
1700        int error;
1701
1702        /* Try to dump all buffered data before doing command. */
1703        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1704
1705        resp_len = sizeof(resp_data);
1706        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1707                        cmd, sizeof(cmd),
1708                        resp_data, &resp_len,
1709                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
1710        if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03))
1711                return -EINVAL;
1712
1713        /* Try to dump all buffered data when suspending scanning. */
1714        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1715
1716        return 0;
1717}
1718
1719static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa,
1720                u8 calibrate_sensing_mode_type)
1721{
1722        struct gen5_app_cmd_head *app_cmd_head;
1723        u8 cmd[8];
1724        u8 resp_data[6];
1725        int resp_len;
1726        int error;
1727
1728        /* Try to dump all buffered data before doing command. */
1729        cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
1730
1731        memset(cmd, 0, sizeof(cmd));
1732        app_cmd_head = (struct gen5_app_cmd_head *)cmd;
1733        put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
1734        put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
1735        app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1736        app_cmd_head->cmd_code = GEN5_CMD_CALIBRATE;
1737        app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type;
1738        resp_len = sizeof(resp_data);
1739        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1740                        cmd, sizeof(cmd),
1741                        resp_data, &resp_len,
1742                        5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
1743        if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) ||
1744                        !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
1745                return error < 0 ? error : -EAGAIN;
1746
1747        return 0;
1748}
1749
1750static ssize_t cyapa_gen5_do_calibrate(struct device *dev,
1751                                     struct device_attribute *attr,
1752                                     const char *buf, size_t count)
1753{
1754        struct cyapa *cyapa = dev_get_drvdata(dev);
1755        int error, calibrate_error;
1756
1757        /* 1. Suspend Scanning*/
1758        error = cyapa_gen5_suspend_scanning(cyapa);
1759        if (error)
1760                return error;
1761
1762        /* 2. Do mutual capacitance fine calibrate. */
1763        calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
1764                                CYAPA_SENSING_MODE_MUTUAL_CAP_FINE);
1765        if (calibrate_error)
1766                goto resume_scanning;
1767
1768        /* 3. Do self capacitance calibrate. */
1769        calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
1770                                CYAPA_SENSING_MODE_SELF_CAP);
1771        if (calibrate_error)
1772                goto resume_scanning;
1773
1774resume_scanning:
1775        /* 4. Resume Scanning*/
1776        error = cyapa_gen5_resume_scanning(cyapa);
1777        if (error || calibrate_error)
1778                return error ? error : calibrate_error;
1779
1780        return count;
1781}
1782
1783static s32 twos_complement_to_s32(s32 value, int num_bits)
1784{
1785        if (value >> (num_bits - 1))
1786                value |=  -1 << num_bits;
1787        return value;
1788}
1789
1790static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len)
1791{
1792        int data_size;
1793        bool big_endian;
1794        bool unsigned_type;
1795        s32 value;
1796
1797        data_size = (data_format & 0x07);
1798        big_endian = ((data_format & 0x10) == 0x00);
1799        unsigned_type = ((data_format & 0x20) == 0x00);
1800
1801        if (buf_len < data_size)
1802                return 0;
1803
1804        switch (data_size) {
1805        case 1:
1806                value  = buf[0];
1807                break;
1808        case 2:
1809                if (big_endian)
1810                        value = get_unaligned_be16(buf);
1811                else
1812                        value = get_unaligned_le16(buf);
1813                break;
1814        case 4:
1815                if (big_endian)
1816                        value = get_unaligned_be32(buf);
1817                else
1818                        value = get_unaligned_le32(buf);
1819                break;
1820        default:
1821                /* Should not happen, just as default case here. */
1822                value = 0;
1823                break;
1824        }
1825
1826        if (!unsigned_type)
1827                value = twos_complement_to_s32(value, data_size * 8);
1828
1829        return value;
1830}
1831
1832static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa,
1833                int *electrodes_rx, int *electrodes_tx)
1834{
1835        if (cyapa->electrodes_rx != 0) {
1836                *electrodes_rx = cyapa->electrodes_rx;
1837                *electrodes_tx = (cyapa->electrodes_x == *electrodes_rx) ?
1838                                cyapa->electrodes_y : cyapa->electrodes_x;
1839        } else {
1840                *electrodes_tx = min(cyapa->electrodes_x, cyapa->electrodes_y);
1841                *electrodes_rx = max(cyapa->electrodes_x, cyapa->electrodes_y);
1842        }
1843}
1844
1845/*
1846 * Read all the global mutual or self idac data or mutual or self local PWC
1847 * data based on the @idac_data_type.
1848 * If the input value of @data_size is 0, then means read global mutual or
1849 * self idac data. For read global mutual idac data, @idac_max, @idac_min and
1850 * @idac_ave are in order used to return the max value of global mutual idac
1851 * data, the min value of global mutual idac and the average value of the
1852 * global mutual idac data. For read global self idac data, @idac_max is used
1853 * to return the global self cap idac data in Rx direction, @idac_min is used
1854 * to return the global self cap idac data in Tx direction. @idac_ave is not
1855 * used.
1856 * If the input value of @data_size is not 0, than means read the mutual or
1857 * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to
1858 * return the max, min and average value of the mutual or self local PWC data.
1859 * Note, in order to raed mutual local PWC data, must read invoke this function
1860 * to read the mutual global idac data firstly to set the correct Rx number
1861 * value, otherwise, the read mutual idac and PWC data may not correct.
1862 */
1863static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
1864                u8 cmd_code, u8 idac_data_type, int *data_size,
1865                int *idac_max, int *idac_min, int *idac_ave)
1866{
1867        struct gen5_app_cmd_head *cmd_head;
1868        u8 cmd[12];
1869        u8 resp_data[256];
1870        int resp_len;
1871        int read_len;
1872        int value;
1873        u16 offset;
1874        int read_elements;
1875        bool read_global_idac;
1876        int sum, count, max_element_cnt;
1877        int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count;
1878        int electrodes_rx, electrodes_tx;
1879        int i;
1880        int error;
1881
1882        if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE ||
1883                (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
1884                idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) ||
1885                !data_size || !idac_max || !idac_min || !idac_ave)
1886                return -EINVAL;
1887
1888        *idac_max = INT_MIN;
1889        *idac_min = INT_MAX;
1890        sum = count = tmp_count = 0;
1891        electrodes_rx = electrodes_tx = 0;
1892        if (*data_size == 0) {
1893                /*
1894                 * Read global idac values firstly.
1895                 * Currently, no idac data exceed 4 bytes.
1896                 */
1897                read_global_idac = true;
1898                offset = 0;
1899                *data_size = 4;
1900                tmp_max = INT_MIN;
1901                tmp_min = INT_MAX;
1902                tmp_ave = tmp_sum = tmp_count = 0;
1903
1904                if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
1905                        if (cyapa->aligned_electrodes_rx == 0) {
1906                                cyapa_gen5_guess_electrodes(cyapa,
1907                                        &electrodes_rx, &electrodes_tx);
1908                                cyapa->aligned_electrodes_rx =
1909                                        (electrodes_rx + 3) & ~3u;
1910                        }
1911                        max_element_cnt =
1912                                (cyapa->aligned_electrodes_rx + 7) & ~7u;
1913                } else {
1914                        max_element_cnt = 2;
1915                }
1916        } else {
1917                read_global_idac = false;
1918                if (*data_size > 4)
1919                        *data_size = 4;
1920                /* Calculate the start offset in bytes of local PWC data. */
1921                if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
1922                        offset = cyapa->aligned_electrodes_rx * (*data_size);
1923                        if (cyapa->electrodes_rx == cyapa->electrodes_x)
1924                                electrodes_tx = cyapa->electrodes_y;
1925                        else
1926                                electrodes_tx = cyapa->electrodes_x;
1927                        max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) &
1928                                                ~7u) * electrodes_tx;
1929                } else {
1930                        offset = 2;
1931                        max_element_cnt = cyapa->electrodes_x +
1932                                                cyapa->electrodes_y;
1933                        max_element_cnt = (max_element_cnt + 3) & ~3u;
1934                }
1935        }
1936
1937        memset(cmd, 0, sizeof(cmd));
1938        cmd_head = (struct gen5_app_cmd_head *)cmd;
1939        put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &cmd_head->addr);
1940        put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length);
1941        cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
1942        cmd_head->cmd_code = cmd_code;
1943        do {
1944                read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) /
1945                                (*data_size);
1946                read_elements = min(read_elements, max_element_cnt - count);
1947                read_len = read_elements * (*data_size);
1948
1949                put_unaligned_le16(offset, &cmd_head->parameter_data[0]);
1950                put_unaligned_le16(read_len, &cmd_head->parameter_data[2]);
1951                cmd_head->parameter_data[4] = idac_data_type;
1952                resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
1953                error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
1954                                cmd, sizeof(cmd),
1955                                resp_data, &resp_len,
1956                                500, cyapa_gen5_sort_tsg_pip_app_resp_data,
1957                                true);
1958                if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
1959                                !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
1960                                !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
1961                                resp_data[6] != idac_data_type)
1962                        return (error < 0) ? error : -EAGAIN;
1963                read_len = get_unaligned_le16(&resp_data[7]);
1964                if (read_len == 0)
1965                        break;
1966
1967                *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
1968                if (read_len < *data_size)
1969                        return -EINVAL;
1970
1971                if (read_global_idac &&
1972                        idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
1973                        /* Rx's self global idac data. */
1974                        *idac_max = cyapa_parse_structure_data(
1975                                resp_data[9],
1976                                &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET],
1977                                *data_size);
1978                        /* Tx's self global idac data. */
1979                        *idac_min = cyapa_parse_structure_data(
1980                                resp_data[9],
1981                                &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET +
1982                                           *data_size],
1983                                *data_size);
1984                        break;
1985                }
1986
1987                /* Read mutual global idac or local mutual/self PWC data. */
1988                offset += read_len;
1989                for (i = 10; i < (read_len + GEN5_RESP_DATA_STRUCTURE_OFFSET);
1990                                i += *data_size) {
1991                        value = cyapa_parse_structure_data(resp_data[9],
1992                                        &resp_data[i], *data_size);
1993                        *idac_min = min(value, *idac_min);
1994                        *idac_max = max(value, *idac_max);
1995
1996                        if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
1997                                tmp_count < cyapa->aligned_electrodes_rx &&
1998                                read_global_idac) {
1999                                /*
2000                                 * The value gap betwen global and local mutual
2001                                 * idac data must bigger than 50%.
2002                                 * Normally, global value bigger than 50,
2003                                 * local values less than 10.
2004                                 */
2005                                if (!tmp_ave || value > tmp_ave / 2) {
2006                                        tmp_min = min(value, tmp_min);
2007                                        tmp_max = max(value, tmp_max);
2008                                        tmp_sum += value;
2009                                        tmp_count++;
2010
2011                                        tmp_ave = tmp_sum / tmp_count;
2012                                }
2013                        }
2014
2015                        sum += value;
2016                        count++;
2017
2018                        if (count >= max_element_cnt)
2019                                goto out;
2020                }
2021        } while (true);
2022
2023out:
2024        *idac_ave = count ? (sum / count) : 0;
2025
2026        if (read_global_idac &&
2027                idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
2028                if (tmp_count == 0)
2029                        return 0;
2030
2031                if (tmp_count == cyapa->aligned_electrodes_rx) {
2032                        cyapa->electrodes_rx = cyapa->electrodes_rx ?
2033                                cyapa->electrodes_rx : electrodes_rx;
2034                } else if (tmp_count == electrodes_rx) {
2035                        cyapa->electrodes_rx = cyapa->electrodes_rx ?
2036                                cyapa->electrodes_rx : electrodes_rx;
2037                        cyapa->aligned_electrodes_rx = electrodes_rx;
2038                } else {
2039                        cyapa->electrodes_rx = cyapa->electrodes_rx ?
2040                                cyapa->electrodes_rx : electrodes_tx;
2041                        cyapa->aligned_electrodes_rx = tmp_count;
2042                }
2043
2044                *idac_min = tmp_min;
2045                *idac_max = tmp_max;
2046                *idac_ave = tmp_ave;
2047        }
2048
2049        return 0;
2050}
2051
2052static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa,
2053        int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave,
2054        int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave)
2055{
2056        int data_size;
2057        int error;
2058
2059        *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0;
2060        *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0;
2061
2062        data_size = 0;
2063        error = cyapa_gen5_read_idac_data(cyapa,
2064                GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2065                GEN5_RETRIEVE_MUTUAL_PWC_DATA,
2066                &data_size,
2067                gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave);
2068        if (error)
2069                return error;
2070
2071        error = cyapa_gen5_read_idac_data(cyapa,
2072                GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2073                GEN5_RETRIEVE_MUTUAL_PWC_DATA,
2074                &data_size,
2075                lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave);
2076        return error;
2077}
2078
2079static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa,
2080                int *gidac_self_rx, int *gidac_self_tx,
2081                int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave)
2082{
2083        int data_size;
2084        int error;
2085
2086        *gidac_self_rx = *gidac_self_tx = 0;
2087        *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0;
2088
2089        data_size = 0;
2090        error = cyapa_gen5_read_idac_data(cyapa,
2091                GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2092                GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
2093                &data_size,
2094                lidac_self_max, lidac_self_min, lidac_self_ave);
2095        if (error)
2096                return error;
2097        *gidac_self_rx = *lidac_self_max;
2098        *gidac_self_tx = *lidac_self_min;
2099
2100        error = cyapa_gen5_read_idac_data(cyapa,
2101                GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
2102                GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
2103                &data_size,
2104                lidac_self_max, lidac_self_min, lidac_self_ave);
2105        return error;
2106}
2107
2108static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa)
2109{
2110        struct gen5_app_cmd_head *app_cmd_head;
2111        u8 cmd[7];
2112        u8 resp_data[6];
2113        int resp_len;
2114        int error;
2115
2116        memset(cmd, 0, sizeof(cmd));
2117        app_cmd_head = (struct gen5_app_cmd_head *)cmd;
2118        put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
2119        put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
2120        app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
2121        app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN;
2122        resp_len = sizeof(resp_data);
2123        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2124                        cmd, sizeof(cmd),
2125                        resp_data, &resp_len,
2126                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
2127        if (error || resp_len != sizeof(resp_data) ||
2128                        !VALID_CMD_RESP_HEADER(resp_data,
2129                                GEN5_CMD_EXECUTE_PANEL_SCAN) ||
2130                        !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
2131                return error ? error : -EAGAIN;
2132
2133        return 0;
2134}
2135
2136static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa,
2137                u8 cmd_code, u8 raw_data_type, int raw_data_max_num,
2138                int *raw_data_max, int *raw_data_min, int *raw_data_ave,
2139                u8 *buffer)
2140{
2141        struct gen5_app_cmd_head *app_cmd_head;
2142        struct gen5_retrieve_panel_scan_data *panel_sacn_data;
2143        u8 cmd[12];
2144        u8 resp_data[256];  /* Max bytes can transfer one time. */
2145        int resp_len;
2146        int read_elements;
2147        int read_len;
2148        u16 offset;
2149        s32 value;
2150        int sum, count;
2151        int data_size;
2152        s32 *intp;
2153        int i;
2154        int error;
2155
2156        if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN ||
2157                (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) ||
2158                !raw_data_max || !raw_data_min || !raw_data_ave)
2159                return -EINVAL;
2160
2161        intp = (s32 *)buffer;
2162        *raw_data_max = INT_MIN;
2163        *raw_data_min = INT_MAX;
2164        sum = count = 0;
2165        offset = 0;
2166        /* Assume max element size is 4 currently. */
2167        read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4;
2168        read_len = read_elements * 4;
2169        app_cmd_head = (struct gen5_app_cmd_head *)cmd;
2170        put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
2171        put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
2172        app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
2173        app_cmd_head->cmd_code = cmd_code;
2174        panel_sacn_data = (struct gen5_retrieve_panel_scan_data *)
2175                        app_cmd_head->parameter_data;
2176        do {
2177                put_unaligned_le16(offset, &panel_sacn_data->read_offset);
2178                put_unaligned_le16(read_elements,
2179                        &panel_sacn_data->read_elements);
2180                panel_sacn_data->data_id = raw_data_type;
2181
2182                resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
2183                error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2184                        cmd, sizeof(cmd),
2185                        resp_data, &resp_len,
2186                        500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
2187                if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
2188                                !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
2189                                !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
2190                                resp_data[6] != raw_data_type)
2191                        return error ? error : -EAGAIN;
2192
2193                read_elements = get_unaligned_le16(&resp_data[7]);
2194                if (read_elements == 0)
2195                        break;
2196
2197                data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
2198                offset += read_elements;
2199                if (read_elements) {
2200                        for (i = GEN5_RESP_DATA_STRUCTURE_OFFSET;
2201                             i < (read_elements * data_size +
2202                                        GEN5_RESP_DATA_STRUCTURE_OFFSET);
2203                             i += data_size) {
2204                                value = cyapa_parse_structure_data(resp_data[9],
2205                                                &resp_data[i], data_size);
2206                                *raw_data_min = min(value, *raw_data_min);
2207                                *raw_data_max = max(value, *raw_data_max);
2208
2209                                if (intp)
2210                                        put_unaligned_le32(value, &intp[count]);
2211
2212                                sum += value;
2213                                count++;
2214
2215                        }
2216                }
2217
2218                if (count >= raw_data_max_num)
2219                        break;
2220
2221                read_elements = (sizeof(resp_data) -
2222                                GEN5_RESP_DATA_STRUCTURE_OFFSET) / data_size;
2223                read_len = read_elements * data_size;
2224        } while (true);
2225
2226        *raw_data_ave = count ? (sum / count) : 0;
2227
2228        return 0;
2229}
2230
2231static ssize_t cyapa_gen5_show_baseline(struct device *dev,
2232                                   struct device_attribute *attr, char *buf)
2233{
2234        struct cyapa *cyapa = dev_get_drvdata(dev);
2235        int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave;
2236        int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave;
2237        int gidac_self_rx, gidac_self_tx;
2238        int lidac_self_max, lidac_self_min, lidac_self_ave;
2239        int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
2240        int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
2241        int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave;
2242        int self_diffdata_max, self_diffdata_min, self_diffdata_ave;
2243        int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave;
2244        int self_baseline_max, self_baseline_min, self_baseline_ave;
2245        int error, resume_error;
2246        int size;
2247
2248        if (cyapa->state != CYAPA_STATE_GEN5_APP)
2249                return -EBUSY;
2250
2251        /* 1. Suspend Scanning*/
2252        error = cyapa_gen5_suspend_scanning(cyapa);
2253        if (error)
2254                return error;
2255
2256        /* 2.  Read global and local mutual IDAC data. */
2257        gidac_self_rx = gidac_self_tx = 0;
2258        error = cyapa_gen5_read_mutual_idac_data(cyapa,
2259                                &gidac_mutual_max, &gidac_mutual_min,
2260                                &gidac_mutual_ave, &lidac_mutual_max,
2261                                &lidac_mutual_min, &lidac_mutual_ave);
2262        if (error)
2263                goto resume_scanning;
2264
2265        /* 3.  Read global and local self IDAC data. */
2266        error = cyapa_gen5_read_self_idac_data(cyapa,
2267                                &gidac_self_rx, &gidac_self_tx,
2268                                &lidac_self_max, &lidac_self_min,
2269                                &lidac_self_ave);
2270        if (error)
2271                goto resume_scanning;
2272
2273        /* 4. Execuate panel scan. It must be executed before read data. */
2274        error = cyapa_gen5_execute_panel_scan(cyapa);
2275        if (error)
2276                goto resume_scanning;
2277
2278        /* 5. Retrieve panel scan, mutual cap raw data. */
2279        error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2280                                GEN5_CMD_RETRIEVE_PANEL_SCAN,
2281                                GEN5_PANEL_SCAN_MUTUAL_RAW_DATA,
2282                                cyapa->electrodes_x * cyapa->electrodes_y,
2283                                &raw_cap_mutual_max, &raw_cap_mutual_min,
2284                                &raw_cap_mutual_ave,
2285                                NULL);
2286        if (error)
2287                goto resume_scanning;
2288
2289        /* 6. Retrieve panel scan, self cap raw data. */
2290        error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2291                                GEN5_CMD_RETRIEVE_PANEL_SCAN,
2292                                GEN5_PANEL_SCAN_SELF_RAW_DATA,
2293                                cyapa->electrodes_x + cyapa->electrodes_y,
2294                                &raw_cap_self_max, &raw_cap_self_min,
2295                                &raw_cap_self_ave,
2296                                NULL);
2297        if (error)
2298                goto resume_scanning;
2299
2300        /* 7. Retrieve panel scan, mutual cap diffcount raw data. */
2301        error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2302                                GEN5_CMD_RETRIEVE_PANEL_SCAN,
2303                                GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
2304                                cyapa->electrodes_x * cyapa->electrodes_y,
2305                                &mutual_diffdata_max, &mutual_diffdata_min,
2306                                &mutual_diffdata_ave,
2307                                NULL);
2308        if (error)
2309                goto resume_scanning;
2310
2311        /* 8. Retrieve panel scan, self cap diffcount raw data. */
2312        error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2313                                GEN5_CMD_RETRIEVE_PANEL_SCAN,
2314                                GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
2315                                cyapa->electrodes_x + cyapa->electrodes_y,
2316                                &self_diffdata_max, &self_diffdata_min,
2317                                &self_diffdata_ave,
2318                                NULL);
2319        if (error)
2320                goto resume_scanning;
2321
2322        /* 9. Retrieve panel scan, mutual cap baseline raw data. */
2323        error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2324                                GEN5_CMD_RETRIEVE_PANEL_SCAN,
2325                                GEN5_PANEL_SCAN_MUTUAL_BASELINE,
2326                                cyapa->electrodes_x * cyapa->electrodes_y,
2327                                &mutual_baseline_max, &mutual_baseline_min,
2328                                &mutual_baseline_ave,
2329                                NULL);
2330        if (error)
2331                goto resume_scanning;
2332
2333        /* 10. Retrieve panel scan, self cap baseline raw data. */
2334        error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
2335                                GEN5_CMD_RETRIEVE_PANEL_SCAN,
2336                                GEN5_PANEL_SCAN_SELF_BASELINE,
2337                                cyapa->electrodes_x + cyapa->electrodes_y,
2338                                &self_baseline_max, &self_baseline_min,
2339                                &self_baseline_ave,
2340                                NULL);
2341        if (error)
2342                goto resume_scanning;
2343
2344resume_scanning:
2345        /* 11. Resume Scanning*/
2346        resume_error = cyapa_gen5_resume_scanning(cyapa);
2347        if (resume_error || error)
2348                return resume_error ? resume_error : error;
2349
2350        /* 12. Output data strings */
2351        size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
2352                gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
2353                lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
2354                gidac_self_rx, gidac_self_tx,
2355                lidac_self_min, lidac_self_max, lidac_self_ave);
2356        size += scnprintf(buf + size, PAGE_SIZE - size,
2357                "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
2358                raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
2359                raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
2360                mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave,
2361                self_diffdata_min, self_diffdata_max, self_diffdata_ave,
2362                mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave,
2363                self_baseline_min, self_baseline_max, self_baseline_ave);
2364        return size;
2365}
2366
2367static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
2368                u8 *buf, int len)
2369{
2370        /* Check the report id and command code */
2371        if (VALID_CMD_RESP_HEADER(buf, 0x02))
2372                return true;
2373
2374        return false;
2375}
2376
2377static int cyapa_gen5_bl_query_data(struct cyapa *cyapa)
2378{
2379        u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00,
2380                0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17
2381        };
2382        u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN];
2383        int resp_len;
2384        int error;
2385
2386        resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN;
2387        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2388                        bl_query_data_cmd, sizeof(bl_query_data_cmd),
2389                        resp_data, &resp_len,
2390                        500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false);
2391        if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN ||
2392                !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
2393                return error ? error : -EIO;
2394
2395        memcpy(&cyapa->product_id[0], &resp_data[8], 5);
2396        cyapa->product_id[5] = '-';
2397        memcpy(&cyapa->product_id[6], &resp_data[13], 6);
2398        cyapa->product_id[12] = '-';
2399        memcpy(&cyapa->product_id[13], &resp_data[19], 2);
2400        cyapa->product_id[15] = '\0';
2401
2402        cyapa->fw_maj_ver = resp_data[22];
2403        cyapa->fw_min_ver = resp_data[23];
2404
2405        return 0;
2406}
2407
2408static int cyapa_gen5_get_query_data(struct cyapa *cyapa)
2409{
2410        u8 get_system_information[] = {
2411                0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02
2412        };
2413        u8 resp_data[71];
2414        int resp_len;
2415        u16 product_family;
2416        int error;
2417
2418        resp_len = sizeof(resp_data);
2419        error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
2420                        get_system_information, sizeof(get_system_information),
2421                        resp_data, &resp_len,
2422                        2000, cyapa_gen5_sort_system_info_data, false);
2423        if (error || resp_len < sizeof(resp_data))
2424                return error ? error : -EIO;
2425
2426        product_family = get_unaligned_le16(&resp_data[7]);
2427        if ((product_family & GEN5_PRODUCT_FAMILY_MASK) !=
2428                GEN5_PRODUCT_FAMILY_TRACKPAD)
2429                return -EINVAL;
2430
2431        cyapa->fw_maj_ver = resp_data[15];
2432        cyapa->fw_min_ver = resp_data[16];
2433
2434        cyapa->electrodes_x = resp_data[52];
2435        cyapa->electrodes_y = resp_data[53];
2436
2437        cyapa->physical_size_x =  get_unaligned_le16(&resp_data[54]) / 100;
2438        cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100;
2439
2440        cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]);
2441        cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]);
2442
2443        cyapa->max_z = get_unaligned_le16(&resp_data[62]);
2444
2445        cyapa->x_origin = resp_data[64] & 0x01;
2446        cyapa->y_origin = resp_data[65] & 0x01;
2447
2448        cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
2449
2450        memcpy(&cyapa->product_id[0], &resp_data[33], 5);
2451        cyapa->product_id[5] = '-';
2452        memcpy(&cyapa->product_id[6], &resp_data[38], 6);
2453        cyapa->product_id[12] = '-';
2454        memcpy(&cyapa->product_id[13], &resp_data[44], 2);
2455        cyapa->product_id[15] = '\0';
2456
2457        if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
2458                !cyapa->physical_size_x || !cyapa->physical_size_y ||
2459                !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
2460                return -EINVAL;
2461
2462        return 0;
2463}
2464
2465static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
2466{
2467        struct device *dev = &cyapa->client->dev;
2468        int error;
2469
2470        if (cyapa->gen != CYAPA_GEN5)
2471                return -ENODEV;
2472
2473        switch (cyapa->state) {
2474        case CYAPA_STATE_GEN5_BL:
2475                error = cyapa_gen5_bl_exit(cyapa);
2476                if (error) {
2477                        /* Rry to update trackpad product information. */
2478                        cyapa_gen5_bl_query_data(cyapa);
2479                        goto out;
2480                }
2481
2482                cyapa->state = CYAPA_STATE_GEN5_APP;
2483
2484        case CYAPA_STATE_GEN5_APP:
2485                /*
2486                 * If trackpad device in deep sleep mode,
2487                 * the app command will fail.
2488                 * So always try to reset trackpad device to full active when
2489                 * the device state is requeried.
2490                 */
2491                error = cyapa_gen5_set_power_mode(cyapa,
2492                                PWR_MODE_FULL_ACTIVE, 0);
2493                if (error)
2494                        dev_warn(dev, "%s: failed to set power active mode.\n",
2495                                __func__);
2496
2497                /* Get trackpad product information. */
2498                error = cyapa_gen5_get_query_data(cyapa);
2499                if (error)
2500                        goto out;
2501                /* Only support product ID starting with CYTRA */
2502                if (memcmp(cyapa->product_id, product_id,
2503                                strlen(product_id)) != 0) {
2504                        dev_err(dev, "%s: unknown product ID (%s)\n",
2505                                __func__, cyapa->product_id);
2506                        error = -EINVAL;
2507                }
2508                break;
2509        default:
2510                error = -EINVAL;
2511        }
2512
2513out:
2514        return error;
2515}
2516
2517/*
2518 * Return false, do not continue process
2519 * Return true, continue process.
2520 */
2521static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
2522{
2523        struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
2524        int length;
2525
2526        if (atomic_read(&gen5_pip->cmd_issued)) {
2527                /* Polling command response data. */
2528                if (gen5_pip->is_irq_mode == false)
2529                        return false;
2530
2531                /*
2532                 * Read out all none command response data.
2533                 * these output data may caused by user put finger on
2534                 * trackpad when host waiting the command response.
2535                 */
2536                cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf,
2537                        GEN5_RESP_LENGTH_SIZE);
2538                length = get_unaligned_le16(gen5_pip->irq_cmd_buf);
2539                length = (length <= GEN5_RESP_LENGTH_SIZE) ?
2540                                GEN5_RESP_LENGTH_SIZE : length;
2541                if (length > GEN5_RESP_LENGTH_SIZE)
2542                        cyapa_i2c_pip_read(cyapa,
2543                                gen5_pip->irq_cmd_buf, length);
2544
2545                if (!(gen5_pip->resp_sort_func &&
2546                        gen5_pip->resp_sort_func(cyapa,
2547                                gen5_pip->irq_cmd_buf, length))) {
2548                        /*
2549                         * Cover the Gen5 V1 firmware issue.
2550                         * The issue is there is no interrut will be
2551                         * asserted to notityf host to read a command
2552                         * data out when always has finger touch on
2553                         * trackpad during the command is issued to
2554                         * trackad device.
2555                         * This issue has the scenario is that,
2556                         * user always has his fingers touched on
2557                         * trackpad device when booting/rebooting
2558                         * their chrome book.
2559                         */
2560                        length = 0;
2561                        if (gen5_pip->resp_len)
2562                                length = *gen5_pip->resp_len;
2563                        cyapa_empty_pip_output_data(cyapa,
2564                                        gen5_pip->resp_data,
2565                                        &length,
2566                                        gen5_pip->resp_sort_func);
2567                        if (gen5_pip->resp_len && length != 0) {
2568                                *gen5_pip->resp_len = length;
2569                                atomic_dec(&gen5_pip->cmd_issued);
2570                                complete(&gen5_pip->cmd_ready);
2571                        }
2572                        return false;
2573                }
2574
2575                if (gen5_pip->resp_data && gen5_pip->resp_len) {
2576                        *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ?
2577                                *gen5_pip->resp_len : length;
2578                        memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf,
2579                                *gen5_pip->resp_len);
2580                }
2581                atomic_dec(&gen5_pip->cmd_issued);
2582                complete(&gen5_pip->cmd_ready);
2583                return false;
2584        }
2585
2586        return true;
2587}
2588
2589static void cyapa_gen5_report_buttons(struct cyapa *cyapa,
2590                const struct cyapa_gen5_report_data *report_data)
2591{
2592        struct input_dev *input = cyapa->input;
2593        u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET];
2594
2595        buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK;
2596
2597        if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) {
2598                input_report_key(input, BTN_LEFT,
2599                        !!(buttons & CAPABILITY_LEFT_BTN_MASK));
2600        }
2601        if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) {
2602                input_report_key(input, BTN_MIDDLE,
2603                        !!(buttons & CAPABILITY_MIDDLE_BTN_MASK));
2604        }
2605        if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) {
2606                input_report_key(input, BTN_RIGHT,
2607                        !!(buttons & CAPABILITY_RIGHT_BTN_MASK));
2608        }
2609
2610        input_sync(input);
2611}
2612
2613static void cyapa_gen5_report_slot_data(struct cyapa *cyapa,
2614                const struct cyapa_gen5_touch_record *touch)
2615{
2616        struct input_dev *input = cyapa->input;
2617        u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id);
2618        int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id);
2619        int x, y;
2620
2621        if (event_id == RECORD_EVENT_LIFTOFF)
2622                return;
2623
2624        input_mt_slot(input, slot);
2625        input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
2626        x = (touch->x_hi << 8) | touch->x_lo;
2627        if (cyapa->x_origin)
2628                x = cyapa->max_abs_x - x;
2629        input_report_abs(input, ABS_MT_POSITION_X, x);
2630        y = (touch->y_hi << 8) | touch->y_lo;
2631        if (cyapa->y_origin)
2632                y = cyapa->max_abs_y - y;
2633        input_report_abs(input, ABS_MT_POSITION_Y, y);
2634        input_report_abs(input, ABS_MT_PRESSURE,
2635                touch->z);
2636        input_report_abs(input, ABS_MT_TOUCH_MAJOR,
2637                touch->major_axis_len);
2638        input_report_abs(input, ABS_MT_TOUCH_MINOR,
2639                touch->minor_axis_len);
2640
2641        input_report_abs(input, ABS_MT_WIDTH_MAJOR,
2642                touch->major_tool_len);
2643        input_report_abs(input, ABS_MT_WIDTH_MINOR,
2644                touch->minor_tool_len);
2645
2646        input_report_abs(input, ABS_MT_ORIENTATION,
2647                touch->orientation);
2648}
2649
2650static void cyapa_gen5_report_touches(struct cyapa *cyapa,
2651                const struct cyapa_gen5_report_data *report_data)
2652{
2653        struct input_dev *input = cyapa->input;
2654        unsigned int touch_num;
2655        int i;
2656
2657        touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] &
2658                        GEN5_NUMBER_OF_TOUCH_MASK;
2659
2660        for (i = 0; i < touch_num; i++)
2661                cyapa_gen5_report_slot_data(cyapa,
2662                        &report_data->touch_records[i]);
2663
2664        input_mt_sync_frame(input);
2665        input_sync(input);
2666}
2667
2668static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
2669{
2670        struct device *dev = &cyapa->client->dev;
2671        struct cyapa_gen5_report_data report_data;
2672        int ret;
2673        u8 report_id;
2674        unsigned int report_len;
2675
2676        if (cyapa->gen != CYAPA_GEN5 ||
2677                cyapa->state != CYAPA_STATE_GEN5_APP) {
2678                dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n",
2679                        cyapa->gen, cyapa->state);
2680                return -EINVAL;
2681        }
2682
2683        ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data,
2684                        GEN5_RESP_LENGTH_SIZE);
2685        if (ret != GEN5_RESP_LENGTH_SIZE) {
2686                dev_err(dev, "failed to read length bytes, (%d)\n", ret);
2687                return -EINVAL;
2688        }
2689
2690        report_len = get_unaligned_le16(
2691                        &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]);
2692        if (report_len < GEN5_RESP_LENGTH_SIZE) {
2693                /* Invliad length or internal reset happened. */
2694                dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n",
2695                        report_len, report_data.report_head[0],
2696                        report_data.report_head[1]);
2697                return -EINVAL;
2698        }
2699
2700        /* Idle, no data for report. */
2701        if (report_len == GEN5_RESP_LENGTH_SIZE)
2702                return 0;
2703
2704        ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len);
2705        if (ret != report_len) {
2706                dev_err(dev, "failed to read %d bytes report data, (%d)\n",
2707                        report_len, ret);
2708                return -EINVAL;
2709        }
2710
2711        report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET];
2712        if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID &&
2713                        report_len == GEN5_WAKEUP_EVENT_SIZE) {
2714                /*
2715                 * Device wake event from deep sleep mode for touch.
2716                 * This interrupt event is used to wake system up.
2717                 */
2718                return 0;
2719        } else if (report_id != GEN5_TOUCH_REPORT_ID &&
2720                        report_id != GEN5_BTN_REPORT_ID &&
2721                        report_id != GEN5_OLD_PUSH_BTN_REPORT_ID &&
2722                        report_id != GEN5_PUSH_BTN_REPORT_ID) {
2723                /* Running in BL mode or unknown response data read. */
2724                dev_err(dev, "invalid report_id=0x%02x\n", report_id);
2725                return -EINVAL;
2726        }
2727
2728        if (report_id == GEN5_TOUCH_REPORT_ID &&
2729                (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE ||
2730                        report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) {
2731                /* Invalid report data length for finger packet. */
2732                dev_err(dev, "invalid touch packet length=%d\n", report_len);
2733                return 0;
2734        }
2735
2736        if ((report_id == GEN5_BTN_REPORT_ID ||
2737                        report_id == GEN5_OLD_PUSH_BTN_REPORT_ID ||
2738                        report_id == GEN5_PUSH_BTN_REPORT_ID) &&
2739                (report_len < GEN5_BTN_REPORT_HEAD_SIZE ||
2740                        report_len > GEN5_BTN_REPORT_MAX_SIZE)) {
2741                /* Invalid report data length of button packet. */
2742                dev_err(dev, "invalid button packet length=%d\n", report_len);
2743                return 0;
2744        }
2745
2746        if (report_id == GEN5_TOUCH_REPORT_ID)
2747                cyapa_gen5_report_touches(cyapa, &report_data);
2748        else
2749                cyapa_gen5_report_buttons(cyapa, &report_data);
2750
2751        return 0;
2752}
2753
2754static int cyapa_gen5_bl_activate(struct cyapa *cyapa) { return 0; }
2755static int cyapa_gen5_bl_deactivate(struct cyapa *cyapa) { return 0; }
2756
2757const struct cyapa_dev_ops cyapa_gen5_ops = {
2758        .check_fw = cyapa_gen5_check_fw,
2759        .bl_enter = cyapa_gen5_bl_enter,
2760        .bl_initiate = cyapa_gen5_bl_initiate,
2761        .update_fw = cyapa_gen5_do_fw_update,
2762        .bl_activate = cyapa_gen5_bl_activate,
2763        .bl_deactivate = cyapa_gen5_bl_deactivate,
2764
2765        .show_baseline = cyapa_gen5_show_baseline,
2766        .calibrate_store = cyapa_gen5_do_calibrate,
2767
2768        .initialize = cyapa_gen5_initialize,
2769
2770        .state_parse = cyapa_gen5_state_parse,
2771        .operational_check = cyapa_gen5_do_operational_check,
2772
2773        .irq_handler = cyapa_gen5_irq_handler,
2774        .irq_cmd_handler = cyapa_gen5_irq_cmd_handler,
2775        .sort_empty_output_data = cyapa_empty_pip_output_data,
2776        .set_power_mode = cyapa_gen5_set_power_mode,
2777};
2778