2015-01-17 18:49:37 -08:00
/*
* Cypress APA trackpad with I2C interface
*
* Author : Dudley Du < dudl @ cypress . com >
*
2015-07-20 16:49:06 -07:00
* Copyright ( C ) 2014 - 2015 Cypress Semiconductor , Inc .
2015-01-17 18:49:37 -08:00
*
* 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>
2015-03-02 09:37:59 -08:00
# include <asm/unaligned.h>
2015-01-17 22:14:48 -08:00
# include <linux/crc-itu-t.h>
2015-07-20 17:09:59 -07:00
# include <linux/pm_runtime.h>
2015-01-17 18:49:37 -08:00
# include "cyapa.h"
2015-07-20 16:49:06 -07:00
/* Macro of TSG firmware image */
2015-01-17 18:49:37 -08:00
# define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80
# define CYAPA_TSG_IMG_FW_HDR_SIZE 13
# define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE)
# define CYAPA_TSG_IMG_START_ROW_NUM 0x002e
# define CYAPA_TSG_IMG_END_ROW_NUM 0x01fe
# define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff
# define CYAPA_TSG_IMG_MAX_RECORDS (CYAPA_TSG_IMG_END_ROW_NUM - \
CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1 )
# define CYAPA_TSG_IMG_READ_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2)
# define CYAPA_TSG_START_OF_APPLICATION 0x1700
# define CYAPA_TSG_APP_INTEGRITY_SIZE 60
# define CYAPA_TSG_FLASH_MAP_METADATA_SIZE 60
# define CYAPA_TSG_BL_KEY_SIZE 8
# define CYAPA_TSG_MAX_CMD_SIZE 256
2015-07-20 16:49:06 -07:00
/* Macro of PIP interface */
# define PIP_BL_INITIATE_RESP_LEN 11
# define PIP_BL_FAIL_EXIT_RESP_LEN 11
# define PIP_BL_FAIL_EXIT_STATUS_CODE 0x0c
# define PIP_BL_VERIFY_INTEGRITY_RESP_LEN 12
# define PIP_BL_INTEGRITY_CHEKC_PASS 0x00
# define PIP_BL_BLOCK_WRITE_RESP_LEN 11
# define PIP_TOUCH_REPORT_ID 0x01
# define PIP_BTN_REPORT_ID 0x03
# define PIP_WAKEUP_EVENT_REPORT_ID 0x04
# define PIP_PUSH_BTN_REPORT_ID 0x06
# define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 /* Special for old Gen5 TP. */
2015-07-20 16:57:53 -07:00
# define PIP_PROXIMITY_REPORT_ID 0x07
# define PIP_PROXIMITY_REPORT_SIZE 6
# define PIP_PROXIMITY_DISTANCE_OFFSET 0x05
# define PIP_PROXIMITY_DISTANCE_MASK 0x01
2015-07-20 16:49:06 -07:00
# define PIP_TOUCH_REPORT_HEAD_SIZE 7
# define PIP_TOUCH_REPORT_MAX_SIZE 127
# define PIP_BTN_REPORT_HEAD_SIZE 6
# define PIP_BTN_REPORT_MAX_SIZE 14
# define PIP_WAKEUP_EVENT_SIZE 4
# define PIP_NUMBER_OF_TOUCH_OFFSET 5
# define PIP_NUMBER_OF_TOUCH_MASK 0x1f
# define PIP_BUTTONS_OFFSET 5
# define PIP_BUTTONS_MASK 0x0f
# define PIP_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03)
# define PIP_GET_TOUCH_ID(reg) ((reg) & 0x1f)
# define PIP_TOUCH_TYPE_FINGER 0x00
# define PIP_TOUCH_TYPE_PROXIMITY 0x01
# define PIP_TOUCH_TYPE_HOVER 0x02
# define PIP_GET_TOUCH_TYPE(reg) ((reg) & 0x07)
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
# define RECORD_EVENT_NONE 0
# define RECORD_EVENT_TOUCHDOWN 1
# define RECORD_EVENT_DISPLACE 2
# define RECORD_EVENT_LIFTOFF 3
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
# define PIP_SENSING_MODE_MUTUAL_CAP_FINE 0x00
# define PIP_SENSING_MODE_SELF_CAP 0x02
2015-07-20 16:57:53 -07:00
# define PIP_SET_PROXIMITY 0x49
2015-07-20 16:49:06 -07:00
/* Macro of Gen5 */
# define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100
# define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe
2015-01-17 18:49:37 -08:00
# define GEN5_POWER_STATE_ACTIVE 0x01
# define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02
# define GEN5_POWER_STATE_READY 0x03
# define GEN5_POWER_STATE_IDLE 0x04
# define GEN5_POWER_STATE_BTN_ONLY 0x05
# define GEN5_POWER_STATE_OFF 0x06
# define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */
# define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */
2015-07-20 16:49:06 -07:00
# define GEN5_CMD_GET_PARAMETER 0x05
# define GEN5_CMD_SET_PARAMETER 0x06
# define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d
# define GEN5_PARAMETER_ACT_INTERVL_SIZE 1
# define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f
# define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2
# define GEN5_PARAMETER_LP_INTRVL_ID 0x4c
# define GEN5_PARAMETER_LP_INTRVL_SIZE 2
# define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08
2015-01-17 18:49:37 -08:00
# define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d
# define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe
# define GEN5_APP_REPORT_DESCRIPTOR_SIZE 0xee
# define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa
# define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6
# define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00
# define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01
# define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
# define GEN5_CMD_EXECUTE_PANEL_SCAN 0x2a
# define GEN5_CMD_RETRIEVE_PANEL_SCAN 0x2b
# define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA 0x00
# define GEN5_PANEL_SCAN_MUTUAL_BASELINE 0x01
# define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT 0x02
# define GEN5_PANEL_SCAN_SELF_RAW_DATA 0x03
# define GEN5_PANEL_SCAN_SELF_BASELINE 0x04
# define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05
2015-07-20 16:49:06 -07:00
/* The offset only valid for retrieve PWC and panel scan commands */
2015-01-17 18:49:37 -08:00
# define GEN5_RESP_DATA_STRUCTURE_OFFSET 10
# define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07
2015-07-20 16:49:06 -07:00
struct cyapa_pip_touch_record {
2015-01-17 18:49:37 -08:00
/*
* Bit 7 - 3 : reserved
* Bit 2 - 0 : touch type ;
* 0 : standard finger ;
2015-07-20 16:53:30 -07:00
* 1 : proximity ( Start supported in Gen5 TP ) .
* 2 : finger hover ( defined , but not used yet . )
* 3 - 15 : reserved .
2015-01-17 18:49:37 -08:00
*/
u8 touch_type ;
/*
* Bit 7 : indicates touch liftoff status .
* 0 : touch is currently on the panel .
* 1 : touch record indicates a liftoff .
* Bit 6 - 5 : indicates an event associated with this touch instance
* 0 : no event
* 1 : touchdown
* 2 : significant displacement ( > active distance )
* 3 : liftoff ( record reports last known coordinates )
* Bit 4 - 0 : An arbitrary ID tag associated with a finger
* to allow tracking a touch as it moves around the panel .
*/
u8 touch_tip_event_id ;
/* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */
u8 x_lo ;
/* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */
u8 x_hi ;
/* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */
u8 y_lo ;
/* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */
u8 y_hi ;
2015-07-20 16:49:06 -07:00
/*
* The meaning of this value is different when touch_type is different .
* For standard finger type :
* Touch intensity in counts , pressure value .
2015-07-20 16:53:30 -07:00
* For proximity type ( Start supported in Gen5 TP ) :
* The distance , in surface units , between the contact and
* the surface .
2015-07-20 16:49:06 -07:00
* */
2015-01-17 18:49:37 -08:00
u8 z ;
/*
* The length of the major axis of the ellipse of contact between
* the finger and the panel ( ABS_MT_TOUCH_MAJOR ) .
*/
u8 major_axis_len ;
/*
* The length of the minor axis of the ellipse of contact between
* the finger and the panel ( ABS_MT_TOUCH_MINOR ) .
*/
u8 minor_axis_len ;
/*
* The length of the major axis of the approaching tool .
* ( ABS_MT_WIDTH_MAJOR )
*/
u8 major_tool_len ;
/*
* The length of the minor axis of the approaching tool .
* ( ABS_MT_WIDTH_MINOR )
*/
u8 minor_tool_len ;
/*
* The angle between the panel vertical axis and
* the major axis of the contact ellipse . This value is an 8 - bit
* signed integer . The range is - 127 to + 127 ( corresponding to
* - 90 degree and + 90 degree respectively ) .
* The positive direction is clockwise from the vertical axis .
* If the ellipse of contact degenerates into a circle ,
* orientation is reported as 0.
*/
u8 orientation ;
} __packed ;
2015-07-20 16:49:06 -07:00
struct cyapa_pip_report_data {
u8 report_head [ PIP_TOUCH_REPORT_HEAD_SIZE ] ;
struct cyapa_pip_touch_record touch_records [ 10 ] ;
2015-01-17 18:49:37 -08:00
} __packed ;
2015-01-17 22:14:48 -08:00
struct cyapa_tsg_bin_image_head {
u8 head_size ; /* Unit: bytes, including itself. */
u8 ttda_driver_major_version ; /* Reserved as 0. */
u8 ttda_driver_minor_version ; /* Reserved as 0. */
u8 fw_major_version ;
u8 fw_minor_version ;
u8 fw_revision_control_number [ 8 ] ;
2015-07-20 16:53:30 -07:00
u8 silicon_id_hi ;
u8 silicon_id_lo ;
u8 chip_revision ;
u8 family_id ;
u8 bl_ver_maj ;
u8 bl_ver_min ;
2015-01-17 22:14:48 -08:00
} __packed ;
struct cyapa_tsg_bin_image_data_record {
u8 flash_array_id ;
__be16 row_number ;
/* The number of bytes of flash data contained in this record. */
__be16 record_len ;
/* The flash program data. */
u8 record_data [ CYAPA_TSG_FW_ROW_SIZE ] ;
} __packed ;
struct cyapa_tsg_bin_image {
struct cyapa_tsg_bin_image_head image_head ;
2020-02-14 17:03:12 -08:00
struct cyapa_tsg_bin_image_data_record records [ ] ;
2015-01-17 22:14:48 -08:00
} __packed ;
2015-07-20 16:49:06 -07:00
struct pip_bl_packet_start {
2015-01-17 22:14:48 -08:00
u8 sop ; /* Start of packet, must be 01h */
u8 cmd_code ;
__le16 data_length ; /* Size of data parameter start from data[0] */
} __packed ;
2015-07-20 16:49:06 -07:00
struct pip_bl_packet_end {
2015-01-17 22:14:48 -08:00
__le16 crc ;
u8 eop ; /* End of packet, must be 17h */
} __packed ;
2015-07-20 16:49:06 -07:00
struct pip_bl_cmd_head {
2015-01-17 22:14:48 -08:00
__le16 addr ; /* Output report register address, must be 0004h */
/* Size of packet not including output report register address */
__le16 length ;
u8 report_id ; /* Bootloader output report id, must be 40h */
u8 rsvd ; /* Reserved, must be 0 */
2015-07-20 16:49:06 -07:00
struct pip_bl_packet_start packet_start ;
2020-02-14 17:03:12 -08:00
u8 data [ ] ; /* Command data variable based on commands */
2015-01-17 22:14:48 -08:00
} __packed ;
/* Initiate bootload command data structure. */
2015-07-20 16:49:06 -07:00
struct pip_bl_initiate_cmd_data {
2015-01-17 22:14:48 -08:00
/* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */
u8 key [ CYAPA_TSG_BL_KEY_SIZE ] ;
u8 metadata_raw_parameter [ CYAPA_TSG_FLASH_MAP_METADATA_SIZE ] ;
__le16 metadata_crc ;
} __packed ;
2015-07-20 16:49:06 -07:00
struct tsg_bl_metadata_row_params {
2015-01-17 22:14:48 -08:00
__le16 size ;
2015-01-19 15:59:31 -08:00
__le16 maximum_size ;
2015-01-17 22:14:48 -08:00
__le32 app_start ;
__le16 app_len ;
__le16 app_crc ;
__le32 app_entry ;
__le32 upgrade_start ;
__le16 upgrade_len ;
__le16 entry_row_crc ;
u8 padding [ 36 ] ; /* Padding data must be 0 */
__le16 metadata_crc ; /* CRC starts at offset of 60 */
} __packed ;
/* Bootload program and verify row command data structure */
2015-07-20 16:49:06 -07:00
struct tsg_bl_flash_row_head {
2015-01-17 22:14:48 -08:00
u8 flash_array_id ;
__le16 flash_row_id ;
2020-02-14 17:03:12 -08:00
u8 flash_data [ ] ;
2015-01-17 22:14:48 -08:00
} __packed ;
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head {
2015-01-17 18:49:37 -08:00
__le16 addr ; /* Output report register address, must be 0004h */
/* Size of packet not including output report register address */
__le16 length ;
u8 report_id ; /* Application output report id, must be 2Fh */
u8 rsvd ; /* Reserved, must be 0 */
/*
* Bit 7 : reserved , must be 0.
* Bit 6 - 0 : command code .
*/
u8 cmd_code ;
2020-02-14 17:03:12 -08:00
u8 parameter_data [ ] ; /* Parameter data variable based on cmd_code */
2015-01-17 18:49:37 -08:00
} __packed ;
2015-05-26 13:44:06 -07:00
/* Application get/set parameter command data structure */
2015-01-17 18:49:37 -08:00
struct gen5_app_set_parameter_data {
u8 parameter_id ;
u8 parameter_size ;
__le32 value ;
} __packed ;
struct gen5_app_get_parameter_data {
u8 parameter_id ;
} __packed ;
2015-01-17 22:16:01 -08:00
struct gen5_retrieve_panel_scan_data {
__le16 read_offset ;
__le16 read_elements ;
u8 data_id ;
} __packed ;
2015-07-20 16:49:06 -07:00
u8 pip_read_sys_info [ ] = { 0x04 , 0x00 , 0x05 , 0x00 , 0x2f , 0x00 , 0x02 } ;
u8 pip_bl_read_app_info [ ] = { 0x04 , 0x00 , 0x0b , 0x00 , 0x40 , 0x00 ,
0x01 , 0x3c , 0x00 , 0x00 , 0xb0 , 0x42 , 0x17
} ;
2015-01-17 22:14:48 -08:00
2015-07-20 16:49:06 -07:00
static u8 cyapa_pip_bl_cmd_key [ ] = { 0xa5 , 0x01 , 0x02 , 0x03 ,
2015-01-17 22:14:48 -08:00
0xff , 0xfe , 0xfd , 0x5a } ;
2016-03-04 11:23:09 -08:00
static int cyapa_pip_event_process ( struct cyapa * cyapa ,
struct cyapa_pip_report_data * report_data ) ;
2015-07-20 16:49:06 -07:00
int cyapa_pip_cmd_state_initialize ( struct cyapa * cyapa )
2015-01-17 18:49:37 -08:00
{
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
init_completion ( & pip - > cmd_ready ) ;
atomic_set ( & pip - > cmd_issued , 0 ) ;
mutex_init ( & pip - > cmd_lock ) ;
2015-01-17 18:49:37 -08:00
2016-03-04 11:23:09 -08:00
mutex_init ( & pip - > pm_stage_lock ) ;
pip - > pm_stage = CYAPA_PM_DEACTIVE ;
2015-07-20 16:49:06 -07:00
pip - > resp_sort_func = NULL ;
pip - > in_progress_cmd = PIP_INVALID_CMD ;
pip - > resp_data = NULL ;
pip - > resp_len = NULL ;
2015-01-17 18:49:37 -08:00
cyapa - > dev_pwr_mode = UNINIT_PWR_MODE ;
cyapa - > dev_sleep_time = UNINIT_SLEEP_TIME ;
return 0 ;
}
/* Return negative errno, or else the number of bytes read. */
2015-07-20 16:49:06 -07:00
ssize_t cyapa_i2c_pip_read ( struct cyapa * cyapa , u8 * buf , size_t size )
2015-01-17 18:49:37 -08:00
{
int ret ;
if ( size = = 0 )
return 0 ;
if ( ! buf | | size > CYAPA_REG_MAP_SIZE )
return - EINVAL ;
ret = i2c_master_recv ( cyapa - > client , buf , size ) ;
if ( ret ! = size )
return ( ret < 0 ) ? ret : - EIO ;
return size ;
}
2020-11-04 11:12:15 -08:00
/*
2015-01-17 18:49:37 -08:00
* Return a negative errno code else zero on success .
*/
2015-07-20 16:49:06 -07:00
ssize_t cyapa_i2c_pip_write ( struct cyapa * cyapa , u8 * buf , size_t size )
2015-01-17 18:49:37 -08:00
{
int ret ;
if ( ! buf | | ! size )
return - EINVAL ;
ret = i2c_master_send ( cyapa - > client , buf , size ) ;
if ( ret ! = size )
return ( ret < 0 ) ? ret : - EIO ;
return 0 ;
}
2016-03-04 11:23:09 -08:00
static void cyapa_set_pip_pm_state ( struct cyapa * cyapa ,
enum cyapa_pm_stage pm_stage )
{
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
mutex_lock ( & pip - > pm_stage_lock ) ;
pip - > pm_stage = pm_stage ;
mutex_unlock ( & pip - > pm_stage_lock ) ;
}
static void cyapa_reset_pip_pm_state ( struct cyapa * cyapa )
{
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
/* Indicates the pip->pm_stage is not valid. */
mutex_lock ( & pip - > pm_stage_lock ) ;
pip - > pm_stage = CYAPA_PM_DEACTIVE ;
mutex_unlock ( & pip - > pm_stage_lock ) ;
}
static enum cyapa_pm_stage cyapa_get_pip_pm_state ( struct cyapa * cyapa )
{
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
enum cyapa_pm_stage pm_stage ;
mutex_lock ( & pip - > pm_stage_lock ) ;
pm_stage = pip - > pm_stage ;
mutex_unlock ( & pip - > pm_stage_lock ) ;
return pm_stage ;
}
2020-11-04 11:12:15 -08:00
/*
2015-01-17 18:49:37 -08:00
* This function is aimed to dump all not read data in Gen5 trackpad
* before send any command , otherwise , the interrupt line will be blocked .
*/
2015-07-20 16:49:06 -07:00
int cyapa_empty_pip_output_data ( struct cyapa * cyapa ,
2015-01-17 18:49:37 -08:00
u8 * buf , int * len , cb_sort func )
{
2016-03-04 11:23:09 -08:00
struct input_dev * input = cyapa - > input ;
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2016-03-04 11:23:09 -08:00
enum cyapa_pm_stage pm_stage = cyapa_get_pip_pm_state ( cyapa ) ;
2015-01-17 18:49:37 -08:00
int length ;
int report_count ;
int empty_count ;
int buf_len ;
int error ;
buf_len = 0 ;
if ( len ) {
buf_len = ( * len < CYAPA_REG_MAP_SIZE ) ?
* len : CYAPA_REG_MAP_SIZE ;
* len = 0 ;
}
report_count = 8 ; /* max 7 pending data before command response data */
empty_count = 0 ;
do {
/*
* Depending on testing in cyapa driver , there are max 5 " 02 00 "
* packets between two valid buffered data report in firmware .
* So in order to dump all buffered data out and
* make interrupt line release for reassert again ,
* we must set the empty_count check value bigger than 5 to
* make it work . Otherwise , in some situation ,
* the interrupt line may unable to reactive again ,
* which will cause trackpad device unable to
* report data any more .
* for example , it may happen in EFT and ESD testing .
*/
if ( empty_count > 5 )
return 0 ;
2015-07-20 16:49:06 -07:00
error = cyapa_i2c_pip_read ( cyapa , pip - > empty_buf ,
PIP_RESP_LENGTH_SIZE ) ;
2015-01-17 18:49:37 -08:00
if ( error < 0 )
return error ;
2015-07-20 16:49:06 -07:00
length = get_unaligned_le16 ( pip - > empty_buf ) ;
if ( length = = PIP_RESP_LENGTH_SIZE ) {
2015-01-17 18:49:37 -08:00
empty_count + + ;
continue ;
} else if ( length > CYAPA_REG_MAP_SIZE ) {
/* Should not happen */
return - EINVAL ;
} else if ( length = = 0 ) {
/* Application or bootloader launch data polled out. */
2015-07-20 16:49:06 -07:00
length = PIP_RESP_LENGTH_SIZE ;
2015-01-17 18:49:37 -08:00
if ( buf & & buf_len & & func & &
2015-07-20 16:49:06 -07:00
func ( cyapa , pip - > empty_buf , length ) ) {
2015-01-17 18:49:37 -08:00
length = min ( buf_len , length ) ;
2015-07-20 16:49:06 -07:00
memcpy ( buf , pip - > empty_buf , length ) ;
2015-01-17 18:49:37 -08:00
* len = length ;
/* Response found, success. */
return 0 ;
}
continue ;
}
2015-07-20 16:49:06 -07:00
error = cyapa_i2c_pip_read ( cyapa , pip - > empty_buf , length ) ;
2015-01-17 18:49:37 -08:00
if ( error < 0 )
return error ;
report_count - - ;
empty_count = 0 ;
2015-07-20 16:49:06 -07:00
length = get_unaligned_le16 ( pip - > empty_buf ) ;
if ( length < = PIP_RESP_LENGTH_SIZE ) {
2015-01-17 18:49:37 -08:00
empty_count + + ;
} else if ( buf & & buf_len & & func & &
2015-07-20 16:49:06 -07:00
func ( cyapa , pip - > empty_buf , length ) ) {
2015-01-17 18:49:37 -08:00
length = min ( buf_len , length ) ;
2015-07-20 16:49:06 -07:00
memcpy ( buf , pip - > empty_buf , length ) ;
2015-01-17 18:49:37 -08:00
* len = length ;
/* Response found, success. */
return 0 ;
2020-10-04 21:16:07 -07:00
} else if ( cyapa - > operational & &
input & & input_device_enabled ( input ) & &
2016-03-04 11:23:09 -08:00
( pm_stage = = CYAPA_PM_RUNTIME_RESUME | |
pm_stage = = CYAPA_PM_RUNTIME_SUSPEND ) ) {
/* Parse the data and report it if it's valid. */
cyapa_pip_event_process ( cyapa ,
( struct cyapa_pip_report_data * ) pip - > empty_buf ) ;
2015-01-17 18:49:37 -08:00
}
error = - EINVAL ;
} while ( report_count ) ;
return error ;
}
static int cyapa_do_i2c_pip_cmd_irq_sync (
struct cyapa * cyapa ,
u8 * cmd , size_t cmd_len ,
unsigned long timeout )
{
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2015-01-17 18:49:37 -08:00
int error ;
/* Wait for interrupt to set ready completion */
2015-07-20 16:49:06 -07:00
init_completion ( & pip - > cmd_ready ) ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
atomic_inc ( & pip - > cmd_issued ) ;
2015-01-17 18:49:37 -08:00
error = cyapa_i2c_pip_write ( cyapa , cmd , cmd_len ) ;
if ( error ) {
2015-07-20 16:49:06 -07:00
atomic_dec ( & pip - > cmd_issued ) ;
2015-01-17 18:49:37 -08:00
return ( error < 0 ) ? error : - EIO ;
}
/* Wait for interrupt to indicate command is completed. */
2015-07-20 16:49:06 -07:00
timeout = wait_for_completion_timeout ( & pip - > cmd_ready ,
2015-01-17 18:49:37 -08:00
msecs_to_jiffies ( timeout ) ) ;
if ( timeout = = 0 ) {
2015-07-20 16:49:06 -07:00
atomic_dec ( & pip - > cmd_issued ) ;
2015-01-17 18:49:37 -08:00
return - ETIMEDOUT ;
}
return 0 ;
}
static int cyapa_do_i2c_pip_cmd_polling (
struct cyapa * cyapa ,
u8 * cmd , size_t cmd_len ,
u8 * resp_data , int * resp_len ,
unsigned long timeout ,
cb_sort func )
{
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2015-01-17 18:49:37 -08:00
int tries ;
int length ;
int error ;
2015-07-20 16:49:06 -07:00
atomic_inc ( & pip - > cmd_issued ) ;
2015-01-17 18:49:37 -08:00
error = cyapa_i2c_pip_write ( cyapa , cmd , cmd_len ) ;
if ( error ) {
2015-07-20 16:49:06 -07:00
atomic_dec ( & pip - > cmd_issued ) ;
2015-01-17 18:49:37 -08:00
return error < 0 ? error : - EIO ;
}
length = resp_len ? * resp_len : 0 ;
if ( resp_data & & resp_len & & length ! = 0 & & func ) {
tries = timeout / 5 ;
do {
usleep_range ( 3000 , 5000 ) ;
* resp_len = length ;
error = cyapa_empty_pip_output_data ( cyapa ,
resp_data , resp_len , func ) ;
if ( error | | * resp_len = = 0 )
continue ;
else
break ;
} while ( - - tries > 0 ) ;
if ( ( error | | * resp_len = = 0 ) | | tries < = 0 )
error = error ? error : - ETIMEDOUT ;
}
2015-07-20 16:49:06 -07:00
atomic_dec ( & pip - > cmd_issued ) ;
2015-01-17 18:49:37 -08:00
return error ;
}
2015-07-20 16:49:06 -07:00
int cyapa_i2c_pip_cmd_irq_sync (
2015-01-17 18:49:37 -08:00
struct cyapa * cyapa ,
u8 * cmd , int cmd_len ,
u8 * resp_data , int * resp_len ,
unsigned long timeout ,
cb_sort func ,
bool irq_mode )
{
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2015-01-17 18:49:37 -08:00
int error ;
if ( ! cmd | | ! cmd_len )
return - EINVAL ;
/* Commands must be serialized. */
2015-07-20 16:49:06 -07:00
error = mutex_lock_interruptible ( & pip - > cmd_lock ) ;
2015-01-17 18:49:37 -08:00
if ( error )
return error ;
2015-07-20 16:49:06 -07:00
pip - > resp_sort_func = func ;
pip - > resp_data = resp_data ;
pip - > resp_len = resp_len ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
if ( cmd_len > = PIP_MIN_APP_CMD_LENGTH & &
cmd [ 4 ] = = PIP_APP_CMD_REPORT_ID ) {
2015-01-17 18:49:37 -08:00
/* Application command */
2015-07-20 16:49:06 -07:00
pip - > in_progress_cmd = cmd [ 6 ] & 0x7f ;
} else if ( cmd_len > = PIP_MIN_BL_CMD_LENGTH & &
cmd [ 4 ] = = PIP_BL_CMD_REPORT_ID ) {
2015-01-17 18:49:37 -08:00
/* Bootloader command */
2015-07-20 16:49:06 -07:00
pip - > in_progress_cmd = cmd [ 7 ] ;
2015-01-17 18:49:37 -08:00
}
/* Send command data, wait and read output response data's length. */
if ( irq_mode ) {
2015-07-20 16:49:06 -07:00
pip - > is_irq_mode = true ;
2015-01-17 18:49:37 -08:00
error = cyapa_do_i2c_pip_cmd_irq_sync ( cyapa , cmd , cmd_len ,
timeout ) ;
if ( error = = - ETIMEDOUT & & resp_data & &
resp_len & & * resp_len ! = 0 & & func ) {
/*
* For some old version , there was no interrupt for
* the command response data , so need to poll here
* to try to get the response data .
*/
error = cyapa_empty_pip_output_data ( cyapa ,
resp_data , resp_len , func ) ;
if ( error | | * resp_len = = 0 )
error = error ? error : - ETIMEDOUT ;
}
} else {
2015-07-20 16:49:06 -07:00
pip - > is_irq_mode = false ;
2015-01-17 18:49:37 -08:00
error = cyapa_do_i2c_pip_cmd_polling ( cyapa , cmd , cmd_len ,
resp_data , resp_len , timeout , func ) ;
}
2015-07-20 16:49:06 -07:00
pip - > resp_sort_func = NULL ;
pip - > resp_data = NULL ;
pip - > resp_len = NULL ;
pip - > in_progress_cmd = PIP_INVALID_CMD ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
mutex_unlock ( & pip - > cmd_lock ) ;
2015-01-17 18:49:37 -08:00
return error ;
}
2015-07-20 16:49:06 -07:00
bool cyapa_sort_tsg_pip_bl_resp_data ( struct cyapa * cyapa ,
2015-01-17 18:49:37 -08:00
u8 * data , int len )
{
2015-07-20 16:49:06 -07:00
if ( ! data | | len < PIP_MIN_BL_RESP_LENGTH )
2015-01-17 18:49:37 -08:00
return false ;
/* Bootloader input report id 30h */
2015-07-20 16:49:06 -07:00
if ( data [ PIP_RESP_REPORT_ID_OFFSET ] = = PIP_BL_RESP_REPORT_ID & &
data [ PIP_RESP_RSVD_OFFSET ] = = PIP_RESP_RSVD_KEY & &
data [ PIP_RESP_BL_SOP_OFFSET ] = = PIP_SOP_KEY )
2015-01-17 18:49:37 -08:00
return true ;
return false ;
}
2015-07-20 16:49:06 -07:00
bool cyapa_sort_tsg_pip_app_resp_data ( struct cyapa * cyapa ,
2015-01-17 18:49:37 -08:00
u8 * data , int len )
{
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2015-01-17 18:49:37 -08:00
int resp_len ;
2015-07-20 16:49:06 -07:00
if ( ! data | | len < PIP_MIN_APP_RESP_LENGTH )
2015-01-17 18:49:37 -08:00
return false ;
2015-07-20 16:49:06 -07:00
if ( data [ PIP_RESP_REPORT_ID_OFFSET ] = = PIP_APP_RESP_REPORT_ID & &
data [ PIP_RESP_RSVD_OFFSET ] = = PIP_RESP_RSVD_KEY ) {
resp_len = get_unaligned_le16 ( & data [ PIP_RESP_LENGTH_OFFSET ] ) ;
if ( GET_PIP_CMD_CODE ( data [ PIP_RESP_APP_CMD_OFFSET ] ) = = 0x00 & &
resp_len = = PIP_UNSUPPORTED_CMD_RESP_LENGTH & &
data [ 5 ] = = pip - > in_progress_cmd ) {
2015-01-17 18:49:37 -08:00
/* Unsupported command code */
return false ;
2015-07-20 16:49:06 -07:00
} else if ( GET_PIP_CMD_CODE ( data [ PIP_RESP_APP_CMD_OFFSET ] ) = =
pip - > in_progress_cmd ) {
2015-01-17 18:49:37 -08:00
/* Correct command response received */
return true ;
}
}
return false ;
}
2015-07-20 16:49:06 -07:00
static bool cyapa_sort_pip_application_launch_data ( struct cyapa * cyapa ,
2015-01-17 22:14:48 -08:00
u8 * buf , int len )
{
2015-07-20 16:49:06 -07:00
if ( buf = = NULL | | len < PIP_RESP_LENGTH_SIZE )
2015-01-17 22:14:48 -08:00
return false ;
/*
* After reset or power on , trackpad device always sets to 0x00 0x00
* to indicate a reset or power on event .
*/
if ( buf [ 0 ] = = 0 & & buf [ 1 ] = = 0 )
return true ;
return false ;
}
2015-07-20 16:49:06 -07:00
static bool cyapa_sort_gen5_hid_descriptor_data ( struct cyapa * cyapa ,
2015-01-17 18:49:37 -08:00
u8 * buf , int len )
{
int resp_len ;
int max_output_len ;
/* Check hid descriptor. */
2015-07-20 16:49:06 -07:00
if ( len ! = PIP_HID_DESCRIPTOR_SIZE )
2015-01-17 18:49:37 -08:00
return false ;
2015-07-20 16:49:06 -07:00
resp_len = get_unaligned_le16 ( & buf [ PIP_RESP_LENGTH_OFFSET ] ) ;
2015-01-17 18:49:37 -08:00
max_output_len = get_unaligned_le16 ( & buf [ 16 ] ) ;
2015-07-20 16:49:06 -07:00
if ( resp_len = = PIP_HID_DESCRIPTOR_SIZE ) {
if ( buf [ PIP_RESP_REPORT_ID_OFFSET ] = = PIP_HID_BL_REPORT_ID & &
2015-01-17 18:49:37 -08:00
max_output_len = = GEN5_BL_MAX_OUTPUT_LENGTH ) {
/* BL mode HID Descriptor */
return true ;
2015-07-20 16:49:06 -07:00
} else if ( ( buf [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_HID_APP_REPORT_ID ) & &
2015-01-17 18:49:37 -08:00
max_output_len = = GEN5_APP_MAX_OUTPUT_LENGTH ) {
/* APP mode HID Descriptor */
return true ;
}
}
return false ;
}
2015-07-20 16:49:06 -07:00
static bool cyapa_sort_pip_deep_sleep_data ( struct cyapa * cyapa ,
2015-01-17 18:49:37 -08:00
u8 * buf , int len )
{
2015-07-20 16:49:06 -07:00
if ( len = = PIP_DEEP_SLEEP_RESP_LENGTH & &
buf [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_APP_DEEP_SLEEP_REPORT_ID & &
( buf [ 4 ] & PIP_DEEP_SLEEP_OPCODE_MASK ) = =
PIP_DEEP_SLEEP_OPCODE )
2015-01-17 18:49:37 -08:00
return true ;
return false ;
}
static int gen5_idle_state_parse ( struct cyapa * cyapa )
{
2015-07-20 16:49:06 -07:00
u8 resp_data [ PIP_HID_DESCRIPTOR_SIZE ] ;
2015-01-17 18:49:37 -08:00
int max_output_len ;
int length ;
u8 cmd [ 2 ] ;
int ret ;
int error ;
/*
* Dump all buffered data firstly for the situation
* when the trackpad is just power on the cyapa go here .
*/
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
memset ( resp_data , 0 , sizeof ( resp_data ) ) ;
ret = cyapa_i2c_pip_read ( cyapa , resp_data , 3 ) ;
if ( ret ! = 3 )
return ret < 0 ? ret : - EIO ;
2015-07-20 16:49:06 -07:00
length = get_unaligned_le16 ( & resp_data [ PIP_RESP_LENGTH_OFFSET ] ) ;
if ( length = = PIP_RESP_LENGTH_SIZE ) {
/* Normal state of Gen5 with no data to response */
2015-01-17 18:49:37 -08:00
cyapa - > gen = CYAPA_GEN5 ;
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
/* Read description from trackpad device */
cmd [ 0 ] = 0x01 ;
cmd [ 1 ] = 0x00 ;
2015-07-20 16:49:06 -07:00
length = PIP_HID_DESCRIPTOR_SIZE ;
2015-01-17 18:49:37 -08:00
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
2015-07-20 16:49:06 -07:00
cmd , PIP_RESP_LENGTH_SIZE ,
2015-01-17 18:49:37 -08:00
resp_data , & length ,
300 ,
2015-07-20 16:49:06 -07:00
cyapa_sort_gen5_hid_descriptor_data ,
2015-01-17 18:49:37 -08:00
false ) ;
if ( error )
return error ;
length = get_unaligned_le16 (
2015-07-20 16:49:06 -07:00
& resp_data [ PIP_RESP_LENGTH_OFFSET ] ) ;
2015-01-17 18:49:37 -08:00
max_output_len = get_unaligned_le16 ( & resp_data [ 16 ] ) ;
2015-07-20 16:49:06 -07:00
if ( ( length = = PIP_HID_DESCRIPTOR_SIZE | |
length = = PIP_RESP_LENGTH_SIZE ) & &
( resp_data [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_HID_BL_REPORT_ID ) & &
2015-01-17 18:49:37 -08:00
max_output_len = = GEN5_BL_MAX_OUTPUT_LENGTH ) {
/* BL mode HID Description read */
cyapa - > state = CYAPA_STATE_GEN5_BL ;
2015-07-20 16:49:06 -07:00
} else if ( ( length = = PIP_HID_DESCRIPTOR_SIZE | |
length = = PIP_RESP_LENGTH_SIZE ) & &
( resp_data [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_HID_APP_REPORT_ID ) & &
2015-01-17 18:49:37 -08:00
max_output_len = = GEN5_APP_MAX_OUTPUT_LENGTH ) {
/* APP mode HID Description read */
cyapa - > state = CYAPA_STATE_GEN5_APP ;
} else {
/* Should not happen!!! */
cyapa - > state = CYAPA_STATE_NO_DEVICE ;
}
}
return 0 ;
}
static int gen5_hid_description_header_parse ( struct cyapa * cyapa , u8 * reg_data )
{
int length ;
u8 resp_data [ 32 ] ;
int max_output_len ;
int ret ;
/* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
2015-05-26 13:44:06 -07:00
* 0x20 0x00 0xFF is Gen5 Bootloader HID Description Header .
2015-01-17 18:49:37 -08:00
*
* Must read HID Description content through out ,
* otherwise Gen5 trackpad cannot response next command
* or report any touch or button data .
*/
ret = cyapa_i2c_pip_read ( cyapa , resp_data ,
2015-07-20 16:49:06 -07:00
PIP_HID_DESCRIPTOR_SIZE ) ;
if ( ret ! = PIP_HID_DESCRIPTOR_SIZE )
2015-01-17 18:49:37 -08:00
return ret < 0 ? ret : - EIO ;
2015-07-20 16:49:06 -07:00
length = get_unaligned_le16 ( & resp_data [ PIP_RESP_LENGTH_OFFSET ] ) ;
2015-01-17 18:49:37 -08:00
max_output_len = get_unaligned_le16 ( & resp_data [ 16 ] ) ;
2015-07-20 16:49:06 -07:00
if ( length = = PIP_RESP_LENGTH_SIZE ) {
if ( reg_data [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_HID_BL_REPORT_ID ) {
2015-01-17 18:49:37 -08:00
/*
* BL mode HID Description has been previously
* read out .
*/
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_BL ;
} else {
/*
* APP mode HID Description has been previously
* read out .
*/
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_APP ;
}
2015-07-20 16:49:06 -07:00
} else if ( length = = PIP_HID_DESCRIPTOR_SIZE & &
resp_data [ 2 ] = = PIP_HID_BL_REPORT_ID & &
2015-01-17 18:49:37 -08:00
max_output_len = = GEN5_BL_MAX_OUTPUT_LENGTH ) {
/* BL mode HID Description read. */
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_BL ;
2015-07-20 16:49:06 -07:00
} else if ( length = = PIP_HID_DESCRIPTOR_SIZE & &
( resp_data [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_HID_APP_REPORT_ID ) & &
2015-01-17 18:49:37 -08:00
max_output_len = = GEN5_APP_MAX_OUTPUT_LENGTH ) {
/* APP mode HID Description read. */
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_APP ;
} else {
/* Should not happen!!! */
cyapa - > state = CYAPA_STATE_NO_DEVICE ;
}
return 0 ;
}
static int gen5_report_data_header_parse ( struct cyapa * cyapa , u8 * reg_data )
{
int length ;
2015-07-20 16:49:06 -07:00
length = get_unaligned_le16 ( & reg_data [ PIP_RESP_LENGTH_OFFSET ] ) ;
switch ( reg_data [ PIP_RESP_REPORT_ID_OFFSET ] ) {
case PIP_TOUCH_REPORT_ID :
if ( length < PIP_TOUCH_REPORT_HEAD_SIZE | |
length > PIP_TOUCH_REPORT_MAX_SIZE )
2015-01-17 18:49:37 -08:00
return - EINVAL ;
break ;
2015-07-20 16:49:06 -07:00
case PIP_BTN_REPORT_ID :
2015-01-17 18:49:37 -08:00
case GEN5_OLD_PUSH_BTN_REPORT_ID :
2015-07-20 16:49:06 -07:00
case PIP_PUSH_BTN_REPORT_ID :
if ( length < PIP_BTN_REPORT_HEAD_SIZE | |
length > PIP_BTN_REPORT_MAX_SIZE )
2015-01-17 18:49:37 -08:00
return - EINVAL ;
break ;
2015-07-20 16:49:06 -07:00
case PIP_WAKEUP_EVENT_REPORT_ID :
if ( length ! = PIP_WAKEUP_EVENT_SIZE )
2015-01-17 18:49:37 -08:00
return - EINVAL ;
break ;
default :
return - EINVAL ;
}
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_APP ;
return 0 ;
}
static int gen5_cmd_resp_header_parse ( struct cyapa * cyapa , u8 * reg_data )
{
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2015-01-17 18:49:37 -08:00
int length ;
int ret ;
/*
* Must read report data through out ,
* otherwise Gen5 trackpad cannot response next command
* or report any touch or button data .
*/
2015-07-20 16:49:06 -07:00
length = get_unaligned_le16 ( & reg_data [ PIP_RESP_LENGTH_OFFSET ] ) ;
ret = cyapa_i2c_pip_read ( cyapa , pip - > empty_buf , length ) ;
2015-01-17 18:49:37 -08:00
if ( ret ! = length )
return ret < 0 ? ret : - EIO ;
2015-07-20 16:49:06 -07:00
if ( length = = PIP_RESP_LENGTH_SIZE ) {
2015-01-17 18:49:37 -08:00
/* Previous command has read the data through out. */
2015-07-20 16:49:06 -07:00
if ( reg_data [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_BL_RESP_REPORT_ID ) {
2015-01-17 18:49:37 -08:00
/* Gen5 BL command response data detected */
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_BL ;
} else {
/* Gen5 APP command response data detected */
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_APP ;
}
2015-07-20 16:49:06 -07:00
} else if ( ( pip - > empty_buf [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_BL_RESP_REPORT_ID ) & &
( pip - > empty_buf [ PIP_RESP_RSVD_OFFSET ] = =
PIP_RESP_RSVD_KEY ) & &
( pip - > empty_buf [ PIP_RESP_BL_SOP_OFFSET ] = =
PIP_SOP_KEY ) & &
( pip - > empty_buf [ length - 1 ] = =
PIP_EOP_KEY ) ) {
2015-01-17 18:49:37 -08:00
/* Gen5 BL command response data detected */
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_BL ;
2015-07-20 16:49:06 -07:00
} else if ( pip - > empty_buf [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_APP_RESP_REPORT_ID & &
pip - > empty_buf [ PIP_RESP_RSVD_OFFSET ] = =
PIP_RESP_RSVD_KEY ) {
2015-01-17 18:49:37 -08:00
/* Gen5 APP command response data detected */
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_APP ;
} else {
/* Should not happen!!! */
cyapa - > state = CYAPA_STATE_NO_DEVICE ;
}
return 0 ;
}
static int cyapa_gen5_state_parse ( struct cyapa * cyapa , u8 * reg_data , int len )
{
int length ;
if ( ! reg_data | | len < 3 )
return - EINVAL ;
cyapa - > state = CYAPA_STATE_NO_DEVICE ;
/* Parse based on Gen5 characteristic registers and bits */
2015-07-20 16:49:06 -07:00
length = get_unaligned_le16 ( & reg_data [ PIP_RESP_LENGTH_OFFSET ] ) ;
if ( length = = 0 | | length = = PIP_RESP_LENGTH_SIZE ) {
2015-01-17 18:49:37 -08:00
gen5_idle_state_parse ( cyapa ) ;
2015-07-20 16:49:06 -07:00
} else if ( length = = PIP_HID_DESCRIPTOR_SIZE & &
( reg_data [ 2 ] = = PIP_HID_BL_REPORT_ID | |
reg_data [ 2 ] = = PIP_HID_APP_REPORT_ID ) ) {
2015-01-17 18:49:37 -08:00
gen5_hid_description_header_parse ( cyapa , reg_data ) ;
} else if ( ( length = = GEN5_APP_REPORT_DESCRIPTOR_SIZE | |
length = = GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE ) & &
reg_data [ 2 ] = = GEN5_APP_REPORT_DESCRIPTOR_ID ) {
/* 0xEE 0x00 0xF6 is Gen5 APP report description header. */
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_APP ;
} else if ( length = = GEN5_BL_REPORT_DESCRIPTOR_SIZE & &
reg_data [ 2 ] = = GEN5_BL_REPORT_DESCRIPTOR_ID ) {
2015-07-20 16:49:06 -07:00
/* 0x1D 0x00 0xFE is Gen5 BL report descriptor header. */
2015-01-17 18:49:37 -08:00
cyapa - > gen = CYAPA_GEN5 ;
cyapa - > state = CYAPA_STATE_GEN5_BL ;
2015-07-20 16:49:06 -07:00
} else if ( reg_data [ 2 ] = = PIP_TOUCH_REPORT_ID | |
reg_data [ 2 ] = = PIP_BTN_REPORT_ID | |
2015-01-17 18:49:37 -08:00
reg_data [ 2 ] = = GEN5_OLD_PUSH_BTN_REPORT_ID | |
2015-07-20 16:49:06 -07:00
reg_data [ 2 ] = = PIP_PUSH_BTN_REPORT_ID | |
reg_data [ 2 ] = = PIP_WAKEUP_EVENT_REPORT_ID ) {
2015-01-17 18:49:37 -08:00
gen5_report_data_header_parse ( cyapa , reg_data ) ;
2015-07-20 16:49:06 -07:00
} else if ( reg_data [ 2 ] = = PIP_BL_RESP_REPORT_ID | |
reg_data [ 2 ] = = PIP_APP_RESP_REPORT_ID ) {
2015-01-17 18:49:37 -08:00
gen5_cmd_resp_header_parse ( cyapa , reg_data ) ;
}
if ( cyapa - > gen = = CYAPA_GEN5 ) {
/*
* Must read the content ( e . g . : report description and so on )
* from trackpad device throughout . Otherwise ,
* Gen5 trackpad cannot response to next command or
* report any touch or button data later .
*/
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
if ( cyapa - > state = = CYAPA_STATE_GEN5_APP | |
cyapa - > state = = CYAPA_STATE_GEN5_BL )
return 0 ;
}
return - EAGAIN ;
}
2015-07-20 16:49:06 -07:00
static struct cyapa_tsg_bin_image_data_record *
cyapa_get_image_record_data_num ( const struct firmware * fw ,
int * record_num )
{
int head_size ;
head_size = fw - > data [ 0 ] + 1 ;
* record_num = ( fw - > size - head_size ) /
sizeof ( struct cyapa_tsg_bin_image_data_record ) ;
return ( struct cyapa_tsg_bin_image_data_record * ) & fw - > data [ head_size ] ;
}
int cyapa_pip_bl_initiate ( struct cyapa * cyapa , const struct firmware * fw )
2015-01-17 22:14:48 -08:00
{
2015-07-20 16:49:06 -07:00
struct cyapa_tsg_bin_image_data_record * image_records ;
struct pip_bl_cmd_head * bl_cmd_head ;
struct pip_bl_packet_start * bl_packet_start ;
struct pip_bl_initiate_cmd_data * cmd_data ;
struct pip_bl_packet_end * bl_packet_end ;
2015-01-17 22:14:48 -08:00
u8 cmd [ CYAPA_TSG_MAX_CMD_SIZE ] ;
int cmd_len ;
u16 cmd_data_len ;
u16 cmd_crc = 0 ;
u16 meta_data_crc = 0 ;
u8 resp_data [ 11 ] ;
int resp_len ;
int records_num ;
u8 * data ;
int error ;
/* Try to dump all buffered report data before any send command. */
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
memset ( cmd , 0 , CYAPA_TSG_MAX_CMD_SIZE ) ;
2015-07-20 16:49:06 -07:00
bl_cmd_head = ( struct pip_bl_cmd_head * ) cmd ;
2015-01-17 22:14:48 -08:00
cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE ;
2015-07-20 16:49:06 -07:00
cmd_len = sizeof ( struct pip_bl_cmd_head ) + cmd_data_len +
sizeof ( struct pip_bl_packet_end ) ;
2015-01-17 22:14:48 -08:00
2015-07-20 16:49:06 -07:00
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & bl_cmd_head - > addr ) ;
2015-01-17 22:14:48 -08:00
put_unaligned_le16 ( cmd_len - 2 , & bl_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
bl_cmd_head - > report_id = PIP_BL_CMD_REPORT_ID ;
2015-01-17 22:14:48 -08:00
bl_packet_start = & bl_cmd_head - > packet_start ;
2015-07-20 16:49:06 -07:00
bl_packet_start - > sop = PIP_SOP_KEY ;
bl_packet_start - > cmd_code = PIP_BL_CMD_INITIATE_BL ;
2015-01-17 22:14:48 -08:00
/* 8 key bytes and 128 bytes block size */
put_unaligned_le16 ( cmd_data_len , & bl_packet_start - > data_length ) ;
2015-07-20 16:49:06 -07:00
cmd_data = ( struct pip_bl_initiate_cmd_data * ) bl_cmd_head - > data ;
memcpy ( cmd_data - > key , cyapa_pip_bl_cmd_key , CYAPA_TSG_BL_KEY_SIZE ) ;
image_records = cyapa_get_image_record_data_num ( fw , & records_num ) ;
2015-01-17 22:14:48 -08:00
/* APP_INTEGRITY row is always the last row block */
2015-07-20 16:49:06 -07:00
data = image_records [ records_num - 1 ] . record_data ;
2015-01-17 22:14:48 -08:00
memcpy ( cmd_data - > metadata_raw_parameter , data ,
CYAPA_TSG_FLASH_MAP_METADATA_SIZE ) ;
meta_data_crc = crc_itu_t ( 0xffff , cmd_data - > metadata_raw_parameter ,
CYAPA_TSG_FLASH_MAP_METADATA_SIZE ) ;
put_unaligned_le16 ( meta_data_crc , & cmd_data - > metadata_crc ) ;
2015-07-20 16:49:06 -07:00
bl_packet_end = ( struct pip_bl_packet_end * ) ( bl_cmd_head - > data +
2015-01-17 22:14:48 -08:00
cmd_data_len ) ;
cmd_crc = crc_itu_t ( 0xffff , ( u8 * ) bl_packet_start ,
2015-07-20 16:49:06 -07:00
sizeof ( struct pip_bl_packet_start ) + cmd_data_len ) ;
2015-01-17 22:14:48 -08:00
put_unaligned_le16 ( cmd_crc , & bl_packet_end - > crc ) ;
2015-07-20 16:49:06 -07:00
bl_packet_end - > eop = PIP_EOP_KEY ;
2015-01-17 22:14:48 -08:00
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , cmd_len ,
resp_data , & resp_len , 12000 ,
2015-07-20 16:49:06 -07:00
cyapa_sort_tsg_pip_bl_resp_data , true ) ;
if ( error | | resp_len ! = PIP_BL_INITIATE_RESP_LEN | |
resp_data [ 2 ] ! = PIP_BL_RESP_REPORT_ID | |
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) )
2015-01-17 22:14:48 -08:00
return error ? error : - EAGAIN ;
return 0 ;
}
2015-07-20 16:49:06 -07:00
static bool cyapa_sort_pip_bl_exit_data ( struct cyapa * cyapa , u8 * buf , int len )
2015-01-17 18:49:37 -08:00
{
2015-07-20 16:49:06 -07:00
if ( buf = = NULL | | len < PIP_RESP_LENGTH_SIZE )
2015-01-17 18:49:37 -08:00
return false ;
if ( buf [ 0 ] = = 0 & & buf [ 1 ] = = 0 )
return true ;
/* Exit bootloader failed for some reason. */
2015-07-20 16:49:06 -07:00
if ( len = = PIP_BL_FAIL_EXIT_RESP_LEN & &
buf [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_BL_RESP_REPORT_ID & &
buf [ PIP_RESP_RSVD_OFFSET ] = = PIP_RESP_RSVD_KEY & &
buf [ PIP_RESP_BL_SOP_OFFSET ] = = PIP_SOP_KEY & &
buf [ 10 ] = = PIP_EOP_KEY )
2015-01-17 18:49:37 -08:00
return true ;
return false ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_bl_exit ( struct cyapa * cyapa )
2015-01-17 18:49:37 -08:00
{
u8 bl_gen5_bl_exit [ ] = { 0x04 , 0x00 ,
0x0B , 0x00 , 0x40 , 0x00 , 0x01 , 0x3b , 0x00 , 0x00 ,
0x20 , 0xc7 , 0x17
} ;
u8 resp_data [ 11 ] ;
int resp_len ;
int error ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
bl_gen5_bl_exit , sizeof ( bl_gen5_bl_exit ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
5000 , cyapa_sort_pip_bl_exit_data , false ) ;
2015-01-17 18:49:37 -08:00
if ( error )
return error ;
2015-07-20 16:49:06 -07:00
if ( resp_len = = PIP_BL_FAIL_EXIT_RESP_LEN | |
resp_data [ PIP_RESP_REPORT_ID_OFFSET ] = =
PIP_BL_RESP_REPORT_ID )
2015-01-17 18:49:37 -08:00
return - EAGAIN ;
if ( resp_data [ 0 ] = = 0x00 & & resp_data [ 1 ] = = 0x00 )
return 0 ;
return - ENODEV ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_bl_enter ( struct cyapa * cyapa )
2015-01-17 22:14:48 -08:00
{
u8 cmd [ ] = { 0x04 , 0x00 , 0x05 , 0x00 , 0x2F , 0x00 , 0x01 } ;
u8 resp_data [ 2 ] ;
int resp_len ;
int error ;
error = cyapa_poll_state ( cyapa , 500 ) ;
if ( error < 0 )
return error ;
2015-07-20 16:49:06 -07:00
/* Already in bootloader mode, Skipping exit. */
if ( cyapa_is_pip_bl_mode ( cyapa ) )
2015-01-17 22:14:48 -08:00
return 0 ;
2015-07-20 16:49:06 -07:00
else if ( ! cyapa_is_pip_app_mode ( cyapa ) )
return - EINVAL ;
2015-01-17 22:14:48 -08:00
/* Try to dump all buffered report data before any send command. */
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
/*
* Send bootloader enter command to trackpad device ,
* after enter bootloader , the response data is two bytes of 0x00 0x00 .
*/
resp_len = sizeof ( resp_data ) ;
memset ( resp_data , 0 , resp_len ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
5000 , cyapa_sort_pip_application_launch_data ,
2015-01-17 22:14:48 -08:00
true ) ;
if ( error | | resp_data [ 0 ] ! = 0x00 | | resp_data [ 1 ] ! = 0x00 )
return error < 0 ? error : - EAGAIN ;
cyapa - > operational = false ;
2015-07-20 16:49:06 -07:00
if ( cyapa - > gen = = CYAPA_GEN5 )
cyapa - > state = CYAPA_STATE_GEN5_BL ;
2015-07-20 16:53:30 -07:00
else if ( cyapa - > gen = = CYAPA_GEN6 )
cyapa - > state = CYAPA_STATE_GEN6_BL ;
return 0 ;
}
static int cyapa_pip_fw_head_check ( struct cyapa * cyapa ,
struct cyapa_tsg_bin_image_head * image_head )
{
if ( image_head - > head_size ! = 0x0C & & image_head - > head_size ! = 0x12 )
return - EINVAL ;
switch ( cyapa - > gen ) {
case CYAPA_GEN6 :
if ( image_head - > family_id ! = 0x9B | |
image_head - > silicon_id_hi ! = 0x0B )
return - EINVAL ;
break ;
case CYAPA_GEN5 :
/* Gen5 without proximity support. */
if ( cyapa - > platform_ver < 2 ) {
if ( image_head - > head_size = = 0x0C )
break ;
return - EINVAL ;
}
if ( image_head - > family_id ! = 0x91 | |
image_head - > silicon_id_hi ! = 0x02 )
return - EINVAL ;
break ;
default :
return - EINVAL ;
}
2015-01-17 22:14:48 -08:00
return 0 ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_check_fw ( struct cyapa * cyapa , const struct firmware * fw )
2015-01-17 22:14:48 -08:00
{
struct device * dev = & cyapa - > client - > dev ;
2015-07-20 16:49:06 -07:00
struct cyapa_tsg_bin_image_data_record * image_records ;
2015-01-19 15:59:31 -08:00
const struct cyapa_tsg_bin_image_data_record * app_integrity ;
2015-07-20 16:49:06 -07:00
const struct tsg_bl_metadata_row_params * metadata ;
int flash_records_count ;
2015-01-19 15:59:31 -08:00
u32 fw_app_start , fw_upgrade_start ;
u16 fw_app_len , fw_upgrade_len ;
u16 app_crc ;
u16 app_integrity_crc ;
2015-01-17 22:14:48 -08:00
int i ;
2015-07-20 16:53:30 -07:00
/* Verify the firmware image not miss-used for Gen5 and Gen6. */
if ( cyapa_pip_fw_head_check ( cyapa ,
( struct cyapa_tsg_bin_image_head * ) fw - > data ) ) {
dev_err ( dev , " %s: firmware image not match TP device. \n " ,
__func__ ) ;
return - EINVAL ;
}
2015-07-20 16:49:06 -07:00
image_records =
cyapa_get_image_record_data_num ( fw , & flash_records_count ) ;
2015-01-17 22:14:48 -08:00
2015-01-19 15:59:31 -08:00
/*
* APP_INTEGRITY row is always the last row block ,
* and the row id must be 0x01ff .
*/
2015-07-20 16:49:06 -07:00
app_integrity = & image_records [ flash_records_count - 1 ] ;
2015-01-19 15:59:31 -08:00
if ( app_integrity - > flash_array_id ! = 0x00 | |
get_unaligned_be16 ( & app_integrity - > row_number ) ! = 0x01ff ) {
2015-01-17 22:14:48 -08:00
dev_err ( dev , " %s: invalid app_integrity data. \n " , __func__ ) ;
return - EINVAL ;
}
2015-01-19 15:59:31 -08:00
metadata = ( const void * ) app_integrity - > record_data ;
2015-01-17 22:14:48 -08:00
/* Verify app_integrity crc */
2015-01-19 15:59:31 -08:00
app_integrity_crc = crc_itu_t ( 0xffff , app_integrity - > record_data ,
CYAPA_TSG_APP_INTEGRITY_SIZE ) ;
if ( app_integrity_crc ! = get_unaligned_le16 ( & metadata - > metadata_crc ) ) {
2015-01-17 22:14:48 -08:00
dev_err ( dev , " %s: invalid app_integrity crc. \n " , __func__ ) ;
return - EINVAL ;
}
2015-01-19 15:59:31 -08:00
fw_app_start = get_unaligned_le32 ( & metadata - > app_start ) ;
fw_app_len = get_unaligned_le16 ( & metadata - > app_len ) ;
fw_upgrade_start = get_unaligned_le32 ( & metadata - > upgrade_start ) ;
fw_upgrade_len = get_unaligned_le16 ( & metadata - > upgrade_len ) ;
if ( fw_app_start % CYAPA_TSG_FW_ROW_SIZE | |
fw_app_len % CYAPA_TSG_FW_ROW_SIZE | |
fw_upgrade_start % CYAPA_TSG_FW_ROW_SIZE | |
fw_upgrade_len % CYAPA_TSG_FW_ROW_SIZE ) {
dev_err ( dev , " %s: invalid image alignment. \n " , __func__ ) ;
return - EINVAL ;
}
2015-07-20 16:49:06 -07:00
/* Verify application image CRC. */
2015-01-19 15:59:31 -08:00
app_crc = 0xffffU ;
for ( i = 0 ; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE ; i + + ) {
2015-07-20 16:49:06 -07:00
const u8 * data = image_records [ i ] . record_data ;
2015-01-17 22:14:48 -08:00
app_crc = crc_itu_t ( app_crc , data , CYAPA_TSG_FW_ROW_SIZE ) ;
}
2015-01-19 15:59:31 -08:00
if ( app_crc ! = get_unaligned_le16 ( & metadata - > app_crc ) ) {
2015-01-17 22:14:48 -08:00
dev_err ( dev , " %s: invalid firmware app crc check. \n " , __func__ ) ;
return - EINVAL ;
}
return 0 ;
}
2015-07-20 16:49:06 -07:00
static int cyapa_pip_write_fw_block ( struct cyapa * cyapa ,
2015-01-17 22:14:48 -08:00
struct cyapa_tsg_bin_image_data_record * flash_record )
{
2015-07-20 16:49:06 -07:00
struct pip_bl_cmd_head * bl_cmd_head ;
struct pip_bl_packet_start * bl_packet_start ;
struct tsg_bl_flash_row_head * flash_row_head ;
struct pip_bl_packet_end * bl_packet_end ;
2015-01-17 22:14:48 -08:00
u8 cmd [ CYAPA_TSG_MAX_CMD_SIZE ] ;
u16 cmd_len ;
u8 flash_array_id ;
u16 flash_row_id ;
u16 record_len ;
u8 * record_data ;
u16 data_len ;
u16 crc ;
u8 resp_data [ 11 ] ;
int resp_len ;
int error ;
flash_array_id = flash_record - > flash_array_id ;
flash_row_id = get_unaligned_be16 ( & flash_record - > row_number ) ;
record_len = get_unaligned_be16 ( & flash_record - > record_len ) ;
record_data = flash_record - > record_data ;
memset ( cmd , 0 , CYAPA_TSG_MAX_CMD_SIZE ) ;
2015-07-20 16:49:06 -07:00
bl_cmd_head = ( struct pip_bl_cmd_head * ) cmd ;
2015-01-17 22:14:48 -08:00
bl_packet_start = & bl_cmd_head - > packet_start ;
2015-07-20 16:49:06 -07:00
cmd_len = sizeof ( struct pip_bl_cmd_head ) +
sizeof ( struct tsg_bl_flash_row_head ) +
2015-01-17 22:14:48 -08:00
CYAPA_TSG_FLASH_MAP_BLOCK_SIZE +
2015-07-20 16:49:06 -07:00
sizeof ( struct pip_bl_packet_end ) ;
2015-01-17 22:14:48 -08:00
2015-07-20 16:49:06 -07:00
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & bl_cmd_head - > addr ) ;
2015-01-17 22:14:48 -08:00
/* Don't include 2 bytes register address */
put_unaligned_le16 ( cmd_len - 2 , & bl_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
bl_cmd_head - > report_id = PIP_BL_CMD_REPORT_ID ;
bl_packet_start - > sop = PIP_SOP_KEY ;
bl_packet_start - > cmd_code = PIP_BL_CMD_PROGRAM_VERIFY_ROW ;
2015-01-17 22:14:48 -08:00
/* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
2015-07-20 16:49:06 -07:00
data_len = sizeof ( struct tsg_bl_flash_row_head ) + record_len ;
2015-01-17 22:14:48 -08:00
put_unaligned_le16 ( data_len , & bl_packet_start - > data_length ) ;
2015-07-20 16:49:06 -07:00
flash_row_head = ( struct tsg_bl_flash_row_head * ) bl_cmd_head - > data ;
2015-01-17 22:14:48 -08:00
flash_row_head - > flash_array_id = flash_array_id ;
put_unaligned_le16 ( flash_row_id , & flash_row_head - > flash_row_id ) ;
memcpy ( flash_row_head - > flash_data , record_data , record_len ) ;
2015-07-20 16:49:06 -07:00
bl_packet_end = ( struct pip_bl_packet_end * ) ( bl_cmd_head - > data +
2015-01-17 22:14:48 -08:00
data_len ) ;
crc = crc_itu_t ( 0xffff , ( u8 * ) bl_packet_start ,
2015-07-20 16:49:06 -07:00
sizeof ( struct pip_bl_packet_start ) + data_len ) ;
2015-01-17 22:14:48 -08:00
put_unaligned_le16 ( crc , & bl_packet_end - > crc ) ;
2015-07-20 16:49:06 -07:00
bl_packet_end - > eop = PIP_EOP_KEY ;
2015-01-17 22:14:48 -08:00
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa , cmd , cmd_len ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_bl_resp_data , true ) ;
if ( error | | resp_len ! = PIP_BL_BLOCK_WRITE_RESP_LEN | |
resp_data [ 2 ] ! = PIP_BL_RESP_REPORT_ID | |
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) )
2015-01-17 22:14:48 -08:00
return error < 0 ? error : - EAGAIN ;
return 0 ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_do_fw_update ( struct cyapa * cyapa ,
2015-01-17 22:14:48 -08:00
const struct firmware * fw )
{
struct device * dev = & cyapa - > client - > dev ;
2015-07-20 16:49:06 -07:00
struct cyapa_tsg_bin_image_data_record * image_records ;
2015-01-17 22:14:48 -08:00
int flash_records_count ;
int i ;
int error ;
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
2015-07-20 16:49:06 -07:00
image_records =
cyapa_get_image_record_data_num ( fw , & flash_records_count ) ;
2015-01-17 22:14:48 -08:00
/*
* The last flash row 0x01ff has been written through bl_initiate
* command , so DO NOT write flash 0x01ff to trackpad device .
*/
for ( i = 0 ; i < ( flash_records_count - 1 ) ; i + + ) {
2015-07-20 16:49:06 -07:00
error = cyapa_pip_write_fw_block ( cyapa , & image_records [ i ] ) ;
2015-01-17 22:14:48 -08:00
if ( error ) {
dev_err ( dev , " %s: Gen5 FW update aborted: %d \n " ,
__func__ , error ) ;
return error ;
}
}
return 0 ;
}
2015-01-17 18:49:37 -08:00
static int cyapa_gen5_change_power_state ( struct cyapa * cyapa , u8 power_state )
{
u8 cmd [ 8 ] = { 0x04 , 0x00 , 0x06 , 0x00 , 0x2f , 0x00 , 0x08 , 0x01 } ;
u8 resp_data [ 6 ] ;
int resp_len ;
int error ;
cmd [ 7 ] = power_state ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa , cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , false ) ;
2015-01-17 18:49:37 -08:00
if ( error | | ! VALID_CMD_RESP_HEADER ( resp_data , 0x08 ) | |
2015-07-20 16:49:06 -07:00
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) )
2015-01-17 18:49:37 -08:00
return error < 0 ? error : - EINVAL ;
return 0 ;
}
static int cyapa_gen5_set_interval_time ( struct cyapa * cyapa ,
u8 parameter_id , u16 interval_time )
{
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head * app_cmd_head ;
2015-01-17 18:49:37 -08:00
struct gen5_app_set_parameter_data * parameter_data ;
u8 cmd [ CYAPA_TSG_MAX_CMD_SIZE ] ;
int cmd_len ;
u8 resp_data [ 7 ] ;
int resp_len ;
u8 parameter_size ;
int error ;
memset ( cmd , 0 , CYAPA_TSG_MAX_CMD_SIZE ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head = ( struct pip_app_cmd_head * ) cmd ;
2015-01-17 18:49:37 -08:00
parameter_data = ( struct gen5_app_set_parameter_data * )
app_cmd_head - > parameter_data ;
2015-07-20 16:49:06 -07:00
cmd_len = sizeof ( struct pip_app_cmd_head ) +
2015-01-17 18:49:37 -08:00
sizeof ( struct gen5_app_set_parameter_data ) ;
switch ( parameter_id ) {
case GEN5_PARAMETER_ACT_INTERVL_ID :
parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE ;
break ;
case GEN5_PARAMETER_ACT_LFT_INTERVL_ID :
parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE ;
break ;
case GEN5_PARAMETER_LP_INTRVL_ID :
parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE ;
break ;
default :
return - EINVAL ;
}
2015-07-20 16:49:06 -07:00
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & app_cmd_head - > addr ) ;
2015-01-17 18:49:37 -08:00
/*
* Don ' t include unused parameter value bytes and
* 2 bytes register address .
*/
put_unaligned_le16 ( cmd_len - ( 4 - parameter_size ) - 2 ,
& app_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head - > report_id = PIP_APP_CMD_REPORT_ID ;
2015-01-17 18:49:37 -08:00
app_cmd_head - > cmd_code = GEN5_CMD_SET_PARAMETER ;
parameter_data - > parameter_id = parameter_id ;
parameter_data - > parameter_size = parameter_size ;
put_unaligned_le32 ( ( u32 ) interval_time , & parameter_data - > value ) ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa , cmd , cmd_len ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , false ) ;
2015-01-17 18:49:37 -08:00
if ( error | | resp_data [ 5 ] ! = parameter_id | |
resp_data [ 6 ] ! = parameter_size | |
! VALID_CMD_RESP_HEADER ( resp_data , GEN5_CMD_SET_PARAMETER ) )
return error < 0 ? error : - EINVAL ;
return 0 ;
}
static int cyapa_gen5_get_interval_time ( struct cyapa * cyapa ,
u8 parameter_id , u16 * interval_time )
{
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head * app_cmd_head ;
2015-01-17 18:49:37 -08:00
struct gen5_app_get_parameter_data * parameter_data ;
u8 cmd [ CYAPA_TSG_MAX_CMD_SIZE ] ;
int cmd_len ;
u8 resp_data [ 11 ] ;
int resp_len ;
u8 parameter_size ;
u16 mask , i ;
int error ;
memset ( cmd , 0 , CYAPA_TSG_MAX_CMD_SIZE ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head = ( struct pip_app_cmd_head * ) cmd ;
2015-01-17 18:49:37 -08:00
parameter_data = ( struct gen5_app_get_parameter_data * )
app_cmd_head - > parameter_data ;
2015-07-20 16:49:06 -07:00
cmd_len = sizeof ( struct pip_app_cmd_head ) +
2015-01-17 18:49:37 -08:00
sizeof ( struct gen5_app_get_parameter_data ) ;
* interval_time = 0 ;
switch ( parameter_id ) {
case GEN5_PARAMETER_ACT_INTERVL_ID :
parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE ;
break ;
case GEN5_PARAMETER_ACT_LFT_INTERVL_ID :
parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE ;
break ;
case GEN5_PARAMETER_LP_INTRVL_ID :
parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE ;
break ;
default :
return - EINVAL ;
}
2015-07-20 16:49:06 -07:00
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & app_cmd_head - > addr ) ;
2015-01-17 18:49:37 -08:00
/* Don't include 2 bytes register address */
put_unaligned_le16 ( cmd_len - 2 , & app_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head - > report_id = PIP_APP_CMD_REPORT_ID ;
2015-01-17 18:49:37 -08:00
app_cmd_head - > cmd_code = GEN5_CMD_GET_PARAMETER ;
parameter_data - > parameter_id = parameter_id ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa , cmd , cmd_len ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , false ) ;
2015-01-17 18:49:37 -08:00
if ( error | | resp_data [ 5 ] ! = parameter_id | | resp_data [ 6 ] = = 0 | |
! VALID_CMD_RESP_HEADER ( resp_data , GEN5_CMD_GET_PARAMETER ) )
return error < 0 ? error : - EINVAL ;
mask = 0 ;
for ( i = 0 ; i < parameter_size ; i + + )
mask | = ( 0xff < < ( i * 8 ) ) ;
* interval_time = get_unaligned_le16 ( & resp_data [ 7 ] ) & mask ;
return 0 ;
}
static int cyapa_gen5_disable_pip_report ( struct cyapa * cyapa )
{
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head * app_cmd_head ;
2015-01-17 18:49:37 -08:00
u8 cmd [ 10 ] ;
u8 resp_data [ 7 ] ;
int resp_len ;
int error ;
memset ( cmd , 0 , sizeof ( cmd ) ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head = ( struct pip_app_cmd_head * ) cmd ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & app_cmd_head - > addr ) ;
2015-01-17 18:49:37 -08:00
put_unaligned_le16 ( sizeof ( cmd ) - 2 , & app_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head - > report_id = PIP_APP_CMD_REPORT_ID ;
2015-01-17 18:49:37 -08:00
app_cmd_head - > cmd_code = GEN5_CMD_SET_PARAMETER ;
app_cmd_head - > parameter_data [ 0 ] = GEN5_PARAMETER_DISABLE_PIP_REPORT ;
app_cmd_head - > parameter_data [ 1 ] = 0x01 ;
app_cmd_head - > parameter_data [ 2 ] = 0x01 ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa , cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , false ) ;
2015-01-17 18:49:37 -08:00
if ( error | | resp_data [ 5 ] ! = GEN5_PARAMETER_DISABLE_PIP_REPORT | |
! VALID_CMD_RESP_HEADER ( resp_data , GEN5_CMD_SET_PARAMETER ) | |
resp_data [ 6 ] ! = 0x01 )
return error < 0 ? error : - EINVAL ;
return 0 ;
}
2015-07-20 16:57:53 -07:00
int cyapa_pip_set_proximity ( struct cyapa * cyapa , bool enable )
{
u8 cmd [ ] = { 0x04 , 0x00 , 0x06 , 0x00 , 0x2f , 0x00 , PIP_SET_PROXIMITY ,
( u8 ) ! ! enable
} ;
u8 resp_data [ 6 ] ;
int resp_len ;
int error ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa , cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
500 , cyapa_sort_tsg_pip_app_resp_data , false ) ;
if ( error | | ! VALID_CMD_RESP_HEADER ( resp_data , PIP_SET_PROXIMITY ) | |
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) ) {
error = ( error = = - ETIMEDOUT ) ? - EOPNOTSUPP : error ;
return error < 0 ? error : - EINVAL ;
}
return 0 ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_deep_sleep ( struct cyapa * cyapa , u8 state )
2015-01-17 18:49:37 -08:00
{
u8 cmd [ ] = { 0x05 , 0x00 , 0x00 , 0x08 } ;
u8 resp_data [ 5 ] ;
int resp_len ;
int error ;
2015-07-20 16:49:06 -07:00
cmd [ 2 ] = state & PIP_DEEP_SLEEP_STATE_MASK ;
2015-01-17 18:49:37 -08:00
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa , cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_pip_deep_sleep_data , false ) ;
if ( error | | ( ( resp_data [ 3 ] & PIP_DEEP_SLEEP_STATE_MASK ) ! = state ) )
2015-01-17 18:49:37 -08:00
return - EINVAL ;
return 0 ;
}
static int cyapa_gen5_set_power_mode ( struct cyapa * cyapa ,
2016-03-04 11:23:09 -08:00
u8 power_mode , u16 sleep_time , enum cyapa_pm_stage pm_stage )
2015-01-17 18:49:37 -08:00
{
struct device * dev = & cyapa - > client - > dev ;
u8 power_state ;
2016-03-04 11:23:09 -08:00
int error = 0 ;
2015-01-17 18:49:37 -08:00
if ( cyapa - > state ! = CYAPA_STATE_GEN5_APP )
return 0 ;
2016-03-04 11:23:09 -08:00
cyapa_set_pip_pm_state ( cyapa , pm_stage ) ;
2015-07-20 16:49:06 -07:00
if ( PIP_DEV_GET_PWR_STATE ( cyapa ) = = UNINIT_PWR_MODE ) {
2015-01-17 18:49:37 -08:00
/*
* Assume TP in deep sleep mode when driver is loaded ,
* avoid driver unload and reload command IO issue caused by TP
* has been set into deep sleep mode when unloading .
*/
2015-07-20 16:49:06 -07:00
PIP_DEV_SET_PWR_STATE ( cyapa , PWR_MODE_OFF ) ;
2015-01-17 18:49:37 -08:00
}
2015-07-20 16:49:06 -07:00
if ( PIP_DEV_UNINIT_SLEEP_TIME ( cyapa ) & &
PIP_DEV_GET_PWR_STATE ( cyapa ) ! = PWR_MODE_OFF )
2015-01-17 18:49:37 -08:00
if ( cyapa_gen5_get_interval_time ( cyapa ,
GEN5_PARAMETER_LP_INTRVL_ID ,
& cyapa - > dev_sleep_time ) ! = 0 )
2015-07-20 16:49:06 -07:00
PIP_DEV_SET_SLEEP_TIME ( cyapa , UNINIT_SLEEP_TIME ) ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
if ( PIP_DEV_GET_PWR_STATE ( cyapa ) = = power_mode ) {
2015-01-17 18:49:37 -08:00
if ( power_mode = = PWR_MODE_OFF | |
power_mode = = PWR_MODE_FULL_ACTIVE | |
power_mode = = PWR_MODE_BTN_ONLY | |
2015-07-20 16:49:06 -07:00
PIP_DEV_GET_SLEEP_TIME ( cyapa ) = = sleep_time ) {
2015-01-17 18:49:37 -08:00
/* Has in correct power mode state, early return. */
2016-03-04 11:23:09 -08:00
goto out ;
2015-01-17 18:49:37 -08:00
}
}
if ( power_mode = = PWR_MODE_OFF ) {
2015-07-20 16:49:06 -07:00
error = cyapa_pip_deep_sleep ( cyapa , PIP_DEEP_SLEEP_STATE_OFF ) ;
2015-01-17 18:49:37 -08:00
if ( error ) {
dev_err ( dev , " enter deep sleep fail: %d \n " , error ) ;
2016-03-04 11:23:09 -08:00
goto out ;
2015-01-17 18:49:37 -08:00
}
2015-07-20 16:49:06 -07:00
PIP_DEV_SET_PWR_STATE ( cyapa , PWR_MODE_OFF ) ;
2016-03-04 11:23:09 -08:00
goto out ;
2015-01-17 18:49:37 -08:00
}
/*
* When trackpad in power off mode , it cannot change to other power
* state directly , must be wake up from sleep firstly , then
* continue to do next power sate change .
*/
2015-07-20 16:49:06 -07:00
if ( PIP_DEV_GET_PWR_STATE ( cyapa ) = = PWR_MODE_OFF ) {
error = cyapa_pip_deep_sleep ( cyapa , PIP_DEEP_SLEEP_STATE_ON ) ;
2015-01-17 18:49:37 -08:00
if ( error ) {
dev_err ( dev , " deep sleep wake fail: %d \n " , error ) ;
2016-03-04 11:23:09 -08:00
goto out ;
2015-01-17 18:49:37 -08:00
}
}
if ( power_mode = = PWR_MODE_FULL_ACTIVE ) {
error = cyapa_gen5_change_power_state ( cyapa ,
GEN5_POWER_STATE_ACTIVE ) ;
if ( error ) {
dev_err ( dev , " change to active fail: %d \n " , error ) ;
2016-03-04 11:23:09 -08:00
goto out ;
2015-01-17 18:49:37 -08:00
}
2015-07-20 16:49:06 -07:00
PIP_DEV_SET_PWR_STATE ( cyapa , PWR_MODE_FULL_ACTIVE ) ;
2015-01-17 18:49:37 -08:00
} else if ( power_mode = = PWR_MODE_BTN_ONLY ) {
error = cyapa_gen5_change_power_state ( cyapa ,
GEN5_POWER_STATE_BTN_ONLY ) ;
if ( error ) {
dev_err ( dev , " fail to button only mode: %d \n " , error ) ;
2016-03-04 11:23:09 -08:00
goto out ;
2015-01-17 18:49:37 -08:00
}
2015-07-20 16:49:06 -07:00
PIP_DEV_SET_PWR_STATE ( cyapa , PWR_MODE_BTN_ONLY ) ;
2015-01-17 18:49:37 -08:00
} else {
/*
* Continue to change power mode even failed to set
* interval time , it won ' t affect the power mode change .
* except the sleep interval time is not correct .
*/
2015-07-20 16:49:06 -07:00
if ( PIP_DEV_UNINIT_SLEEP_TIME ( cyapa ) | |
sleep_time ! = PIP_DEV_GET_SLEEP_TIME ( cyapa ) )
2015-01-17 18:49:37 -08:00
if ( cyapa_gen5_set_interval_time ( cyapa ,
GEN5_PARAMETER_LP_INTRVL_ID ,
sleep_time ) = = 0 )
2015-07-20 16:49:06 -07:00
PIP_DEV_SET_SLEEP_TIME ( cyapa , sleep_time ) ;
2015-01-17 18:49:37 -08:00
if ( sleep_time < = GEN5_POWER_READY_MAX_INTRVL_TIME )
power_state = GEN5_POWER_STATE_READY ;
else
power_state = GEN5_POWER_STATE_IDLE ;
error = cyapa_gen5_change_power_state ( cyapa , power_state ) ;
if ( error ) {
dev_err ( dev , " set power state to 0x%02x failed: %d \n " ,
power_state , error ) ;
2016-03-04 11:23:09 -08:00
goto out ;
2015-01-17 18:49:37 -08:00
}
/*
* Disable pip report for a little time , firmware will
* re - enable it automatically . It ' s used to fix the issue
* that trackpad unable to report signal to wake system up
* in the special situation that system is in suspending , and
* at the same time , user touch trackpad to wake system up .
2015-05-26 13:44:06 -07:00
* This function can avoid the data to be buffered when system
* is suspending which may cause interrupt line unable to be
2015-01-17 18:49:37 -08:00
* asserted again .
*/
2016-03-04 11:23:09 -08:00
if ( pm_stage = = CYAPA_PM_SUSPEND )
2015-07-20 17:09:59 -07:00
cyapa_gen5_disable_pip_report ( cyapa ) ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
PIP_DEV_SET_PWR_STATE ( cyapa ,
2015-01-17 18:49:37 -08:00
cyapa_sleep_time_to_pwr_cmd ( sleep_time ) ) ;
}
2016-03-04 11:23:09 -08:00
out :
cyapa_reset_pip_pm_state ( cyapa ) ;
return error ;
2015-01-17 18:49:37 -08:00
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_resume_scanning ( struct cyapa * cyapa )
2015-01-17 22:16:01 -08:00
{
u8 cmd [ ] = { 0x04 , 0x00 , 0x05 , 0x00 , 0x2f , 0x00 , 0x04 } ;
u8 resp_data [ 6 ] ;
int resp_len ;
int error ;
/* Try to dump all buffered data before doing command. */
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , true ) ;
2015-01-17 22:16:01 -08:00
if ( error | | ! VALID_CMD_RESP_HEADER ( resp_data , 0x04 ) )
return - EINVAL ;
/* Try to dump all buffered data when resuming scanning. */
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
return 0 ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_suspend_scanning ( struct cyapa * cyapa )
2015-01-17 22:16:01 -08:00
{
u8 cmd [ ] = { 0x04 , 0x00 , 0x05 , 0x00 , 0x2f , 0x00 , 0x03 } ;
u8 resp_data [ 6 ] ;
int resp_len ;
int error ;
/* Try to dump all buffered data before doing command. */
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , true ) ;
2015-01-17 22:16:01 -08:00
if ( error | | ! VALID_CMD_RESP_HEADER ( resp_data , 0x03 ) )
return - EINVAL ;
/* Try to dump all buffered data when suspending scanning. */
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
return 0 ;
}
2015-07-20 16:49:06 -07:00
static int cyapa_pip_calibrate_pwcs ( struct cyapa * cyapa ,
2015-01-17 22:18:14 -08:00
u8 calibrate_sensing_mode_type )
{
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head * app_cmd_head ;
2015-01-17 22:18:14 -08:00
u8 cmd [ 8 ] ;
u8 resp_data [ 6 ] ;
int resp_len ;
int error ;
/* Try to dump all buffered data before doing command. */
cyapa_empty_pip_output_data ( cyapa , NULL , NULL , NULL ) ;
memset ( cmd , 0 , sizeof ( cmd ) ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head = ( struct pip_app_cmd_head * ) cmd ;
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & app_cmd_head - > addr ) ;
2015-01-17 22:18:14 -08:00
put_unaligned_le16 ( sizeof ( cmd ) - 2 , & app_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head - > report_id = PIP_APP_CMD_REPORT_ID ;
app_cmd_head - > cmd_code = PIP_CMD_CALIBRATE ;
2015-01-17 22:18:14 -08:00
app_cmd_head - > parameter_data [ 0 ] = calibrate_sensing_mode_type ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
5000 , cyapa_sort_tsg_pip_app_resp_data , true ) ;
if ( error | | ! VALID_CMD_RESP_HEADER ( resp_data , PIP_CMD_CALIBRATE ) | |
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) )
2015-01-17 22:18:14 -08:00
return error < 0 ? error : - EAGAIN ;
return 0 ;
}
2015-07-20 16:49:06 -07:00
ssize_t cyapa_pip_do_calibrate ( struct device * dev ,
2015-01-17 22:18:14 -08:00
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct cyapa * cyapa = dev_get_drvdata ( dev ) ;
int error , calibrate_error ;
/* 1. Suspend Scanning*/
2015-07-20 16:49:06 -07:00
error = cyapa_pip_suspend_scanning ( cyapa ) ;
2015-01-17 22:18:14 -08:00
if ( error )
return error ;
/* 2. Do mutual capacitance fine calibrate. */
2015-07-20 16:49:06 -07:00
calibrate_error = cyapa_pip_calibrate_pwcs ( cyapa ,
PIP_SENSING_MODE_MUTUAL_CAP_FINE ) ;
2015-01-17 22:18:14 -08:00
if ( calibrate_error )
goto resume_scanning ;
/* 3. Do self capacitance calibrate. */
2015-07-20 16:49:06 -07:00
calibrate_error = cyapa_pip_calibrate_pwcs ( cyapa ,
PIP_SENSING_MODE_SELF_CAP ) ;
2015-01-17 22:18:14 -08:00
if ( calibrate_error )
goto resume_scanning ;
resume_scanning :
/* 4. Resume Scanning*/
2015-07-20 16:49:06 -07:00
error = cyapa_pip_resume_scanning ( cyapa ) ;
2015-01-17 22:18:14 -08:00
if ( error | | calibrate_error )
return error ? error : calibrate_error ;
return count ;
}
2015-01-17 22:16:01 -08:00
static s32 twos_complement_to_s32 ( s32 value , int num_bits )
{
if ( value > > ( num_bits - 1 ) )
value | = - 1 < < num_bits ;
return value ;
}
static s32 cyapa_parse_structure_data ( u8 data_format , u8 * buf , int buf_len )
{
int data_size ;
bool big_endian ;
bool unsigned_type ;
s32 value ;
data_size = ( data_format & 0x07 ) ;
big_endian = ( ( data_format & 0x10 ) = = 0x00 ) ;
unsigned_type = ( ( data_format & 0x20 ) = = 0x00 ) ;
if ( buf_len < data_size )
return 0 ;
switch ( data_size ) {
case 1 :
value = buf [ 0 ] ;
break ;
case 2 :
if ( big_endian )
value = get_unaligned_be16 ( buf ) ;
else
value = get_unaligned_le16 ( buf ) ;
break ;
case 4 :
if ( big_endian )
value = get_unaligned_be32 ( buf ) ;
else
value = get_unaligned_le32 ( buf ) ;
break ;
default :
/* Should not happen, just as default case here. */
value = 0 ;
break ;
}
if ( ! unsigned_type )
value = twos_complement_to_s32 ( value , data_size * 8 ) ;
return value ;
}
static void cyapa_gen5_guess_electrodes ( struct cyapa * cyapa ,
int * electrodes_rx , int * electrodes_tx )
{
if ( cyapa - > electrodes_rx ! = 0 ) {
* electrodes_rx = cyapa - > electrodes_rx ;
* electrodes_tx = ( cyapa - > electrodes_x = = * electrodes_rx ) ?
cyapa - > electrodes_y : cyapa - > electrodes_x ;
} else {
* electrodes_tx = min ( cyapa - > electrodes_x , cyapa - > electrodes_y ) ;
* electrodes_rx = max ( cyapa - > electrodes_x , cyapa - > electrodes_y ) ;
}
}
/*
* Read all the global mutual or self idac data or mutual or self local PWC
* data based on the @ idac_data_type .
* If the input value of @ data_size is 0 , then means read global mutual or
* self idac data . For read global mutual idac data , @ idac_max , @ idac_min and
* @ idac_ave are in order used to return the max value of global mutual idac
* data , the min value of global mutual idac and the average value of the
* global mutual idac data . For read global self idac data , @ idac_max is used
* to return the global self cap idac data in Rx direction , @ idac_min is used
* to return the global self cap idac data in Tx direction . @ idac_ave is not
* used .
* If the input value of @ data_size is not 0 , than means read the mutual or
* self local PWC data . The @ idac_max , @ idac_min and @ idac_ave are used to
* return the max , min and average value of the mutual or self local PWC data .
2015-07-20 16:49:06 -07:00
* Note , in order to read mutual local PWC data , must read invoke this function
2015-01-17 22:16:01 -08:00
* to read the mutual global idac data firstly to set the correct Rx number
* value , otherwise , the read mutual idac and PWC data may not correct .
*/
static int cyapa_gen5_read_idac_data ( struct cyapa * cyapa ,
u8 cmd_code , u8 idac_data_type , int * data_size ,
int * idac_max , int * idac_min , int * idac_ave )
{
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head * cmd_head ;
2015-01-17 22:16:01 -08:00
u8 cmd [ 12 ] ;
u8 resp_data [ 256 ] ;
int resp_len ;
int read_len ;
int value ;
u16 offset ;
int read_elements ;
bool read_global_idac ;
int sum , count , max_element_cnt ;
int tmp_max , tmp_min , tmp_ave , tmp_sum , tmp_count ;
int electrodes_rx , electrodes_tx ;
int i ;
int error ;
2015-07-20 16:49:06 -07:00
if ( cmd_code ! = PIP_RETRIEVE_DATA_STRUCTURE | |
2015-01-17 22:16:01 -08:00
( idac_data_type ! = GEN5_RETRIEVE_MUTUAL_PWC_DATA & &
idac_data_type ! = GEN5_RETRIEVE_SELF_CAP_PWC_DATA ) | |
! data_size | | ! idac_max | | ! idac_min | | ! idac_ave )
return - EINVAL ;
* idac_max = INT_MIN ;
* idac_min = INT_MAX ;
sum = count = tmp_count = 0 ;
electrodes_rx = electrodes_tx = 0 ;
if ( * data_size = = 0 ) {
/*
* Read global idac values firstly .
* Currently , no idac data exceed 4 bytes .
*/
read_global_idac = true ;
offset = 0 ;
* data_size = 4 ;
tmp_max = INT_MIN ;
tmp_min = INT_MAX ;
tmp_ave = tmp_sum = tmp_count = 0 ;
if ( idac_data_type = = GEN5_RETRIEVE_MUTUAL_PWC_DATA ) {
if ( cyapa - > aligned_electrodes_rx = = 0 ) {
cyapa_gen5_guess_electrodes ( cyapa ,
& electrodes_rx , & electrodes_tx ) ;
cyapa - > aligned_electrodes_rx =
( electrodes_rx + 3 ) & ~ 3u ;
}
max_element_cnt =
( cyapa - > aligned_electrodes_rx + 7 ) & ~ 7u ;
} else {
max_element_cnt = 2 ;
}
} else {
read_global_idac = false ;
if ( * data_size > 4 )
* data_size = 4 ;
/* Calculate the start offset in bytes of local PWC data. */
if ( idac_data_type = = GEN5_RETRIEVE_MUTUAL_PWC_DATA ) {
offset = cyapa - > aligned_electrodes_rx * ( * data_size ) ;
if ( cyapa - > electrodes_rx = = cyapa - > electrodes_x )
electrodes_tx = cyapa - > electrodes_y ;
else
electrodes_tx = cyapa - > electrodes_x ;
max_element_cnt = ( ( cyapa - > aligned_electrodes_rx + 7 ) &
~ 7u ) * electrodes_tx ;
2015-03-02 09:39:24 -08:00
} else {
2015-01-17 22:16:01 -08:00
offset = 2 ;
max_element_cnt = cyapa - > electrodes_x +
cyapa - > electrodes_y ;
max_element_cnt = ( max_element_cnt + 3 ) & ~ 3u ;
}
}
memset ( cmd , 0 , sizeof ( cmd ) ) ;
2015-07-20 16:49:06 -07:00
cmd_head = ( struct pip_app_cmd_head * ) cmd ;
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & cmd_head - > addr ) ;
2015-01-17 22:16:01 -08:00
put_unaligned_le16 ( sizeof ( cmd ) - 2 , & cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
cmd_head - > report_id = PIP_APP_CMD_REPORT_ID ;
2015-01-17 22:16:01 -08:00
cmd_head - > cmd_code = cmd_code ;
do {
read_elements = ( 256 - GEN5_RESP_DATA_STRUCTURE_OFFSET ) /
( * data_size ) ;
read_elements = min ( read_elements , max_element_cnt - count ) ;
read_len = read_elements * ( * data_size ) ;
put_unaligned_le16 ( offset , & cmd_head - > parameter_data [ 0 ] ) ;
put_unaligned_le16 ( read_len , & cmd_head - > parameter_data [ 2 ] ) ;
cmd_head - > parameter_data [ 4 ] = idac_data_type ;
resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data ,
2015-01-17 22:16:01 -08:00
true ) ;
if ( error | | resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET | |
! VALID_CMD_RESP_HEADER ( resp_data , cmd_code ) | |
2015-07-20 16:49:06 -07:00
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) | |
2015-01-17 22:16:01 -08:00
resp_data [ 6 ] ! = idac_data_type )
return ( error < 0 ) ? error : - EAGAIN ;
read_len = get_unaligned_le16 ( & resp_data [ 7 ] ) ;
if ( read_len = = 0 )
break ;
* data_size = ( resp_data [ 9 ] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK ) ;
if ( read_len < * data_size )
return - EINVAL ;
if ( read_global_idac & &
idac_data_type = = GEN5_RETRIEVE_SELF_CAP_PWC_DATA ) {
/* Rx's self global idac data. */
* idac_max = cyapa_parse_structure_data (
resp_data [ 9 ] ,
& resp_data [ GEN5_RESP_DATA_STRUCTURE_OFFSET ] ,
* data_size ) ;
/* Tx's self global idac data. */
* idac_min = cyapa_parse_structure_data (
resp_data [ 9 ] ,
& resp_data [ GEN5_RESP_DATA_STRUCTURE_OFFSET +
* data_size ] ,
* data_size ) ;
break ;
}
/* Read mutual global idac or local mutual/self PWC data. */
offset + = read_len ;
for ( i = 10 ; i < ( read_len + GEN5_RESP_DATA_STRUCTURE_OFFSET ) ;
i + = * data_size ) {
value = cyapa_parse_structure_data ( resp_data [ 9 ] ,
& resp_data [ i ] , * data_size ) ;
* idac_min = min ( value , * idac_min ) ;
* idac_max = max ( value , * idac_max ) ;
if ( idac_data_type = = GEN5_RETRIEVE_MUTUAL_PWC_DATA & &
tmp_count < cyapa - > aligned_electrodes_rx & &
read_global_idac ) {
/*
2015-07-20 16:49:06 -07:00
* The value gap between global and local mutual
2015-01-17 22:16:01 -08:00
* idac data must bigger than 50 % .
* Normally , global value bigger than 50 ,
* local values less than 10.
*/
if ( ! tmp_ave | | value > tmp_ave / 2 ) {
tmp_min = min ( value , tmp_min ) ;
tmp_max = max ( value , tmp_max ) ;
tmp_sum + = value ;
tmp_count + + ;
tmp_ave = tmp_sum / tmp_count ;
}
}
sum + = value ;
count + + ;
if ( count > = max_element_cnt )
goto out ;
}
} while ( true ) ;
out :
* idac_ave = count ? ( sum / count ) : 0 ;
if ( read_global_idac & &
idac_data_type = = GEN5_RETRIEVE_MUTUAL_PWC_DATA ) {
if ( tmp_count = = 0 )
return 0 ;
if ( tmp_count = = cyapa - > aligned_electrodes_rx ) {
cyapa - > electrodes_rx = cyapa - > electrodes_rx ?
cyapa - > electrodes_rx : electrodes_rx ;
} else if ( tmp_count = = electrodes_rx ) {
cyapa - > electrodes_rx = cyapa - > electrodes_rx ?
cyapa - > electrodes_rx : electrodes_rx ;
cyapa - > aligned_electrodes_rx = electrodes_rx ;
} else {
cyapa - > electrodes_rx = cyapa - > electrodes_rx ?
cyapa - > electrodes_rx : electrodes_tx ;
cyapa - > aligned_electrodes_rx = tmp_count ;
}
* idac_min = tmp_min ;
* idac_max = tmp_max ;
* idac_ave = tmp_ave ;
}
return 0 ;
}
static int cyapa_gen5_read_mutual_idac_data ( struct cyapa * cyapa ,
int * gidac_mutual_max , int * gidac_mutual_min , int * gidac_mutual_ave ,
int * lidac_mutual_max , int * lidac_mutual_min , int * lidac_mutual_ave )
{
int data_size ;
int error ;
* gidac_mutual_max = * gidac_mutual_min = * gidac_mutual_ave = 0 ;
* lidac_mutual_max = * lidac_mutual_min = * lidac_mutual_ave = 0 ;
data_size = 0 ;
error = cyapa_gen5_read_idac_data ( cyapa ,
2015-07-20 16:49:06 -07:00
PIP_RETRIEVE_DATA_STRUCTURE ,
2015-01-17 22:16:01 -08:00
GEN5_RETRIEVE_MUTUAL_PWC_DATA ,
& data_size ,
gidac_mutual_max , gidac_mutual_min , gidac_mutual_ave ) ;
if ( error )
return error ;
error = cyapa_gen5_read_idac_data ( cyapa ,
2015-07-20 16:49:06 -07:00
PIP_RETRIEVE_DATA_STRUCTURE ,
2015-01-17 22:16:01 -08:00
GEN5_RETRIEVE_MUTUAL_PWC_DATA ,
& data_size ,
lidac_mutual_max , lidac_mutual_min , lidac_mutual_ave ) ;
return error ;
}
static int cyapa_gen5_read_self_idac_data ( struct cyapa * cyapa ,
int * gidac_self_rx , int * gidac_self_tx ,
int * lidac_self_max , int * lidac_self_min , int * lidac_self_ave )
{
int data_size ;
int error ;
* gidac_self_rx = * gidac_self_tx = 0 ;
* lidac_self_max = * lidac_self_min = * lidac_self_ave = 0 ;
data_size = 0 ;
error = cyapa_gen5_read_idac_data ( cyapa ,
2015-07-20 16:49:06 -07:00
PIP_RETRIEVE_DATA_STRUCTURE ,
2015-01-17 22:16:01 -08:00
GEN5_RETRIEVE_SELF_CAP_PWC_DATA ,
& data_size ,
lidac_self_max , lidac_self_min , lidac_self_ave ) ;
if ( error )
return error ;
* gidac_self_rx = * lidac_self_max ;
* gidac_self_tx = * lidac_self_min ;
error = cyapa_gen5_read_idac_data ( cyapa ,
2015-07-20 16:49:06 -07:00
PIP_RETRIEVE_DATA_STRUCTURE ,
2015-01-17 22:16:01 -08:00
GEN5_RETRIEVE_SELF_CAP_PWC_DATA ,
& data_size ,
lidac_self_max , lidac_self_min , lidac_self_ave ) ;
return error ;
}
static ssize_t cyapa_gen5_execute_panel_scan ( struct cyapa * cyapa )
{
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head * app_cmd_head ;
2015-01-17 22:16:01 -08:00
u8 cmd [ 7 ] ;
u8 resp_data [ 6 ] ;
int resp_len ;
int error ;
memset ( cmd , 0 , sizeof ( cmd ) ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head = ( struct pip_app_cmd_head * ) cmd ;
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & app_cmd_head - > addr ) ;
2015-01-17 22:16:01 -08:00
put_unaligned_le16 ( sizeof ( cmd ) - 2 , & app_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head - > report_id = PIP_APP_CMD_REPORT_ID ;
2015-01-17 22:16:01 -08:00
app_cmd_head - > cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , true ) ;
2015-01-17 22:16:01 -08:00
if ( error | | resp_len ! = sizeof ( resp_data ) | |
! VALID_CMD_RESP_HEADER ( resp_data ,
GEN5_CMD_EXECUTE_PANEL_SCAN ) | |
2015-07-20 16:49:06 -07:00
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) )
2015-01-17 22:16:01 -08:00
return error ? error : - EAGAIN ;
return 0 ;
}
static int cyapa_gen5_read_panel_scan_raw_data ( struct cyapa * cyapa ,
u8 cmd_code , u8 raw_data_type , int raw_data_max_num ,
int * raw_data_max , int * raw_data_min , int * raw_data_ave ,
u8 * buffer )
{
2015-07-20 16:49:06 -07:00
struct pip_app_cmd_head * app_cmd_head ;
2015-01-17 22:16:01 -08:00
struct gen5_retrieve_panel_scan_data * panel_sacn_data ;
u8 cmd [ 12 ] ;
u8 resp_data [ 256 ] ; /* Max bytes can transfer one time. */
int resp_len ;
int read_elements ;
int read_len ;
u16 offset ;
s32 value ;
int sum , count ;
int data_size ;
s32 * intp ;
int i ;
int error ;
if ( cmd_code ! = GEN5_CMD_RETRIEVE_PANEL_SCAN | |
( raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT ) | |
! raw_data_max | | ! raw_data_min | | ! raw_data_ave )
return - EINVAL ;
intp = ( s32 * ) buffer ;
* raw_data_max = INT_MIN ;
* raw_data_min = INT_MAX ;
sum = count = 0 ;
offset = 0 ;
/* Assume max element size is 4 currently. */
read_elements = ( 256 - GEN5_RESP_DATA_STRUCTURE_OFFSET ) / 4 ;
read_len = read_elements * 4 ;
2015-07-20 16:49:06 -07:00
app_cmd_head = ( struct pip_app_cmd_head * ) cmd ;
put_unaligned_le16 ( PIP_OUTPUT_REPORT_ADDR , & app_cmd_head - > addr ) ;
2015-01-17 22:16:01 -08:00
put_unaligned_le16 ( sizeof ( cmd ) - 2 , & app_cmd_head - > length ) ;
2015-07-20 16:49:06 -07:00
app_cmd_head - > report_id = PIP_APP_CMD_REPORT_ID ;
2015-01-17 22:16:01 -08:00
app_cmd_head - > cmd_code = cmd_code ;
panel_sacn_data = ( struct gen5_retrieve_panel_scan_data * )
app_cmd_head - > parameter_data ;
do {
put_unaligned_le16 ( offset , & panel_sacn_data - > read_offset ) ;
put_unaligned_le16 ( read_elements ,
& panel_sacn_data - > read_elements ) ;
panel_sacn_data - > data_id = raw_data_type ;
resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
cmd , sizeof ( cmd ) ,
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_app_resp_data , true ) ;
2015-01-17 22:16:01 -08:00
if ( error | | resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET | |
! VALID_CMD_RESP_HEADER ( resp_data , cmd_code ) | |
2015-07-20 16:49:06 -07:00
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) | |
2015-01-17 22:16:01 -08:00
resp_data [ 6 ] ! = raw_data_type )
return error ? error : - EAGAIN ;
read_elements = get_unaligned_le16 ( & resp_data [ 7 ] ) ;
if ( read_elements = = 0 )
break ;
data_size = ( resp_data [ 9 ] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK ) ;
offset + = read_elements ;
if ( read_elements ) {
for ( i = GEN5_RESP_DATA_STRUCTURE_OFFSET ;
i < ( read_elements * data_size +
GEN5_RESP_DATA_STRUCTURE_OFFSET ) ;
i + = data_size ) {
value = cyapa_parse_structure_data ( resp_data [ 9 ] ,
& resp_data [ i ] , data_size ) ;
* raw_data_min = min ( value , * raw_data_min ) ;
* raw_data_max = max ( value , * raw_data_max ) ;
if ( intp )
put_unaligned_le32 ( value , & intp [ count ] ) ;
sum + = value ;
count + + ;
}
}
if ( count > = raw_data_max_num )
break ;
read_elements = ( sizeof ( resp_data ) -
GEN5_RESP_DATA_STRUCTURE_OFFSET ) / data_size ;
read_len = read_elements * data_size ;
} while ( true ) ;
* raw_data_ave = count ? ( sum / count ) : 0 ;
return 0 ;
}
static ssize_t cyapa_gen5_show_baseline ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct cyapa * cyapa = dev_get_drvdata ( dev ) ;
int gidac_mutual_max , gidac_mutual_min , gidac_mutual_ave ;
int lidac_mutual_max , lidac_mutual_min , lidac_mutual_ave ;
int gidac_self_rx , gidac_self_tx ;
int lidac_self_max , lidac_self_min , lidac_self_ave ;
int raw_cap_mutual_max , raw_cap_mutual_min , raw_cap_mutual_ave ;
int raw_cap_self_max , raw_cap_self_min , raw_cap_self_ave ;
int mutual_diffdata_max , mutual_diffdata_min , mutual_diffdata_ave ;
int self_diffdata_max , self_diffdata_min , self_diffdata_ave ;
int mutual_baseline_max , mutual_baseline_min , mutual_baseline_ave ;
int self_baseline_max , self_baseline_min , self_baseline_ave ;
int error , resume_error ;
int size ;
2015-07-20 16:49:06 -07:00
if ( ! cyapa_is_pip_app_mode ( cyapa ) )
2015-01-17 22:16:01 -08:00
return - EBUSY ;
/* 1. Suspend Scanning*/
2015-07-20 16:49:06 -07:00
error = cyapa_pip_suspend_scanning ( cyapa ) ;
2015-01-17 22:16:01 -08:00
if ( error )
return error ;
/* 2. Read global and local mutual IDAC data. */
gidac_self_rx = gidac_self_tx = 0 ;
error = cyapa_gen5_read_mutual_idac_data ( cyapa ,
& gidac_mutual_max , & gidac_mutual_min ,
& gidac_mutual_ave , & lidac_mutual_max ,
& lidac_mutual_min , & lidac_mutual_ave ) ;
if ( error )
goto resume_scanning ;
/* 3. Read global and local self IDAC data. */
error = cyapa_gen5_read_self_idac_data ( cyapa ,
& gidac_self_rx , & gidac_self_tx ,
& lidac_self_max , & lidac_self_min ,
& lidac_self_ave ) ;
if ( error )
goto resume_scanning ;
2015-07-20 16:49:06 -07:00
/* 4. Execute panel scan. It must be executed before read data. */
2015-01-17 22:16:01 -08:00
error = cyapa_gen5_execute_panel_scan ( cyapa ) ;
if ( error )
goto resume_scanning ;
/* 5. Retrieve panel scan, mutual cap raw data. */
error = cyapa_gen5_read_panel_scan_raw_data ( cyapa ,
GEN5_CMD_RETRIEVE_PANEL_SCAN ,
GEN5_PANEL_SCAN_MUTUAL_RAW_DATA ,
cyapa - > electrodes_x * cyapa - > electrodes_y ,
& raw_cap_mutual_max , & raw_cap_mutual_min ,
& raw_cap_mutual_ave ,
NULL ) ;
if ( error )
goto resume_scanning ;
/* 6. Retrieve panel scan, self cap raw data. */
error = cyapa_gen5_read_panel_scan_raw_data ( cyapa ,
GEN5_CMD_RETRIEVE_PANEL_SCAN ,
GEN5_PANEL_SCAN_SELF_RAW_DATA ,
cyapa - > electrodes_x + cyapa - > electrodes_y ,
& raw_cap_self_max , & raw_cap_self_min ,
& raw_cap_self_ave ,
NULL ) ;
if ( error )
goto resume_scanning ;
/* 7. Retrieve panel scan, mutual cap diffcount raw data. */
error = cyapa_gen5_read_panel_scan_raw_data ( cyapa ,
GEN5_CMD_RETRIEVE_PANEL_SCAN ,
GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT ,
cyapa - > electrodes_x * cyapa - > electrodes_y ,
& mutual_diffdata_max , & mutual_diffdata_min ,
& mutual_diffdata_ave ,
NULL ) ;
if ( error )
goto resume_scanning ;
/* 8. Retrieve panel scan, self cap diffcount raw data. */
error = cyapa_gen5_read_panel_scan_raw_data ( cyapa ,
GEN5_CMD_RETRIEVE_PANEL_SCAN ,
GEN5_PANEL_SCAN_SELF_DIFFCOUNT ,
cyapa - > electrodes_x + cyapa - > electrodes_y ,
& self_diffdata_max , & self_diffdata_min ,
& self_diffdata_ave ,
NULL ) ;
if ( error )
goto resume_scanning ;
/* 9. Retrieve panel scan, mutual cap baseline raw data. */
error = cyapa_gen5_read_panel_scan_raw_data ( cyapa ,
GEN5_CMD_RETRIEVE_PANEL_SCAN ,
GEN5_PANEL_SCAN_MUTUAL_BASELINE ,
cyapa - > electrodes_x * cyapa - > electrodes_y ,
& mutual_baseline_max , & mutual_baseline_min ,
& mutual_baseline_ave ,
NULL ) ;
if ( error )
goto resume_scanning ;
/* 10. Retrieve panel scan, self cap baseline raw data. */
error = cyapa_gen5_read_panel_scan_raw_data ( cyapa ,
GEN5_CMD_RETRIEVE_PANEL_SCAN ,
GEN5_PANEL_SCAN_SELF_BASELINE ,
cyapa - > electrodes_x + cyapa - > electrodes_y ,
& self_baseline_max , & self_baseline_min ,
& self_baseline_ave ,
NULL ) ;
if ( error )
goto resume_scanning ;
resume_scanning :
/* 11. Resume Scanning*/
2015-07-20 16:49:06 -07:00
resume_error = cyapa_pip_resume_scanning ( cyapa ) ;
2015-01-17 22:16:01 -08:00
if ( resume_error | | error )
return resume_error ? resume_error : error ;
/* 12. Output data strings */
size = scnprintf ( buf , PAGE_SIZE , " %d %d %d %d %d %d %d %d %d %d %d " ,
gidac_mutual_min , gidac_mutual_max , gidac_mutual_ave ,
lidac_mutual_min , lidac_mutual_max , lidac_mutual_ave ,
gidac_self_rx , gidac_self_tx ,
lidac_self_min , lidac_self_max , lidac_self_ave ) ;
size + = scnprintf ( buf + size , PAGE_SIZE - size ,
" %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d \n " ,
raw_cap_mutual_min , raw_cap_mutual_max , raw_cap_mutual_ave ,
raw_cap_self_min , raw_cap_self_max , raw_cap_self_ave ,
mutual_diffdata_min , mutual_diffdata_max , mutual_diffdata_ave ,
self_diffdata_min , self_diffdata_max , self_diffdata_ave ,
mutual_baseline_min , mutual_baseline_max , mutual_baseline_ave ,
self_baseline_min , self_baseline_max , self_baseline_ave ) ;
return size ;
}
2015-07-20 16:49:06 -07:00
bool cyapa_pip_sort_system_info_data ( struct cyapa * cyapa ,
2015-01-17 18:49:37 -08:00
u8 * buf , int len )
{
/* Check the report id and command code */
if ( VALID_CMD_RESP_HEADER ( buf , 0x02 ) )
return true ;
return false ;
}
static int cyapa_gen5_bl_query_data ( struct cyapa * cyapa )
{
2015-07-20 16:49:06 -07:00
u8 resp_data [ PIP_BL_APP_INFO_RESP_LENGTH ] ;
2015-01-17 18:49:37 -08:00
int resp_len ;
int error ;
2015-07-20 16:49:06 -07:00
resp_len = sizeof ( resp_data ) ;
2015-01-17 18:49:37 -08:00
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
2015-07-20 16:49:06 -07:00
pip_bl_read_app_info , PIP_BL_READ_APP_INFO_CMD_LENGTH ,
2015-01-17 18:49:37 -08:00
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
500 , cyapa_sort_tsg_pip_bl_resp_data , false ) ;
if ( error | | resp_len < PIP_BL_APP_INFO_RESP_LENGTH | |
! PIP_CMD_COMPLETE_SUCCESS ( resp_data ) )
2015-01-17 18:49:37 -08:00
return error ? error : - EIO ;
memcpy ( & cyapa - > product_id [ 0 ] , & resp_data [ 8 ] , 5 ) ;
cyapa - > product_id [ 5 ] = ' - ' ;
memcpy ( & cyapa - > product_id [ 6 ] , & resp_data [ 13 ] , 6 ) ;
cyapa - > product_id [ 12 ] = ' - ' ;
memcpy ( & cyapa - > product_id [ 13 ] , & resp_data [ 19 ] , 2 ) ;
cyapa - > product_id [ 15 ] = ' \0 ' ;
cyapa - > fw_maj_ver = resp_data [ 22 ] ;
cyapa - > fw_min_ver = resp_data [ 23 ] ;
2015-07-20 16:53:30 -07:00
cyapa - > platform_ver = ( resp_data [ 26 ] > > PIP_BL_PLATFORM_VER_SHIFT ) &
PIP_BL_PLATFORM_VER_MASK ;
2015-01-17 18:49:37 -08:00
return 0 ;
}
static int cyapa_gen5_get_query_data ( struct cyapa * cyapa )
{
2015-07-20 16:49:06 -07:00
u8 resp_data [ PIP_READ_SYS_INFO_RESP_LENGTH ] ;
2015-01-17 18:49:37 -08:00
int resp_len ;
u16 product_family ;
int error ;
resp_len = sizeof ( resp_data ) ;
error = cyapa_i2c_pip_cmd_irq_sync ( cyapa ,
2015-07-20 16:49:06 -07:00
pip_read_sys_info , PIP_READ_SYS_INFO_CMD_LENGTH ,
2015-01-17 18:49:37 -08:00
resp_data , & resp_len ,
2015-07-20 16:49:06 -07:00
2000 , cyapa_pip_sort_system_info_data , false ) ;
2015-01-17 18:49:37 -08:00
if ( error | | resp_len < sizeof ( resp_data ) )
return error ? error : - EIO ;
product_family = get_unaligned_le16 ( & resp_data [ 7 ] ) ;
2015-07-20 16:49:06 -07:00
if ( ( product_family & PIP_PRODUCT_FAMILY_MASK ) ! =
PIP_PRODUCT_FAMILY_TRACKPAD )
2015-01-17 18:49:37 -08:00
return - EINVAL ;
2015-07-20 16:53:30 -07:00
cyapa - > platform_ver = ( resp_data [ 49 ] > > PIP_BL_PLATFORM_VER_SHIFT ) &
PIP_BL_PLATFORM_VER_MASK ;
if ( cyapa - > gen = = CYAPA_GEN5 & & cyapa - > platform_ver < 2 ) {
/* Gen5 firmware that does not support proximity. */
cyapa - > fw_maj_ver = resp_data [ 15 ] ;
cyapa - > fw_min_ver = resp_data [ 16 ] ;
} else {
cyapa - > fw_maj_ver = resp_data [ 9 ] ;
cyapa - > fw_min_ver = resp_data [ 10 ] ;
}
2015-01-17 18:49:37 -08:00
cyapa - > electrodes_x = resp_data [ 52 ] ;
cyapa - > electrodes_y = resp_data [ 53 ] ;
cyapa - > physical_size_x = get_unaligned_le16 ( & resp_data [ 54 ] ) / 100 ;
cyapa - > physical_size_y = get_unaligned_le16 ( & resp_data [ 56 ] ) / 100 ;
cyapa - > max_abs_x = get_unaligned_le16 ( & resp_data [ 58 ] ) ;
cyapa - > max_abs_y = get_unaligned_le16 ( & resp_data [ 60 ] ) ;
cyapa - > max_z = get_unaligned_le16 ( & resp_data [ 62 ] ) ;
cyapa - > x_origin = resp_data [ 64 ] & 0x01 ;
cyapa - > y_origin = resp_data [ 65 ] & 0x01 ;
cyapa - > btn_capability = ( resp_data [ 70 ] < < 3 ) & CAPABILITY_BTN_MASK ;
memcpy ( & cyapa - > product_id [ 0 ] , & resp_data [ 33 ] , 5 ) ;
cyapa - > product_id [ 5 ] = ' - ' ;
memcpy ( & cyapa - > product_id [ 6 ] , & resp_data [ 38 ] , 6 ) ;
cyapa - > product_id [ 12 ] = ' - ' ;
memcpy ( & cyapa - > product_id [ 13 ] , & resp_data [ 44 ] , 2 ) ;
cyapa - > product_id [ 15 ] = ' \0 ' ;
if ( ! cyapa - > electrodes_x | | ! cyapa - > electrodes_y | |
! cyapa - > physical_size_x | | ! cyapa - > physical_size_y | |
! cyapa - > max_abs_x | | ! cyapa - > max_abs_y | | ! cyapa - > max_z )
return - EINVAL ;
return 0 ;
}
static int cyapa_gen5_do_operational_check ( struct cyapa * cyapa )
{
struct device * dev = & cyapa - > client - > dev ;
int error ;
if ( cyapa - > gen ! = CYAPA_GEN5 )
return - ENODEV ;
switch ( cyapa - > state ) {
case CYAPA_STATE_GEN5_BL :
2015-07-20 16:49:06 -07:00
error = cyapa_pip_bl_exit ( cyapa ) ;
2015-01-17 18:49:37 -08:00
if ( error ) {
2015-07-20 16:49:06 -07:00
/* Try to update trackpad product information. */
2015-01-17 18:49:37 -08:00
cyapa_gen5_bl_query_data ( cyapa ) ;
goto out ;
}
cyapa - > state = CYAPA_STATE_GEN5_APP ;
2020-07-07 11:24:55 -07:00
fallthrough ;
2015-01-17 18:49:37 -08:00
case CYAPA_STATE_GEN5_APP :
/*
* If trackpad device in deep sleep mode ,
* the app command will fail .
* So always try to reset trackpad device to full active when
2015-07-20 16:49:06 -07:00
* the device state is required .
2015-01-17 18:49:37 -08:00
*/
error = cyapa_gen5_set_power_mode ( cyapa ,
2016-03-04 11:23:09 -08:00
PWR_MODE_FULL_ACTIVE , 0 , CYAPA_PM_ACTIVE ) ;
2015-01-17 18:49:37 -08:00
if ( error )
dev_warn ( dev , " %s: failed to set power active mode. \n " ,
__func__ ) ;
2015-07-20 16:57:53 -07:00
/* By default, the trackpad proximity function is enabled. */
2015-07-30 11:26:39 -07:00
if ( cyapa - > platform_ver > = 2 ) {
error = cyapa_pip_set_proximity ( cyapa , true ) ;
if ( error )
dev_warn ( dev ,
" %s: failed to enable proximity. \n " ,
__func__ ) ;
}
2015-07-20 16:57:53 -07:00
2015-01-17 18:49:37 -08:00
/* Get trackpad product information. */
error = cyapa_gen5_get_query_data ( cyapa ) ;
if ( error )
goto out ;
/* Only support product ID starting with CYTRA */
if ( memcmp ( cyapa - > product_id , product_id ,
strlen ( product_id ) ) ! = 0 ) {
dev_err ( dev , " %s: unknown product ID (%s) \n " ,
__func__ , cyapa - > product_id ) ;
error = - EINVAL ;
}
break ;
default :
error = - EINVAL ;
}
out :
return error ;
}
/*
* Return false , do not continue process
* Return true , continue process .
*/
2015-07-20 16:49:06 -07:00
bool cyapa_pip_irq_cmd_handler ( struct cyapa * cyapa )
2015-01-17 18:49:37 -08:00
{
2015-07-20 16:49:06 -07:00
struct cyapa_pip_cmd_states * pip = & cyapa - > cmd_states . pip ;
2015-01-17 18:49:37 -08:00
int length ;
2015-07-20 16:49:06 -07:00
if ( atomic_read ( & pip - > cmd_issued ) ) {
2015-01-17 18:49:37 -08:00
/* Polling command response data. */
2015-07-20 16:49:06 -07:00
if ( pip - > is_irq_mode = = false )
2015-01-17 18:49:37 -08:00
return false ;
/*
* Read out all none command response data .
* these output data may caused by user put finger on
* trackpad when host waiting the command response .
*/
2015-07-20 16:49:06 -07:00
cyapa_i2c_pip_read ( cyapa , pip - > irq_cmd_buf ,
PIP_RESP_LENGTH_SIZE ) ;
length = get_unaligned_le16 ( pip - > irq_cmd_buf ) ;
length = ( length < = PIP_RESP_LENGTH_SIZE ) ?
PIP_RESP_LENGTH_SIZE : length ;
if ( length > PIP_RESP_LENGTH_SIZE )
2015-01-17 18:49:37 -08:00
cyapa_i2c_pip_read ( cyapa ,
2015-07-20 16:49:06 -07:00
pip - > irq_cmd_buf , length ) ;
if ( ! ( pip - > resp_sort_func & &
pip - > resp_sort_func ( cyapa ,
pip - > irq_cmd_buf , length ) ) ) {
2015-01-17 18:49:37 -08:00
/*
2015-07-20 16:49:06 -07:00
* Cover the Gen5 V1 firmware issue .
* The issue is no interrupt would be asserted from
* trackpad device to host for the command response
* ready event . Because when there was a finger touch
* on trackpad device , and the firmware output queue
* won ' t be empty ( always with touch report data ) , so
* the interrupt signal won ' t be asserted again until
* the output queue was previous emptied .
* This issue would happen in the scenario that
* user always has his / her fingers touched on the
* trackpad device during system booting / rebooting .
2015-01-17 18:49:37 -08:00
*/
2015-01-22 08:17:16 -08:00
length = 0 ;
2015-07-20 16:49:06 -07:00
if ( pip - > resp_len )
length = * pip - > resp_len ;
2015-01-17 18:49:37 -08:00
cyapa_empty_pip_output_data ( cyapa ,
2015-07-20 16:49:06 -07:00
pip - > resp_data ,
2015-01-17 18:49:37 -08:00
& length ,
2015-07-20 16:49:06 -07:00
pip - > resp_sort_func ) ;
if ( pip - > resp_len & & length ! = 0 ) {
* pip - > resp_len = length ;
atomic_dec ( & pip - > cmd_issued ) ;
complete ( & pip - > cmd_ready ) ;
2015-01-17 18:49:37 -08:00
}
return false ;
}
2015-07-20 16:49:06 -07:00
if ( pip - > resp_data & & pip - > resp_len ) {
* pip - > resp_len = ( * pip - > resp_len < length ) ?
* pip - > resp_len : length ;
memcpy ( pip - > resp_data , pip - > irq_cmd_buf ,
* pip - > resp_len ) ;
2015-01-17 18:49:37 -08:00
}
2015-07-20 16:49:06 -07:00
atomic_dec ( & pip - > cmd_issued ) ;
complete ( & pip - > cmd_ready ) ;
2015-01-17 18:49:37 -08:00
return false ;
}
return true ;
}
2015-07-20 16:49:06 -07:00
static void cyapa_pip_report_buttons ( struct cyapa * cyapa ,
const struct cyapa_pip_report_data * report_data )
2015-01-17 18:49:37 -08:00
{
struct input_dev * input = cyapa - > input ;
2015-07-20 16:49:06 -07:00
u8 buttons = report_data - > report_head [ PIP_BUTTONS_OFFSET ] ;
2015-01-17 18:49:37 -08:00
buttons = ( buttons < < CAPABILITY_BTN_SHIFT ) & CAPABILITY_BTN_MASK ;
if ( cyapa - > btn_capability & CAPABILITY_LEFT_BTN_MASK ) {
input_report_key ( input , BTN_LEFT ,
! ! ( buttons & CAPABILITY_LEFT_BTN_MASK ) ) ;
}
if ( cyapa - > btn_capability & CAPABILITY_MIDDLE_BTN_MASK ) {
input_report_key ( input , BTN_MIDDLE ,
! ! ( buttons & CAPABILITY_MIDDLE_BTN_MASK ) ) ;
}
if ( cyapa - > btn_capability & CAPABILITY_RIGHT_BTN_MASK ) {
input_report_key ( input , BTN_RIGHT ,
! ! ( buttons & CAPABILITY_RIGHT_BTN_MASK ) ) ;
}
input_sync ( input ) ;
}
2015-07-20 16:57:53 -07:00
static void cyapa_pip_report_proximity ( struct cyapa * cyapa ,
const struct cyapa_pip_report_data * report_data )
{
struct input_dev * input = cyapa - > input ;
u8 distance = report_data - > report_head [ PIP_PROXIMITY_DISTANCE_OFFSET ] &
PIP_PROXIMITY_DISTANCE_MASK ;
input_report_abs ( input , ABS_DISTANCE , distance ) ;
input_sync ( input ) ;
}
2015-07-20 16:49:06 -07:00
static void cyapa_pip_report_slot_data ( struct cyapa * cyapa ,
const struct cyapa_pip_touch_record * touch )
2015-01-17 18:49:37 -08:00
{
struct input_dev * input = cyapa - > input ;
2015-07-20 16:49:06 -07:00
u8 event_id = PIP_GET_EVENT_ID ( touch - > touch_tip_event_id ) ;
int slot = PIP_GET_TOUCH_ID ( touch - > touch_tip_event_id ) ;
2015-01-17 18:49:37 -08:00
int x , y ;
if ( event_id = = RECORD_EVENT_LIFTOFF )
return ;
input_mt_slot ( input , slot ) ;
input_mt_report_slot_state ( input , MT_TOOL_FINGER , true ) ;
x = ( touch - > x_hi < < 8 ) | touch - > x_lo ;
if ( cyapa - > x_origin )
x = cyapa - > max_abs_x - x ;
y = ( touch - > y_hi < < 8 ) | touch - > y_lo ;
if ( cyapa - > y_origin )
y = cyapa - > max_abs_y - y ;
2015-07-20 16:49:06 -07:00
input_report_abs ( input , ABS_MT_POSITION_X , x ) ;
2015-01-17 18:49:37 -08:00
input_report_abs ( input , ABS_MT_POSITION_Y , y ) ;
2015-07-20 16:57:53 -07:00
input_report_abs ( input , ABS_DISTANCE , 0 ) ;
2015-01-17 18:49:37 -08:00
input_report_abs ( input , ABS_MT_PRESSURE ,
touch - > z ) ;
input_report_abs ( input , ABS_MT_TOUCH_MAJOR ,
touch - > major_axis_len ) ;
input_report_abs ( input , ABS_MT_TOUCH_MINOR ,
touch - > minor_axis_len ) ;
input_report_abs ( input , ABS_MT_WIDTH_MAJOR ,
touch - > major_tool_len ) ;
input_report_abs ( input , ABS_MT_WIDTH_MINOR ,
touch - > minor_tool_len ) ;
input_report_abs ( input , ABS_MT_ORIENTATION ,
touch - > orientation ) ;
}
2015-07-20 16:49:06 -07:00
static void cyapa_pip_report_touches ( struct cyapa * cyapa ,
const struct cyapa_pip_report_data * report_data )
2015-01-17 18:49:37 -08:00
{
struct input_dev * input = cyapa - > input ;
unsigned int touch_num ;
int i ;
2015-07-20 16:49:06 -07:00
touch_num = report_data - > report_head [ PIP_NUMBER_OF_TOUCH_OFFSET ] &
PIP_NUMBER_OF_TOUCH_MASK ;
2015-01-17 18:49:37 -08:00
for ( i = 0 ; i < touch_num ; i + + )
2015-07-20 16:49:06 -07:00
cyapa_pip_report_slot_data ( cyapa ,
2015-01-17 18:49:37 -08:00
& report_data - > touch_records [ i ] ) ;
input_mt_sync_frame ( input ) ;
input_sync ( input ) ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_irq_handler ( struct cyapa * cyapa )
2015-01-17 18:49:37 -08:00
{
struct device * dev = & cyapa - > client - > dev ;
2015-07-20 16:49:06 -07:00
struct cyapa_pip_report_data report_data ;
2015-01-17 18:49:37 -08:00
unsigned int report_len ;
2015-07-20 16:49:06 -07:00
int ret ;
2015-01-17 18:49:37 -08:00
2015-07-20 16:49:06 -07:00
if ( ! cyapa_is_pip_app_mode ( cyapa ) ) {
2015-01-17 18:49:37 -08:00
dev_err ( dev , " invalid device state, gen=%d, state=0x%02x \n " ,
cyapa - > gen , cyapa - > state ) ;
return - EINVAL ;
}
ret = cyapa_i2c_pip_read ( cyapa , ( u8 * ) & report_data ,
2015-07-20 16:49:06 -07:00
PIP_RESP_LENGTH_SIZE ) ;
if ( ret ! = PIP_RESP_LENGTH_SIZE ) {
2015-01-17 18:49:37 -08:00
dev_err ( dev , " failed to read length bytes, (%d) \n " , ret ) ;
return - EINVAL ;
}
report_len = get_unaligned_le16 (
2015-07-20 16:49:06 -07:00
& report_data . report_head [ PIP_RESP_LENGTH_OFFSET ] ) ;
if ( report_len < PIP_RESP_LENGTH_SIZE ) {
/* Invalid length or internal reset happened. */
2015-01-17 18:49:37 -08:00
dev_err ( dev , " invalid report_len=%d. bytes: %02x %02x \n " ,
report_len , report_data . report_head [ 0 ] ,
report_data . report_head [ 1 ] ) ;
return - EINVAL ;
}
/* Idle, no data for report. */
2015-07-20 16:49:06 -07:00
if ( report_len = = PIP_RESP_LENGTH_SIZE )
2015-01-17 18:49:37 -08:00
return 0 ;
ret = cyapa_i2c_pip_read ( cyapa , ( u8 * ) & report_data , report_len ) ;
if ( ret ! = report_len ) {
dev_err ( dev , " failed to read %d bytes report data, (%d) \n " ,
report_len , ret ) ;
return - EINVAL ;
}
2016-03-04 11:23:09 -08:00
return cyapa_pip_event_process ( cyapa , & report_data ) ;
}
static int cyapa_pip_event_process ( struct cyapa * cyapa ,
struct cyapa_pip_report_data * report_data )
{
struct device * dev = & cyapa - > client - > dev ;
unsigned int report_len ;
u8 report_id ;
report_len = get_unaligned_le16 (
& report_data - > report_head [ PIP_RESP_LENGTH_OFFSET ] ) ;
/* Idle, no data for report. */
if ( report_len = = PIP_RESP_LENGTH_SIZE )
return 0 ;
report_id = report_data - > report_head [ PIP_RESP_REPORT_ID_OFFSET ] ;
2015-07-20 16:49:06 -07:00
if ( report_id = = PIP_WAKEUP_EVENT_REPORT_ID & &
report_len = = PIP_WAKEUP_EVENT_SIZE ) {
2015-01-17 18:49:37 -08:00
/*
* Device wake event from deep sleep mode for touch .
* This interrupt event is used to wake system up .
2015-07-20 17:09:59 -07:00
*
* Note :
* It will introduce about 20 ~ 40 ms additional delay
* time in receiving for first valid touch report data .
* The time is used to execute device runtime resume
* process .
2015-01-17 18:49:37 -08:00
*/
2015-07-20 17:09:59 -07:00
pm_runtime_get_sync ( dev ) ;
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_put_sync_autosuspend ( dev ) ;
2015-01-17 18:49:37 -08:00
return 0 ;
2015-07-20 16:49:06 -07:00
} else if ( report_id ! = PIP_TOUCH_REPORT_ID & &
report_id ! = PIP_BTN_REPORT_ID & &
2015-01-17 18:49:37 -08:00
report_id ! = GEN5_OLD_PUSH_BTN_REPORT_ID & &
2015-07-20 16:57:53 -07:00
report_id ! = PIP_PUSH_BTN_REPORT_ID & &
report_id ! = PIP_PROXIMITY_REPORT_ID ) {
2015-01-17 18:49:37 -08:00
/* Running in BL mode or unknown response data read. */
dev_err ( dev , " invalid report_id=0x%02x \n " , report_id ) ;
return - EINVAL ;
}
2015-07-20 16:49:06 -07:00
if ( report_id = = PIP_TOUCH_REPORT_ID & &
( report_len < PIP_TOUCH_REPORT_HEAD_SIZE | |
report_len > PIP_TOUCH_REPORT_MAX_SIZE ) ) {
2015-01-17 18:49:37 -08:00
/* Invalid report data length for finger packet. */
dev_err ( dev , " invalid touch packet length=%d \n " , report_len ) ;
return 0 ;
}
2015-07-20 16:49:06 -07:00
if ( ( report_id = = PIP_BTN_REPORT_ID | |
2015-01-17 18:49:37 -08:00
report_id = = GEN5_OLD_PUSH_BTN_REPORT_ID | |
2015-07-20 16:49:06 -07:00
report_id = = PIP_PUSH_BTN_REPORT_ID ) & &
( report_len < PIP_BTN_REPORT_HEAD_SIZE | |
report_len > PIP_BTN_REPORT_MAX_SIZE ) ) {
2015-01-17 18:49:37 -08:00
/* Invalid report data length of button packet. */
dev_err ( dev , " invalid button packet length=%d \n " , report_len ) ;
return 0 ;
}
2015-07-20 16:57:53 -07:00
if ( report_id = = PIP_PROXIMITY_REPORT_ID & &
report_len ! = PIP_PROXIMITY_REPORT_SIZE ) {
/* Invalid report data length of proximity packet. */
dev_err ( dev , " invalid proximity data, length=%d \n " , report_len ) ;
return 0 ;
}
2015-07-20 16:49:06 -07:00
if ( report_id = = PIP_TOUCH_REPORT_ID )
2016-03-04 11:23:09 -08:00
cyapa_pip_report_touches ( cyapa , report_data ) ;
2015-07-20 16:57:53 -07:00
else if ( report_id = = PIP_PROXIMITY_REPORT_ID )
2016-03-04 11:23:09 -08:00
cyapa_pip_report_proximity ( cyapa , report_data ) ;
2015-01-17 18:49:37 -08:00
else
2016-03-04 11:23:09 -08:00
cyapa_pip_report_buttons ( cyapa , report_data ) ;
2015-01-17 18:49:37 -08:00
return 0 ;
}
2015-07-20 16:49:06 -07:00
int cyapa_pip_bl_activate ( struct cyapa * cyapa ) { return 0 ; }
int cyapa_pip_bl_deactivate ( struct cyapa * cyapa ) { return 0 ; }
2015-01-17 22:14:48 -08:00
2015-01-17 18:49:37 -08:00
const struct cyapa_dev_ops cyapa_gen5_ops = {
2015-07-20 16:49:06 -07:00
. check_fw = cyapa_pip_check_fw ,
. bl_enter = cyapa_pip_bl_enter ,
. bl_initiate = cyapa_pip_bl_initiate ,
. update_fw = cyapa_pip_do_fw_update ,
. bl_activate = cyapa_pip_bl_activate ,
. bl_deactivate = cyapa_pip_bl_deactivate ,
2015-01-17 22:14:48 -08:00
2015-01-17 22:16:01 -08:00
. show_baseline = cyapa_gen5_show_baseline ,
2015-07-20 16:49:06 -07:00
. calibrate_store = cyapa_pip_do_calibrate ,
2015-01-17 22:16:01 -08:00
2015-07-20 16:49:06 -07:00
. initialize = cyapa_pip_cmd_state_initialize ,
2015-01-17 18:49:37 -08:00
. state_parse = cyapa_gen5_state_parse ,
. operational_check = cyapa_gen5_do_operational_check ,
2015-07-20 16:49:06 -07:00
. irq_handler = cyapa_pip_irq_handler ,
. irq_cmd_handler = cyapa_pip_irq_cmd_handler ,
2015-01-17 18:49:37 -08:00
. sort_empty_output_data = cyapa_empty_pip_output_data ,
. set_power_mode = cyapa_gen5_set_power_mode ,
2015-07-20 16:57:53 -07:00
. set_proximity = cyapa_pip_set_proximity ,
2015-01-17 18:49:37 -08:00
} ;