1c2c06c41SDudley Du /* 2c2c06c41SDudley Du * Cypress APA trackpad with I2C interface 3c2c06c41SDudley Du * 4c2c06c41SDudley Du * Author: Dudley Du <dudl@cypress.com> 5c2c06c41SDudley Du * 6c2c06c41SDudley Du * Copyright (C) 2015 Cypress Semiconductor, Inc. 7c2c06c41SDudley Du * 8c2c06c41SDudley Du * This file is subject to the terms and conditions of the GNU General Public 9c2c06c41SDudley Du * License. See the file COPYING in the main directory of this archive for 10c2c06c41SDudley Du * more details. 11c2c06c41SDudley Du */ 12c2c06c41SDudley Du 13c2c06c41SDudley Du #include <linux/delay.h> 14c2c06c41SDudley Du #include <linux/i2c.h> 15c2c06c41SDudley Du #include <linux/input.h> 16c2c06c41SDudley Du #include <linux/input/mt.h> 17c2c06c41SDudley Du #include <linux/mutex.h> 18c2c06c41SDudley Du #include <linux/completion.h> 19c2c06c41SDudley Du #include <linux/slab.h> 20c2c06c41SDudley Du #include <asm/unaligned.h> 21c2c06c41SDudley Du #include <linux/crc-itu-t.h> 22c2c06c41SDudley Du #include "cyapa.h" 23c2c06c41SDudley Du 24c2c06c41SDudley Du 25c2c06c41SDudley Du #define GEN6_ENABLE_CMD_IRQ 0x41 26c2c06c41SDudley Du #define GEN6_DISABLE_CMD_IRQ 0x42 27c2c06c41SDudley Du #define GEN6_ENABLE_DEV_IRQ 0x43 28c2c06c41SDudley Du #define GEN6_DISABLE_DEV_IRQ 0x44 29c2c06c41SDudley Du 30c2c06c41SDudley Du #define GEN6_POWER_MODE_ACTIVE 0x01 31c2c06c41SDudley Du #define GEN6_POWER_MODE_LP_MODE1 0x02 32c2c06c41SDudley Du #define GEN6_POWER_MODE_LP_MODE2 0x03 33c2c06c41SDudley Du #define GEN6_POWER_MODE_BTN_ONLY 0x04 34c2c06c41SDudley Du 35c2c06c41SDudley Du #define GEN6_SET_POWER_MODE_INTERVAL 0x47 36c2c06c41SDudley Du #define GEN6_GET_POWER_MODE_INTERVAL 0x48 37c2c06c41SDudley Du 38c2c06c41SDudley Du #define GEN6_MAX_RX_NUM 14 39c2c06c41SDudley Du #define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00 40c2c06c41SDudley Du #define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12 41c2c06c41SDudley Du 42c2c06c41SDudley Du 43c2c06c41SDudley Du struct pip_app_cmd_head { 44c2c06c41SDudley Du __le16 addr; 45c2c06c41SDudley Du __le16 length; 46c2c06c41SDudley Du u8 report_id; 47c2c06c41SDudley Du u8 resv; /* Reserved, must be 0 */ 48c2c06c41SDudley Du u8 cmd_code; /* bit7: resv, set to 0; bit6~0: command code.*/ 49c2c06c41SDudley Du } __packed; 50c2c06c41SDudley Du 51c2c06c41SDudley Du struct pip_app_resp_head { 52c2c06c41SDudley Du __le16 length; 53c2c06c41SDudley Du u8 report_id; 54c2c06c41SDudley Du u8 resv; /* Reserved, must be 0 */ 55c2c06c41SDudley Du u8 cmd_code; /* bit7: TGL; bit6~0: command code.*/ 56c2c06c41SDudley Du /* 57c2c06c41SDudley Du * The value of data_status can be the first byte of data or 58c2c06c41SDudley Du * the command status or the unsupported command code depending on the 59c2c06c41SDudley Du * requested command code. 60c2c06c41SDudley Du */ 61c2c06c41SDudley Du u8 data_status; 62c2c06c41SDudley Du } __packed; 63c2c06c41SDudley Du 64c2c06c41SDudley Du struct pip_fixed_info { 65c2c06c41SDudley Du u8 silicon_id_high; 66c2c06c41SDudley Du u8 silicon_id_low; 67c2c06c41SDudley Du u8 family_id; 68c2c06c41SDudley Du }; 69c2c06c41SDudley Du 70c2c06c41SDudley Du static u8 pip_get_bl_info[] = { 71c2c06c41SDudley Du 0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38, 72c2c06c41SDudley Du 0x00, 0x00, 0x70, 0x9E, 0x17 73c2c06c41SDudley Du }; 74c2c06c41SDudley Du 75c2c06c41SDudley Du static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa, 76c2c06c41SDudley Du u8 *buf, int len) 77c2c06c41SDudley Du { 78c2c06c41SDudley Du if (len != PIP_HID_DESCRIPTOR_SIZE) 79c2c06c41SDudley Du return false; 80c2c06c41SDudley Du 81c2c06c41SDudley Du if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID || 82c2c06c41SDudley Du buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID) 83c2c06c41SDudley Du return true; 84c2c06c41SDudley Du 85c2c06c41SDudley Du return false; 86c2c06c41SDudley Du } 87c2c06c41SDudley Du 88c2c06c41SDudley Du static int cyapa_get_pip_fixed_info(struct cyapa *cyapa, 89c2c06c41SDudley Du struct pip_fixed_info *pip_info, bool is_bootloader) 90c2c06c41SDudley Du { 91c2c06c41SDudley Du u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; 92c2c06c41SDudley Du int resp_len; 93c2c06c41SDudley Du u16 product_family; 94c2c06c41SDudley Du int error; 95c2c06c41SDudley Du 96c2c06c41SDudley Du if (is_bootloader) { 97c2c06c41SDudley Du /* Read Bootloader Information to determine Gen5 or Gen6. */ 98c2c06c41SDudley Du resp_len = sizeof(resp_data); 99c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 100c2c06c41SDudley Du pip_get_bl_info, sizeof(pip_get_bl_info), 101c2c06c41SDudley Du resp_data, &resp_len, 102c2c06c41SDudley Du 2000, cyapa_sort_tsg_pip_bl_resp_data, 103c2c06c41SDudley Du false); 104c2c06c41SDudley Du if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH) 105c2c06c41SDudley Du return error ? error : -EIO; 106c2c06c41SDudley Du 107c2c06c41SDudley Du pip_info->family_id = resp_data[8]; 108c2c06c41SDudley Du pip_info->silicon_id_low = resp_data[10]; 109c2c06c41SDudley Du pip_info->silicon_id_high = resp_data[11]; 110c2c06c41SDudley Du 111c2c06c41SDudley Du return 0; 112c2c06c41SDudley Du } 113c2c06c41SDudley Du 114c2c06c41SDudley Du /* Get App System Information to determine Gen5 or Gen6. */ 115c2c06c41SDudley Du resp_len = sizeof(resp_data); 116c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 117c2c06c41SDudley Du pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, 118c2c06c41SDudley Du resp_data, &resp_len, 119c2c06c41SDudley Du 2000, cyapa_pip_sort_system_info_data, false); 120c2c06c41SDudley Du if (error || resp_len < PIP_READ_SYS_INFO_RESP_LENGTH) 121c2c06c41SDudley Du return error ? error : -EIO; 122c2c06c41SDudley Du 123c2c06c41SDudley Du product_family = get_unaligned_le16(&resp_data[7]); 124c2c06c41SDudley Du if ((product_family & PIP_PRODUCT_FAMILY_MASK) != 125c2c06c41SDudley Du PIP_PRODUCT_FAMILY_TRACKPAD) 126c2c06c41SDudley Du return -EINVAL; 127c2c06c41SDudley Du 128c2c06c41SDudley Du pip_info->family_id = resp_data[19]; 129c2c06c41SDudley Du pip_info->silicon_id_low = resp_data[21]; 130c2c06c41SDudley Du pip_info->silicon_id_high = resp_data[22]; 131c2c06c41SDudley Du 132c2c06c41SDudley Du return 0; 133c2c06c41SDudley Du 134c2c06c41SDudley Du } 135c2c06c41SDudley Du 136c2c06c41SDudley Du int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) 137c2c06c41SDudley Du { 138c2c06c41SDudley Du u8 cmd[] = { 0x01, 0x00}; 139c2c06c41SDudley Du struct pip_fixed_info pip_info; 140c2c06c41SDudley Du u8 resp_data[PIP_HID_DESCRIPTOR_SIZE]; 141c2c06c41SDudley Du int resp_len; 142c2c06c41SDudley Du bool is_bootloader; 143c2c06c41SDudley Du int error; 144c2c06c41SDudley Du 145c2c06c41SDudley Du cyapa->state = CYAPA_STATE_NO_DEVICE; 146c2c06c41SDudley Du 147c2c06c41SDudley Du /* Try to wake from it deep sleep state if it is. */ 148c2c06c41SDudley Du cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); 149c2c06c41SDudley Du 150c2c06c41SDudley Du /* Empty the buffer queue to get fresh data with later commands. */ 151c2c06c41SDudley Du cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); 152c2c06c41SDudley Du 153c2c06c41SDudley Du /* 154c2c06c41SDudley Du * Read description info from trackpad device to determine running in 155c2c06c41SDudley Du * APP mode or Bootloader mode. 156c2c06c41SDudley Du */ 157c2c06c41SDudley Du resp_len = PIP_HID_DESCRIPTOR_SIZE; 158c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 159c2c06c41SDudley Du cmd, sizeof(cmd), 160c2c06c41SDudley Du resp_data, &resp_len, 161c2c06c41SDudley Du 300, 162c2c06c41SDudley Du cyapa_sort_pip_hid_descriptor_data, 163c2c06c41SDudley Du false); 164c2c06c41SDudley Du if (error) 165c2c06c41SDudley Du return error; 166c2c06c41SDudley Du 167c2c06c41SDudley Du if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID) 168c2c06c41SDudley Du is_bootloader = true; 169c2c06c41SDudley Du else if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID) 170c2c06c41SDudley Du is_bootloader = false; 171c2c06c41SDudley Du else 172c2c06c41SDudley Du return -EAGAIN; 173c2c06c41SDudley Du 174c2c06c41SDudley Du /* Get PIP fixed information to determine Gen5 or Gen6. */ 175c2c06c41SDudley Du memset(&pip_info, 0, sizeof(struct pip_fixed_info)); 176c2c06c41SDudley Du error = cyapa_get_pip_fixed_info(cyapa, &pip_info, is_bootloader); 177c2c06c41SDudley Du if (error) 178c2c06c41SDudley Du return error; 179c2c06c41SDudley Du 180c2c06c41SDudley Du if (pip_info.family_id == 0x9B && pip_info.silicon_id_high == 0x0B) { 181c2c06c41SDudley Du cyapa->gen = CYAPA_GEN6; 182c2c06c41SDudley Du cyapa->state = is_bootloader ? CYAPA_STATE_GEN6_BL 183c2c06c41SDudley Du : CYAPA_STATE_GEN6_APP; 184c2c06c41SDudley Du } else if (pip_info.family_id == 0x91 && 185c2c06c41SDudley Du pip_info.silicon_id_high == 0x02) { 186c2c06c41SDudley Du cyapa->gen = CYAPA_GEN5; 187c2c06c41SDudley Du cyapa->state = is_bootloader ? CYAPA_STATE_GEN5_BL 188c2c06c41SDudley Du : CYAPA_STATE_GEN5_APP; 189c2c06c41SDudley Du } 190c2c06c41SDudley Du 191c2c06c41SDudley Du return 0; 192c2c06c41SDudley Du } 193c2c06c41SDudley Du 194c2c06c41SDudley Du static int cyapa_gen6_read_sys_info(struct cyapa *cyapa) 195c2c06c41SDudley Du { 196c2c06c41SDudley Du u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; 197c2c06c41SDudley Du int resp_len; 198c2c06c41SDudley Du u16 product_family; 199c2c06c41SDudley Du u8 rotat_align; 200c2c06c41SDudley Du int error; 201c2c06c41SDudley Du 202c2c06c41SDudley Du /* Get App System Information to determine Gen5 or Gen6. */ 203c2c06c41SDudley Du resp_len = sizeof(resp_data); 204c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 205c2c06c41SDudley Du pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, 206c2c06c41SDudley Du resp_data, &resp_len, 207c2c06c41SDudley Du 2000, cyapa_pip_sort_system_info_data, false); 208c2c06c41SDudley Du if (error || resp_len < sizeof(resp_data)) 209c2c06c41SDudley Du return error ? error : -EIO; 210c2c06c41SDudley Du 211c2c06c41SDudley Du product_family = get_unaligned_le16(&resp_data[7]); 212c2c06c41SDudley Du if ((product_family & PIP_PRODUCT_FAMILY_MASK) != 213c2c06c41SDudley Du PIP_PRODUCT_FAMILY_TRACKPAD) 214c2c06c41SDudley Du return -EINVAL; 215c2c06c41SDudley Du 216c2c06c41SDudley Du cyapa->platform_ver = (resp_data[67] >> PIP_BL_PLATFORM_VER_SHIFT) & 217c2c06c41SDudley Du PIP_BL_PLATFORM_VER_MASK; 218c2c06c41SDudley Du cyapa->fw_maj_ver = resp_data[9]; 219c2c06c41SDudley Du cyapa->fw_min_ver = resp_data[10]; 220c2c06c41SDudley Du 221c2c06c41SDudley Du cyapa->electrodes_x = resp_data[33]; 222c2c06c41SDudley Du cyapa->electrodes_y = resp_data[34]; 223c2c06c41SDudley Du 224c2c06c41SDudley Du cyapa->physical_size_x = get_unaligned_le16(&resp_data[35]) / 100; 225c2c06c41SDudley Du cyapa->physical_size_y = get_unaligned_le16(&resp_data[37]) / 100; 226c2c06c41SDudley Du 227c2c06c41SDudley Du cyapa->max_abs_x = get_unaligned_le16(&resp_data[39]); 228c2c06c41SDudley Du cyapa->max_abs_y = get_unaligned_le16(&resp_data[41]); 229c2c06c41SDudley Du 230c2c06c41SDudley Du cyapa->max_z = get_unaligned_le16(&resp_data[43]); 231c2c06c41SDudley Du 232c2c06c41SDudley Du cyapa->x_origin = resp_data[45] & 0x01; 233c2c06c41SDudley Du cyapa->y_origin = resp_data[46] & 0x01; 234c2c06c41SDudley Du 235c2c06c41SDudley Du cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK; 236c2c06c41SDudley Du 237c2c06c41SDudley Du memcpy(&cyapa->product_id[0], &resp_data[51], 5); 238c2c06c41SDudley Du cyapa->product_id[5] = '-'; 239c2c06c41SDudley Du memcpy(&cyapa->product_id[6], &resp_data[56], 6); 240c2c06c41SDudley Du cyapa->product_id[12] = '-'; 241c2c06c41SDudley Du memcpy(&cyapa->product_id[13], &resp_data[62], 2); 242c2c06c41SDudley Du cyapa->product_id[15] = '\0'; 243c2c06c41SDudley Du 244a487c03fSDudley Du /* Get the number of Rx electrodes. */ 245c2c06c41SDudley Du rotat_align = resp_data[68]; 246a487c03fSDudley Du cyapa->electrodes_rx = 247a487c03fSDudley Du rotat_align ? cyapa->electrodes_y : cyapa->electrodes_x; 248c2c06c41SDudley Du cyapa->aligned_electrodes_rx = (cyapa->electrodes_rx + 3) & ~3u; 249c2c06c41SDudley Du 250c2c06c41SDudley Du if (!cyapa->electrodes_x || !cyapa->electrodes_y || 251c2c06c41SDudley Du !cyapa->physical_size_x || !cyapa->physical_size_y || 252c2c06c41SDudley Du !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z) 253c2c06c41SDudley Du return -EINVAL; 254c2c06c41SDudley Du 255c2c06c41SDudley Du return 0; 256c2c06c41SDudley Du } 257c2c06c41SDudley Du 258c2c06c41SDudley Du static int cyapa_gen6_bl_read_app_info(struct cyapa *cyapa) 259c2c06c41SDudley Du { 260c2c06c41SDudley Du u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH]; 261c2c06c41SDudley Du int resp_len; 262c2c06c41SDudley Du int error; 263c2c06c41SDudley Du 264c2c06c41SDudley Du resp_len = sizeof(resp_data); 265c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 266c2c06c41SDudley Du pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH, 267c2c06c41SDudley Du resp_data, &resp_len, 268c2c06c41SDudley Du 500, cyapa_sort_tsg_pip_bl_resp_data, false); 269c2c06c41SDudley Du if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH || 270c2c06c41SDudley Du !PIP_CMD_COMPLETE_SUCCESS(resp_data)) 271c2c06c41SDudley Du return error ? error : -EIO; 272c2c06c41SDudley Du 273c2c06c41SDudley Du cyapa->fw_maj_ver = resp_data[8]; 274c2c06c41SDudley Du cyapa->fw_min_ver = resp_data[9]; 275c2c06c41SDudley Du 276c2c06c41SDudley Du cyapa->platform_ver = (resp_data[12] >> PIP_BL_PLATFORM_VER_SHIFT) & 277c2c06c41SDudley Du PIP_BL_PLATFORM_VER_MASK; 278c2c06c41SDudley Du 279c2c06c41SDudley Du memcpy(&cyapa->product_id[0], &resp_data[13], 5); 280c2c06c41SDudley Du cyapa->product_id[5] = '-'; 281c2c06c41SDudley Du memcpy(&cyapa->product_id[6], &resp_data[18], 6); 282c2c06c41SDudley Du cyapa->product_id[12] = '-'; 283c2c06c41SDudley Du memcpy(&cyapa->product_id[13], &resp_data[24], 2); 284c2c06c41SDudley Du cyapa->product_id[15] = '\0'; 285c2c06c41SDudley Du 286c2c06c41SDudley Du return 0; 287c2c06c41SDudley Du 288c2c06c41SDudley Du } 289c2c06c41SDudley Du 290c2c06c41SDudley Du static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code) 291c2c06c41SDudley Du { 292c2c06c41SDudley Du u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, cmd_code }; 293c2c06c41SDudley Du u8 resp_data[6]; 294c2c06c41SDudley Du int resp_len; 295c2c06c41SDudley Du int error; 296c2c06c41SDudley Du 297c2c06c41SDudley Du resp_len = sizeof(resp_data); 298c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), 299c2c06c41SDudley Du resp_data, &resp_len, 300c2c06c41SDudley Du 500, cyapa_sort_tsg_pip_app_resp_data, false); 301c2c06c41SDudley Du if (error || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || 302c2c06c41SDudley Du !PIP_CMD_COMPLETE_SUCCESS(resp_data) 303c2c06c41SDudley Du ) 304c2c06c41SDudley Du return error < 0 ? error : -EINVAL; 305c2c06c41SDudley Du 306c2c06c41SDudley Du return 0; 307c2c06c41SDudley Du } 308c2c06c41SDudley Du 309945525eeSDudley Du static int cyapa_gen6_set_proximity(struct cyapa *cyapa, bool enable) 310945525eeSDudley Du { 311945525eeSDudley Du int error; 312945525eeSDudley Du 313945525eeSDudley Du cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); 314945525eeSDudley Du error = cyapa_pip_set_proximity(cyapa, enable); 315945525eeSDudley Du cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ); 316945525eeSDudley Du 317945525eeSDudley Du return error; 318945525eeSDudley Du } 319945525eeSDudley Du 320c2c06c41SDudley Du static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode) 321c2c06c41SDudley Du { 322c2c06c41SDudley Du u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode }; 323c2c06c41SDudley Du u8 resp_data[6]; 324c2c06c41SDudley Du int resp_len; 325c2c06c41SDudley Du int error; 326c2c06c41SDudley Du 327c2c06c41SDudley Du resp_len = sizeof(resp_data); 328c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), 329c2c06c41SDudley Du resp_data, &resp_len, 330c2c06c41SDudley Du 500, cyapa_sort_tsg_pip_app_resp_data, false); 331c2c06c41SDudley Du if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x46)) 332c2c06c41SDudley Du return error < 0 ? error : -EINVAL; 333c2c06c41SDudley Du 334c2c06c41SDudley Du /* New power state applied in device not match the set power state. */ 335c2c06c41SDudley Du if (resp_data[5] != power_mode) 336c2c06c41SDudley Du return -EAGAIN; 337c2c06c41SDudley Du 338c2c06c41SDudley Du return 0; 339c2c06c41SDudley Du } 340c2c06c41SDudley Du 341c2c06c41SDudley Du static int cyapa_gen6_set_interval_setting(struct cyapa *cyapa, 342c2c06c41SDudley Du struct gen6_interval_setting *interval_setting) 343c2c06c41SDudley Du { 344c2c06c41SDudley Du struct gen6_set_interval_cmd { 345c2c06c41SDudley Du __le16 addr; 346c2c06c41SDudley Du __le16 length; 347c2c06c41SDudley Du u8 report_id; 348c2c06c41SDudley Du u8 rsvd; /* Reserved, must be 0 */ 349c2c06c41SDudley Du u8 cmd_code; 350c2c06c41SDudley Du __le16 active_interval; 351c2c06c41SDudley Du __le16 lp1_interval; 352c2c06c41SDudley Du __le16 lp2_interval; 353c2c06c41SDudley Du } __packed set_interval_cmd; 354c2c06c41SDudley Du u8 resp_data[11]; 355c2c06c41SDudley Du int resp_len; 356c2c06c41SDudley Du int error; 357c2c06c41SDudley Du 358c2c06c41SDudley Du memset(&set_interval_cmd, 0, sizeof(set_interval_cmd)); 359c2c06c41SDudley Du put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &set_interval_cmd.addr); 360c2c06c41SDudley Du put_unaligned_le16(sizeof(set_interval_cmd) - 2, 361c2c06c41SDudley Du &set_interval_cmd.length); 362c2c06c41SDudley Du set_interval_cmd.report_id = PIP_APP_CMD_REPORT_ID; 363c2c06c41SDudley Du set_interval_cmd.cmd_code = GEN6_SET_POWER_MODE_INTERVAL; 364c2c06c41SDudley Du put_unaligned_le16(interval_setting->active_interval, 365c2c06c41SDudley Du &set_interval_cmd.active_interval); 366c2c06c41SDudley Du put_unaligned_le16(interval_setting->lp1_interval, 367c2c06c41SDudley Du &set_interval_cmd.lp1_interval); 368c2c06c41SDudley Du put_unaligned_le16(interval_setting->lp2_interval, 369c2c06c41SDudley Du &set_interval_cmd.lp2_interval); 370c2c06c41SDudley Du 371c2c06c41SDudley Du resp_len = sizeof(resp_data); 372c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 373c2c06c41SDudley Du (u8 *)&set_interval_cmd, sizeof(set_interval_cmd), 374c2c06c41SDudley Du resp_data, &resp_len, 375c2c06c41SDudley Du 500, cyapa_sort_tsg_pip_app_resp_data, false); 376c2c06c41SDudley Du if (error || 377c2c06c41SDudley Du !VALID_CMD_RESP_HEADER(resp_data, GEN6_SET_POWER_MODE_INTERVAL)) 378c2c06c41SDudley Du return error < 0 ? error : -EINVAL; 379c2c06c41SDudley Du 380c2c06c41SDudley Du /* Get the real set intervals from response. */ 381c2c06c41SDudley Du interval_setting->active_interval = get_unaligned_le16(&resp_data[5]); 382c2c06c41SDudley Du interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]); 383c2c06c41SDudley Du interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]); 384c2c06c41SDudley Du 385c2c06c41SDudley Du return 0; 386c2c06c41SDudley Du } 387c2c06c41SDudley Du 388c2c06c41SDudley Du static int cyapa_gen6_get_interval_setting(struct cyapa *cyapa, 389c2c06c41SDudley Du struct gen6_interval_setting *interval_setting) 390c2c06c41SDudley Du { 391c2c06c41SDudley Du u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 392c2c06c41SDudley Du GEN6_GET_POWER_MODE_INTERVAL }; 393c2c06c41SDudley Du u8 resp_data[11]; 394c2c06c41SDudley Du int resp_len; 395c2c06c41SDudley Du int error; 396c2c06c41SDudley Du 397c2c06c41SDudley Du resp_len = sizeof(resp_data); 398c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), 399c2c06c41SDudley Du resp_data, &resp_len, 400c2c06c41SDudley Du 500, cyapa_sort_tsg_pip_app_resp_data, false); 401c2c06c41SDudley Du if (error || 402c2c06c41SDudley Du !VALID_CMD_RESP_HEADER(resp_data, GEN6_GET_POWER_MODE_INTERVAL)) 403c2c06c41SDudley Du return error < 0 ? error : -EINVAL; 404c2c06c41SDudley Du 405c2c06c41SDudley Du interval_setting->active_interval = get_unaligned_le16(&resp_data[5]); 406c2c06c41SDudley Du interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]); 407c2c06c41SDudley Du interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]); 408c2c06c41SDudley Du 409c2c06c41SDudley Du return 0; 410c2c06c41SDudley Du } 411c2c06c41SDudley Du 412c2c06c41SDudley Du static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state) 413c2c06c41SDudley Du { 414c2c06c41SDudley Du u8 ping[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00 }; 415c2c06c41SDudley Du 416c2c06c41SDudley Du if (state == PIP_DEEP_SLEEP_STATE_ON) 417c2c06c41SDudley Du /* 418c2c06c41SDudley Du * Send ping command to notify device prepare for wake up 419c2c06c41SDudley Du * when it's in deep sleep mode. At this time, device will 420c2c06c41SDudley Du * response nothing except an I2C NAK. 421c2c06c41SDudley Du */ 422c2c06c41SDudley Du cyapa_i2c_pip_write(cyapa, ping, sizeof(ping)); 423c2c06c41SDudley Du 424c2c06c41SDudley Du return cyapa_pip_deep_sleep(cyapa, state); 425c2c06c41SDudley Du } 426c2c06c41SDudley Du 427c2c06c41SDudley Du static int cyapa_gen6_set_power_mode(struct cyapa *cyapa, 428*3cd47869SDudley Du u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage) 429c2c06c41SDudley Du { 430c2c06c41SDudley Du struct device *dev = &cyapa->client->dev; 431c2c06c41SDudley Du struct gen6_interval_setting *interval_setting = 432c2c06c41SDudley Du &cyapa->gen6_interval_setting; 433c2c06c41SDudley Du u8 lp_mode; 434c2c06c41SDudley Du int error; 435c2c06c41SDudley Du 436c2c06c41SDudley Du if (cyapa->state != CYAPA_STATE_GEN6_APP) 437c2c06c41SDudley Du return 0; 438c2c06c41SDudley Du 439c2c06c41SDudley Du if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { 440c2c06c41SDudley Du /* 441c2c06c41SDudley Du * Assume TP in deep sleep mode when driver is loaded, 442c2c06c41SDudley Du * avoid driver unload and reload command IO issue caused by TP 443c2c06c41SDudley Du * has been set into deep sleep mode when unloading. 444c2c06c41SDudley Du */ 445c2c06c41SDudley Du PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); 446c2c06c41SDudley Du } 447c2c06c41SDudley Du 448c2c06c41SDudley Du if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) && 449c2c06c41SDudley Du PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) 450c2c06c41SDudley Du PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); 451c2c06c41SDudley Du 452c2c06c41SDudley Du if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) { 453c2c06c41SDudley Du if (power_mode == PWR_MODE_OFF || 454c2c06c41SDudley Du power_mode == PWR_MODE_FULL_ACTIVE || 455c2c06c41SDudley Du power_mode == PWR_MODE_BTN_ONLY || 456c2c06c41SDudley Du PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { 457c2c06c41SDudley Du /* Has in correct power mode state, early return. */ 458c2c06c41SDudley Du return 0; 459c2c06c41SDudley Du } 460c2c06c41SDudley Du } 461c2c06c41SDudley Du 462c2c06c41SDudley Du if (power_mode == PWR_MODE_OFF) { 463c2c06c41SDudley Du cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); 464c2c06c41SDudley Du 465c2c06c41SDudley Du error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF); 466c2c06c41SDudley Du if (error) { 467c2c06c41SDudley Du dev_err(dev, "enter deep sleep fail: %d\n", error); 468c2c06c41SDudley Du return error; 469c2c06c41SDudley Du } 470c2c06c41SDudley Du 471c2c06c41SDudley Du PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); 472c2c06c41SDudley Du return 0; 473c2c06c41SDudley Du } 474c2c06c41SDudley Du 475c2c06c41SDudley Du /* 476c2c06c41SDudley Du * When trackpad in power off mode, it cannot change to other power 477c2c06c41SDudley Du * state directly, must be wake up from sleep firstly, then 478c2c06c41SDudley Du * continue to do next power sate change. 479c2c06c41SDudley Du */ 480c2c06c41SDudley Du if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { 481c2c06c41SDudley Du error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); 482c2c06c41SDudley Du if (error) { 483c2c06c41SDudley Du dev_err(dev, "deep sleep wake fail: %d\n", error); 484c2c06c41SDudley Du return error; 485c2c06c41SDudley Du } 486c2c06c41SDudley Du } 487c2c06c41SDudley Du 488c2c06c41SDudley Du /* 489c2c06c41SDudley Du * Disable device assert interrupts for command response to avoid 490c2c06c41SDudley Du * disturbing system suspending or hibernating process. 491c2c06c41SDudley Du */ 492c2c06c41SDudley Du cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); 493c2c06c41SDudley Du 494c2c06c41SDudley Du if (power_mode == PWR_MODE_FULL_ACTIVE) { 495c2c06c41SDudley Du error = cyapa_gen6_change_power_state(cyapa, 496c2c06c41SDudley Du GEN6_POWER_MODE_ACTIVE); 497c2c06c41SDudley Du if (error) { 498c2c06c41SDudley Du dev_err(dev, "change to active fail: %d\n", error); 499c2c06c41SDudley Du goto out; 500c2c06c41SDudley Du } 501c2c06c41SDudley Du 502c2c06c41SDudley Du PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); 503c2c06c41SDudley Du 504c2c06c41SDudley Du /* Sync the interval setting from device. */ 505c2c06c41SDudley Du cyapa_gen6_get_interval_setting(cyapa, interval_setting); 506c2c06c41SDudley Du 507c2c06c41SDudley Du } else if (power_mode == PWR_MODE_BTN_ONLY) { 508c2c06c41SDudley Du error = cyapa_gen6_change_power_state(cyapa, 509c2c06c41SDudley Du GEN6_POWER_MODE_BTN_ONLY); 510c2c06c41SDudley Du if (error) { 511c2c06c41SDudley Du dev_err(dev, "fail to button only mode: %d\n", error); 512c2c06c41SDudley Du goto out; 513c2c06c41SDudley Du } 514c2c06c41SDudley Du 515c2c06c41SDudley Du PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); 516c2c06c41SDudley Du } else { 517c2c06c41SDudley Du /* 518c2c06c41SDudley Du * Gen6 internally supports to 2 low power scan interval time, 519c2c06c41SDudley Du * so can help to switch power mode quickly. 520c2c06c41SDudley Du * such as runtime suspend and system suspend. 521c2c06c41SDudley Du */ 522c2c06c41SDudley Du if (interval_setting->lp1_interval == sleep_time) { 523c2c06c41SDudley Du lp_mode = GEN6_POWER_MODE_LP_MODE1; 524c2c06c41SDudley Du } else if (interval_setting->lp2_interval == sleep_time) { 525c2c06c41SDudley Du lp_mode = GEN6_POWER_MODE_LP_MODE2; 526c2c06c41SDudley Du } else { 527c2c06c41SDudley Du if (interval_setting->lp1_interval == 0) { 528c2c06c41SDudley Du interval_setting->lp1_interval = sleep_time; 529c2c06c41SDudley Du lp_mode = GEN6_POWER_MODE_LP_MODE1; 530c2c06c41SDudley Du } else { 531c2c06c41SDudley Du interval_setting->lp2_interval = sleep_time; 532c2c06c41SDudley Du lp_mode = GEN6_POWER_MODE_LP_MODE2; 533c2c06c41SDudley Du } 534c2c06c41SDudley Du cyapa_gen6_set_interval_setting(cyapa, 535c2c06c41SDudley Du interval_setting); 536c2c06c41SDudley Du } 537c2c06c41SDudley Du 538c2c06c41SDudley Du error = cyapa_gen6_change_power_state(cyapa, lp_mode); 539c2c06c41SDudley Du if (error) { 540c2c06c41SDudley Du dev_err(dev, "set power state to 0x%02x failed: %d\n", 541c2c06c41SDudley Du lp_mode, error); 542c2c06c41SDudley Du goto out; 543c2c06c41SDudley Du } 544c2c06c41SDudley Du 545c2c06c41SDudley Du PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time); 546c2c06c41SDudley Du PIP_DEV_SET_PWR_STATE(cyapa, 547c2c06c41SDudley Du cyapa_sleep_time_to_pwr_cmd(sleep_time)); 548c2c06c41SDudley Du } 549c2c06c41SDudley Du 550c2c06c41SDudley Du out: 551c2c06c41SDudley Du cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ); 552c2c06c41SDudley Du return error; 553c2c06c41SDudley Du } 554c2c06c41SDudley Du 555c2c06c41SDudley Du static int cyapa_gen6_initialize(struct cyapa *cyapa) 556c2c06c41SDudley Du { 557c2c06c41SDudley Du return 0; 558c2c06c41SDudley Du } 559c2c06c41SDudley Du 560c2c06c41SDudley Du static int cyapa_pip_retrieve_data_structure(struct cyapa *cyapa, 561c2c06c41SDudley Du u16 read_offset, u16 read_len, u8 data_id, 562c2c06c41SDudley Du u8 *data, int *data_buf_lens) 563c2c06c41SDudley Du { 564c2c06c41SDudley Du struct retrieve_data_struct_cmd { 565c2c06c41SDudley Du struct pip_app_cmd_head head; 566c2c06c41SDudley Du __le16 read_offset; 567c2c06c41SDudley Du __le16 read_length; 568c2c06c41SDudley Du u8 data_id; 569c2c06c41SDudley Du } __packed cmd; 570c2c06c41SDudley Du u8 resp_data[GEN6_MAX_RX_NUM + 10]; 571c2c06c41SDudley Du int resp_len; 572c2c06c41SDudley Du int error; 573c2c06c41SDudley Du 574c2c06c41SDudley Du memset(&cmd, 0, sizeof(cmd)); 575c2c06c41SDudley Du put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr); 576c2c06c41SDudley Du put_unaligned_le16(sizeof(cmd), &cmd.head.length - 2); 577c2c06c41SDudley Du cmd.head.report_id = PIP_APP_CMD_REPORT_ID; 578c2c06c41SDudley Du cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE; 579c2c06c41SDudley Du put_unaligned_le16(read_offset, &cmd.read_offset); 580c2c06c41SDudley Du put_unaligned_le16(read_len, &cmd.read_length); 581c2c06c41SDudley Du cmd.data_id = data_id; 582c2c06c41SDudley Du 583c2c06c41SDudley Du resp_len = sizeof(resp_data); 584c2c06c41SDudley Du error = cyapa_i2c_pip_cmd_irq_sync(cyapa, 585c2c06c41SDudley Du (u8 *)&cmd, sizeof(cmd), 586c2c06c41SDudley Du resp_data, &resp_len, 587c2c06c41SDudley Du 500, cyapa_sort_tsg_pip_app_resp_data, 588c2c06c41SDudley Du true); 589c2c06c41SDudley Du if (error || !PIP_CMD_COMPLETE_SUCCESS(resp_data) || 590c2c06c41SDudley Du resp_data[6] != data_id || 591c2c06c41SDudley Du !VALID_CMD_RESP_HEADER(resp_data, PIP_RETRIEVE_DATA_STRUCTURE)) 592c2c06c41SDudley Du return (error < 0) ? error : -EAGAIN; 593c2c06c41SDudley Du 594c2c06c41SDudley Du read_len = get_unaligned_le16(&resp_data[7]); 595c2c06c41SDudley Du if (*data_buf_lens < read_len) { 596c2c06c41SDudley Du *data_buf_lens = read_len; 597c2c06c41SDudley Du return -ENOBUFS; 598c2c06c41SDudley Du } 599c2c06c41SDudley Du 600c2c06c41SDudley Du memcpy(data, &resp_data[10], read_len); 601c2c06c41SDudley Du *data_buf_lens = read_len; 602c2c06c41SDudley Du return 0; 603c2c06c41SDudley Du } 604c2c06c41SDudley Du 605c2c06c41SDudley Du static ssize_t cyapa_gen6_show_baseline(struct device *dev, 606c2c06c41SDudley Du struct device_attribute *attr, char *buf) 607c2c06c41SDudley Du { 608c2c06c41SDudley Du struct cyapa *cyapa = dev_get_drvdata(dev); 609c2c06c41SDudley Du u8 data[GEN6_MAX_RX_NUM]; 610c2c06c41SDudley Du int data_len; 611c2c06c41SDudley Du int size = 0; 612c2c06c41SDudley Du int i; 613c2c06c41SDudley Du int error; 614c2c06c41SDudley Du int resume_error; 615c2c06c41SDudley Du 616c2c06c41SDudley Du if (!cyapa_is_pip_app_mode(cyapa)) 617c2c06c41SDudley Du return -EBUSY; 618c2c06c41SDudley Du 619c2c06c41SDudley Du /* 1. Suspend Scanning*/ 620c2c06c41SDudley Du error = cyapa_pip_suspend_scanning(cyapa); 621c2c06c41SDudley Du if (error) 622c2c06c41SDudley Du return error; 623c2c06c41SDudley Du 624c2c06c41SDudley Du /* 2. IDAC and RX Attenuator Calibration Data (Center Frequency). */ 625c2c06c41SDudley Du data_len = sizeof(data); 626c2c06c41SDudley Du error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len, 627c2c06c41SDudley Du GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC, 628c2c06c41SDudley Du data, &data_len); 629c2c06c41SDudley Du if (error) 630c2c06c41SDudley Du goto resume_scanning; 631c2c06c41SDudley Du 632c2c06c41SDudley Du size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d ", 633c2c06c41SDudley Du data[0], /* RX Attenuator Mutual */ 634c2c06c41SDudley Du data[1], /* IDAC Mutual */ 635c2c06c41SDudley Du data[2], /* RX Attenuator Self RX */ 636c2c06c41SDudley Du data[3], /* IDAC Self RX */ 637c2c06c41SDudley Du data[4], /* RX Attenuator Self TX */ 638c2c06c41SDudley Du data[5] /* IDAC Self TX */ 639c2c06c41SDudley Du ); 640c2c06c41SDudley Du 641c2c06c41SDudley Du /* 3. Read Attenuator Trim. */ 642c2c06c41SDudley Du data_len = sizeof(data); 643c2c06c41SDudley Du error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len, 644c2c06c41SDudley Du GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM, 645c2c06c41SDudley Du data, &data_len); 646c2c06c41SDudley Du if (error) 647c2c06c41SDudley Du goto resume_scanning; 648c2c06c41SDudley Du 649c2c06c41SDudley Du /* set attenuator trim values. */ 650c2c06c41SDudley Du for (i = 0; i < data_len; i++) 651c2c06c41SDudley Du size += scnprintf(buf + size, PAGE_SIZE - size, "%d ", data[i]); 652c2c06c41SDudley Du size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); 653c2c06c41SDudley Du 654c2c06c41SDudley Du resume_scanning: 655c2c06c41SDudley Du /* 4. Resume Scanning*/ 656c2c06c41SDudley Du resume_error = cyapa_pip_resume_scanning(cyapa); 657c2c06c41SDudley Du if (resume_error || error) { 658c2c06c41SDudley Du memset(buf, 0, PAGE_SIZE); 659c2c06c41SDudley Du return resume_error ? resume_error : error; 660c2c06c41SDudley Du } 661c2c06c41SDudley Du 662c2c06c41SDudley Du return size; 663c2c06c41SDudley Du } 664c2c06c41SDudley Du 665c2c06c41SDudley Du static int cyapa_gen6_operational_check(struct cyapa *cyapa) 666c2c06c41SDudley Du { 667c2c06c41SDudley Du struct device *dev = &cyapa->client->dev; 668c2c06c41SDudley Du int error; 669c2c06c41SDudley Du 670c2c06c41SDudley Du if (cyapa->gen != CYAPA_GEN6) 671c2c06c41SDudley Du return -ENODEV; 672c2c06c41SDudley Du 673c2c06c41SDudley Du switch (cyapa->state) { 674c2c06c41SDudley Du case CYAPA_STATE_GEN6_BL: 675c2c06c41SDudley Du error = cyapa_pip_bl_exit(cyapa); 676c2c06c41SDudley Du if (error) { 677c2c06c41SDudley Du /* Try to update trackpad product information. */ 678c2c06c41SDudley Du cyapa_gen6_bl_read_app_info(cyapa); 679c2c06c41SDudley Du goto out; 680c2c06c41SDudley Du } 681c2c06c41SDudley Du 682c2c06c41SDudley Du cyapa->state = CYAPA_STATE_GEN6_APP; 683c2c06c41SDudley Du 684c2c06c41SDudley Du case CYAPA_STATE_GEN6_APP: 685c2c06c41SDudley Du /* 686c2c06c41SDudley Du * If trackpad device in deep sleep mode, 687c2c06c41SDudley Du * the app command will fail. 688c2c06c41SDudley Du * So always try to reset trackpad device to full active when 689c2c06c41SDudley Du * the device state is required. 690c2c06c41SDudley Du */ 691c2c06c41SDudley Du error = cyapa_gen6_set_power_mode(cyapa, 692*3cd47869SDudley Du PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE); 693c2c06c41SDudley Du if (error) 694c2c06c41SDudley Du dev_warn(dev, "%s: failed to set power active mode.\n", 695c2c06c41SDudley Du __func__); 696c2c06c41SDudley Du 697945525eeSDudley Du /* By default, the trackpad proximity function is enabled. */ 698945525eeSDudley Du error = cyapa_pip_set_proximity(cyapa, true); 699945525eeSDudley Du if (error) 700945525eeSDudley Du dev_warn(dev, "%s: failed to enable proximity.\n", 701945525eeSDudley Du __func__); 702945525eeSDudley Du 703c2c06c41SDudley Du /* Get trackpad product information. */ 704c2c06c41SDudley Du error = cyapa_gen6_read_sys_info(cyapa); 705c2c06c41SDudley Du if (error) 706c2c06c41SDudley Du goto out; 707c2c06c41SDudley Du /* Only support product ID starting with CYTRA */ 708c2c06c41SDudley Du if (memcmp(cyapa->product_id, product_id, 709c2c06c41SDudley Du strlen(product_id)) != 0) { 710c2c06c41SDudley Du dev_err(dev, "%s: unknown product ID (%s)\n", 711c2c06c41SDudley Du __func__, cyapa->product_id); 712c2c06c41SDudley Du error = -EINVAL; 713c2c06c41SDudley Du } 714c2c06c41SDudley Du break; 715c2c06c41SDudley Du default: 716c2c06c41SDudley Du error = -EINVAL; 717c2c06c41SDudley Du } 718c2c06c41SDudley Du 719c2c06c41SDudley Du out: 720c2c06c41SDudley Du return error; 721c2c06c41SDudley Du } 722c2c06c41SDudley Du 723c2c06c41SDudley Du const struct cyapa_dev_ops cyapa_gen6_ops = { 724c2c06c41SDudley Du .check_fw = cyapa_pip_check_fw, 725c2c06c41SDudley Du .bl_enter = cyapa_pip_bl_enter, 726c2c06c41SDudley Du .bl_initiate = cyapa_pip_bl_initiate, 727c2c06c41SDudley Du .update_fw = cyapa_pip_do_fw_update, 728c2c06c41SDudley Du .bl_activate = cyapa_pip_bl_activate, 729c2c06c41SDudley Du .bl_deactivate = cyapa_pip_bl_deactivate, 730c2c06c41SDudley Du 731c2c06c41SDudley Du .show_baseline = cyapa_gen6_show_baseline, 732c2c06c41SDudley Du .calibrate_store = cyapa_pip_do_calibrate, 733c2c06c41SDudley Du 734c2c06c41SDudley Du .initialize = cyapa_gen6_initialize, 735c2c06c41SDudley Du 736c2c06c41SDudley Du .state_parse = cyapa_pip_state_parse, 737c2c06c41SDudley Du .operational_check = cyapa_gen6_operational_check, 738c2c06c41SDudley Du 739c2c06c41SDudley Du .irq_handler = cyapa_pip_irq_handler, 740c2c06c41SDudley Du .irq_cmd_handler = cyapa_pip_irq_cmd_handler, 741c2c06c41SDudley Du .sort_empty_output_data = cyapa_empty_pip_output_data, 742c2c06c41SDudley Du .set_power_mode = cyapa_gen6_set_power_mode, 743945525eeSDudley Du 744945525eeSDudley Du .set_proximity = cyapa_gen6_set_proximity, 745c2c06c41SDudley Du }; 746