/*
- Cypress APA trackpad with I2C interface
 - Copyright © 2015 Cypress Semiconductor, Inc.
 - This file is subject to the terms and conditions of the GNU General Public
 - License. See the file COPYING in the main directory of this archive for
 - more details.
*/ 
#include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/mt.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 #include <linux/crc-itu-t.h>
 #include “cyapa.h”
#define GEN6_ENABLE_CMD_IRQ 0x41
 #define GEN6_DISABLE_CMD_IRQ 0x42
 #define GEN6_ENABLE_DEV_IRQ 0x43
 #define GEN6_DISABLE_DEV_IRQ 0x44
#define GEN6_POWER_MODE_ACTIVE 0x01
 #define GEN6_POWER_MODE_LP_MODE1 0x02
 #define GEN6_POWER_MODE_LP_MODE2 0x03
 #define GEN6_POWER_MODE_BTN_ONLY 0x04
#define GEN6_SET_POWER_MODE_INTERVAL 0x47
 #define GEN6_GET_POWER_MODE_INTERVAL 0x48
#define GEN6_MAX_RX_NUM 14
 #define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00
 #define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12
struct pip_app_cmd_head {
 __le16 addr;
 __le16 length;
 u8 report_id;
 u8 resv; /* Reserved, must be 0 /
 u8 cmd_code; / bit7: resv, set to 0; bit6~0: command code.*/
 } __packed;
struct pip_app_resp_head {
 __le16 length;
 u8 report_id;
 u8 resv; /* Reserved, must be 0 /
 u8 cmd_code; / bit7: TGL; bit6~0: command code./
 /
 * The value of data_status can be the first byte of data or
 * the command status or the unsupported command code depending on the
 * requested command code.
 */
 u8 data_status;
 } __packed;
struct pip_fixed_info {
 u8 silicon_id_high;
 u8 silicon_id_low;
 u8 family_id;
 };
static u8 pip_get_bl_info[] = {
 0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38,
 0x00, 0x00, 0x70, 0x9E, 0x17
 };
static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa,
 u8 *buf, int len)
 {
 if (len != PIP_HID_DESCRIPTOR_SIZE)
 return false;
if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID ||buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID)return true;return false;
 
}
static int cyapa_get_pip_fixed_info(struct cyapa *cyapa,
 struct pip_fixed_info *pip_info, bool is_bootloader)
 {
 u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH];
 int resp_len;
 u16 product_family;
 int error;
if (is_bootloader) {/* Read Bootloader Information to determine Gen5 or Gen6. */resp_len = sizeof(resp_data);error = cyapa_i2c_pip_cmd_irq_sync(cyapa,pip_get_bl_info, sizeof(pip_get_bl_info),resp_data, &resp_len,2000, cyapa_sort_tsg_pip_bl_resp_data,false);if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH)return error ? error : -EIO;pip_info->family_id = resp_data[8];pip_info->silicon_id_low = resp_data[10];pip_info->silicon_id_high = resp_data[11];return 0;
}/* Get App System Information to determine Gen5 or Gen6. */
resp_len = sizeof(resp_data);
error = cyapa_i2c_pip_cmd_irq_sync(cyapa,pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH,resp_data, &resp_len,2000, cyapa_pip_sort_system_info_data, false);
if (error || resp_len < PIP_READ_SYS_INFO_RESP_LENGTH)return error ? error : -EIO;product_family = get_unaligned_le16(&resp_data[7]);
if ((product_family & PIP_PRODUCT_FAMILY_MASK) !=PIP_PRODUCT_FAMILY_TRACKPAD)return -EINVAL;pip_info->family_id = resp_data[19];
pip_info->silicon_id_low = resp_data[21];
pip_info->silicon_id_high = resp_data[22];return 0;
 
}
int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
 {
 u8 cmd[] = { 0x01, 0x00};
 struct pip_fixed_info pip_info;
 u8 resp_data[PIP_HID_DESCRIPTOR_SIZE];
 int resp_len;
 bool is_bootloader;
 int error;
cyapa->state = CYAPA_STATE_NO_DEVICE;/* Try to wake from it deep sleep state if it is. */
cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);/* Empty the buffer queue to get fresh data with later commands. */
cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);/** Read description info from trackpad device to determine running in* APP mode or Boo