2021-02-07 10:37:17 -07:00
/*
* cyttsp5_device_access . c
* Parade TrueTouch ( TM ) Standard Product V5 Device Access Module .
* Configuration and Test command / status user interface .
* For use with Parade touchscreen controllers .
* Supported parts include :
* CYTMA5XX
* CYTMA448
* CYTMA445A
* CYTT21XXX
* CYTT31XXX
*
* Copyright ( C ) 2015 Parade Technologies
* Copyright ( C ) 2012 - 2015 Cypress Semiconductor
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 , and only version 2 , as published by the
* Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* Contact Parade Technologies at www . paradetech . com < ttdrivers @ paradetech . com >
*
*/
# include "cyttsp5_regs.h"
# include <linux/firmware.h>
# include <linux/timer.h>
# include <linux/timex.h>
# include <linux/rtc.h>
# define CMCP_THRESHOLD_FILE_NAME "cyttsp5_thresholdfile.csv"
/* Max test case number */
# define MAX_CASE_NUM (22)
/* ASCII */
# define ASCII_LF (0x0A)
# define ASCII_CR (0x0D)
# define ASCII_COMMA (0x2C)
# define ASCII_ZERO (0x30)
# define ASCII_NINE (0x39)
/* Max characters of test case name */
# define NAME_SIZE_MAX (50)
/* Max sensor and button number */
# define MAX_BUTTONS (HID_SYSINFO_MAX_BTN)
# define MAX_SENSORS (1024)
# define MAX_TX_SENSORS (128)
# define MAX_RX_SENSORS (128)
/* Multiply by 2 for double (min, max) values */
# define TABLE_BUTTON_MAX_SIZE (MAX_BUTTONS * 2)
# define TABLE_SENSOR_MAX_SIZE (MAX_SENSORS * 2)
# define TABLE_TX_MAX_SIZE (MAX_TX_SENSORS*2)
# define TABLE_RX_MAX_SIZE (MAX_RX_SENSORS*2)
# define CM_PANEL_DATA_OFFSET (6)
# define CM_BTN_DATA_OFFSET (6)
# define CP_PANEL_DATA_OFFSET (6)
# define CP_BTN_DATA_OFFSET (6)
# define MAX_BUF_LEN (50000)
/* cmcp csv file information */
struct configuration {
u32 cm_range_limit_row ;
u32 cm_range_limit_col ;
u32 cm_min_limit_cal ;
u32 cm_max_limit_cal ;
u32 cm_max_delta_sensor_percent ;
u32 cm_max_delta_button_percent ;
u32 min_sensor_rx ;
u32 max_sensor_rx ;
u32 min_sensor_tx ;
u32 max_sensor_tx ;
u32 min_button ;
u32 max_button ;
u32 max_delta_sensor ;
u32 cp_max_delta_sensor_rx_percent ;
u32 cp_max_delta_sensor_tx_percent ;
u32 cm_min_max_table_button [ TABLE_BUTTON_MAX_SIZE ] ;
u32 cp_min_max_table_button [ TABLE_BUTTON_MAX_SIZE ] ;
u32 cm_min_max_table_sensor [ TABLE_SENSOR_MAX_SIZE ] ;
u32 cp_min_max_table_rx [ TABLE_RX_MAX_SIZE ] ;
u32 cp_min_max_table_tx [ TABLE_TX_MAX_SIZE ] ;
u32 cm_min_max_table_button_size ;
u32 cp_min_max_table_button_size ;
u32 cm_min_max_table_sensor_size ;
u32 cp_min_max_table_rx_size ;
u32 cp_min_max_table_tx_size ;
u32 cp_max_delta_button_percent ;
u32 cm_max_table_gradient_cols_percent [ TABLE_TX_MAX_SIZE ] ;
u32 cm_max_table_gradient_cols_percent_size ;
u32 cm_max_table_gradient_rows_percent [ TABLE_RX_MAX_SIZE ] ;
u32 cm_max_table_gradient_rows_percent_size ;
u32 cm_excluding_row_edge ;
u32 cm_excluding_col_edge ;
u32 rx_num ;
u32 tx_num ;
u32 btn_num ;
u32 cm_enabled ;
u32 cp_enabled ;
u32 is_valid_or_not ;
} ;
/* Test case search definition */
struct test_case_search {
char name [ NAME_SIZE_MAX ] ; /* Test case name */
u32 name_size ; /* Test case name size */
u32 offset ; /* Test case offset */
} ;
/* Test case field definition */
struct test_case_field {
char * name ; /* Test case name */
u32 name_size ; /* Test case name size */
u32 type ; /* Test case type */
u32 * bufptr ; /* Buffer to store value information */
u32 exist_or_not ; /* Test case exist or not */
u32 data_num ; /* Buffer data number */
u32 line_num ; /* Buffer line number */
} ;
/* Test case type */
enum test_case_type {
TEST_CASE_TYPE_NO ,
TEST_CASE_TYPE_ONE ,
TEST_CASE_TYPE_MUL ,
TEST_CASE_TYPE_MUL_LINES ,
} ;
/* Test case order in test_case_field_array */
enum case_order {
CM_TEST_INPUTS ,
CM_EXCLUDING_COL_EDGE ,
CM_EXCLUDING_ROW_EDGE ,
CM_GRADIENT_CHECK_COL ,
CM_GRADIENT_CHECK_ROW ,
CM_RANGE_LIMIT_ROW ,
CM_RANGE_LIMIT_COL ,
CM_MIN_LIMIT_CAL ,
CM_MAX_LIMIT_CAL ,
CM_MAX_DELTA_SENSOR_PERCENT ,
CM_MAX_DELTA_BUTTON_PERCENT ,
PER_ELEMENT_MIN_MAX_TABLE_BUTTON ,
PER_ELEMENT_MIN_MAX_TABLE_SENSOR ,
CP_TEST_INPUTS ,
CP_MAX_DELTA_SENSOR_RX_PERCENT ,
CP_MAX_DELTA_SENSOR_TX_PERCENT ,
CP_MAX_DELTA_BUTTON_PERCENT ,
CP_PER_ELEMENT_MIN_MAX_BUTTON ,
MIN_BUTTON ,
MAX_BUTTON ,
PER_ELEMENT_MIN_MAX_RX ,
PER_ELEMENT_MIN_MAX_TX ,
CASE_ORDER_MAX ,
} ;
enum cmcp_test_item {
CMCP_FULL = 0 ,
CMCP_CM_PANEL ,
CMCP_CP_PANEL ,
CMCP_CM_BTN ,
CMCP_CP_BTN ,
} ;
# define CM_ENABLED 0x10
# define CP_ENABLED 0x20
# define CM_PANEL (0x01 | CM_ENABLED)
# define CP_PANEL (0x02 | CP_ENABLED)
# define CM_BTN (0x04 | CM_ENABLED)
# define CP_BTN (0x08 | CP_ENABLED)
# define CMCP_FULL_CASE\
( CM_PANEL | CP_PANEL | CM_BTN | CP_BTN | CM_ENABLED | CP_ENABLED )
# define CYTTSP5_DEVICE_ACCESS_NAME "cyttsp5_device_access"
# define CYTTSP5_INPUT_ELEM_SZ (sizeof("0xHH") + 1)
# define STATUS_SUCCESS 0
# define STATUS_FAIL -1
# define PIP_CMD_MAX_LENGTH ((1 << 16) - 1)
# ifdef TTHE_TUNER_SUPPORT
struct heatmap_param {
bool scan_start ;
enum scan_data_type_list data_type ; /* raw, base, diff */
int num_element ;
} ;
# endif
# define ABS(x) (((x) < 0) ? -(x) : (x))
# define CY_MAX_CONFIG_BYTES 256
# define CYTTSP5_TTHE_TUNER_GET_PANEL_DATA_FILE_NAME "get_panel_data"
# define TTHE_TUNER_MAX_BUF (CY_MAX_PRBUF_SIZE * 3)
struct cyttsp5_device_access_data {
struct device * dev ;
struct cyttsp5_sysinfo * si ;
struct mutex sysfs_lock ;
u8 status ;
u16 response_length ;
bool sysfs_nodes_created ;
struct kobject mfg_test ;
u8 panel_scan_data_id ;
u8 get_idac_data_id ;
u8 calibrate_sensing_mode ;
u8 calibrate_initialize_baselines ;
u8 baseline_sensing_mode ;
# ifdef TTHE_TUNER_SUPPORT
struct heatmap_param heatmap ;
struct dentry * tthe_get_panel_data_debugfs ;
struct mutex debugfs_lock ;
u8 tthe_get_panel_data_buf [ TTHE_TUNER_MAX_BUF ] ;
u8 tthe_get_panel_data_is_open ;
# endif
struct dentry * cmcp_results_debugfs ;
struct dentry * base_dentry ;
struct dentry * mfg_test_dentry ;
u8 ic_buf [ CY_MAX_PRBUF_SIZE ] ;
u8 response_buf [ CY_MAX_PRBUF_SIZE ] ;
struct mutex cmcp_threshold_lock ;
u8 * cmcp_threshold_data ;
int cmcp_threshold_size ;
bool cmcp_threshold_loading ;
struct work_struct cmcp_threshold_update ;
struct completion builtin_cmcp_threshold_complete ;
int builtin_cmcp_threshold_status ;
bool is_manual_upgrade_enabled ;
struct configuration * configs ;
struct cmcp_data * cmcp_info ;
struct result * result ;
struct test_case_search * test_search_array ;
struct test_case_field * test_field_array ;
int cmcp_test_items ;
int test_executed ;
int cmcp_range_check ;
int cmcp_force_calibrate ;
int cmcp_test_in_progress ;
} ;
struct cmcp_data {
struct gd_sensor * gd_sensor_col ;
struct gd_sensor * gd_sensor_row ;
int32_t * cm_data_panel ;
int32_t * cp_tx_data_panel ;
int32_t * cp_rx_data_panel ;
int32_t * cp_tx_cal_data_panel ;
int32_t * cp_rx_cal_data_panel ;
int32_t cp_sensor_rx_delta ;
int32_t cp_sensor_tx_delta ;
int32_t cp_button_delta ;
int32_t * cm_btn_data ;
int32_t * cp_btn_data ;
int32_t * cm_sensor_column_delta ;
int32_t * cm_sensor_row_delta ;
int32_t cp_btn_cal ;
int32_t cm_btn_cal ;
int32_t cp_button_ave ;
int32_t cm_ave_data_panel ;
int32_t cp_tx_ave_data_panel ;
int32_t cp_rx_ave_data_panel ;
int32_t cm_cal_data_panel ;
int32_t cm_ave_data_btn ;
int32_t cm_cal_data_btn ;
int32_t cm_delta_data_btn ;
int32_t cm_sensor_delta ;
int32_t tx_num ;
int32_t rx_num ;
int32_t btn_num ;
} ;
struct result {
int32_t sensor_assignment ;
int32_t config_ver ;
int32_t revision_ctrl ;
int32_t device_id_high ;
int32_t device_id_low ;
bool cm_test_run ;
bool cp_test_run ;
/* Sensor Cm validation */
bool cm_test_pass ;
bool cm_sensor_validation_pass ;
bool cm_sensor_row_delta_pass ;
bool cm_sensor_col_delta_pass ;
bool cm_sensor_gd_row_pass ;
bool cm_sensor_gd_col_pass ;
bool cm_sensor_calibration_pass ;
bool cm_sensor_delta_pass ;
bool cm_button_validation_pass ;
bool cm_button_delta_pass ;
int32_t * cm_sensor_raw_data ;
int32_t cm_sensor_calibration ;
int32_t cm_sensor_delta ;
int32_t * cm_button_raw_data ;
int32_t cm_button_delta ;
/* Sensor Cp validation */
bool cp_test_pass ;
bool cp_sensor_delta_pass ;
bool cp_sensor_rx_delta_pass ;
bool cp_sensor_tx_delta_pass ;
bool cp_sensor_average_pass ;
bool cp_button_delta_pass ;
bool cp_button_average_pass ;
bool cp_rx_validation_pass ;
bool cp_tx_validation_pass ;
bool cp_button_validation_pass ;
int32_t * cp_sensor_rx_raw_data ;
int32_t * cp_sensor_tx_raw_data ;
int32_t cp_sensor_rx_delta ;
int32_t cp_sensor_tx_delta ;
int32_t cp_sensor_rx_calibration ;
int32_t cp_sensor_tx_calibration ;
int32_t * cp_button_raw_data ;
int32_t cp_button_delta ;
/*other validation*/
bool short_test_pass ;
bool test_summary ;
uint8_t * cm_open_pwc ;
} ;
static struct cyttsp5_core_commands * cmd ;
static struct cyttsp5_module device_access_module ;
static ssize_t cyttsp5_run_and_get_selftest_result_noprint ( struct device * dev ,
char * buf , size_t buf_len , u8 test_id , u16 read_length ,
bool get_result_on_pass ) ;
static int _cyttsp5_calibrate_idacs_cmd ( struct device * dev ,
u8 sensing_mode , u8 * status ) ;
static inline struct cyttsp5_device_access_data * cyttsp5_get_device_access_data (
struct device * dev )
{
return cyttsp5_get_module_data ( dev , & device_access_module ) ;
}
static ssize_t cyttsp5_status_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
u8 val ;
mutex_lock ( & dad - > sysfs_lock ) ;
val = dad - > status ;
mutex_unlock ( & dad - > sysfs_lock ) ;
return scnprintf ( buf , CY_MAX_PRBUF_SIZE , " %d \n " , val ) ;
}
static DEVICE_ATTR ( status , S_IRUSR , cyttsp5_status_show , NULL ) ;
static ssize_t cyttsp5_response_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
int i ;
ssize_t num_read ;
int index ;
mutex_lock ( & dad - > sysfs_lock ) ;
index = scnprintf ( buf , CY_MAX_PRBUF_SIZE ,
" Status %d \n " , dad - > status ) ;
if ( ! dad - > status )
goto error ;
num_read = dad - > response_length ;
for ( i = 0 ; i < num_read ; i + + )
index + = scnprintf ( buf + index , CY_MAX_PRBUF_SIZE - index ,
" 0x%02X \n " , dad - > response_buf [ i ] ) ;
index + = scnprintf ( buf + index , CY_MAX_PRBUF_SIZE - index ,
" (%zd bytes) \n " , num_read ) ;
error :
mutex_unlock ( & dad - > sysfs_lock ) ;
return index ;
}
static DEVICE_ATTR ( response , S_IRUSR , cyttsp5_response_show , NULL ) ;
/*
* Gets user input from sysfs and parse it
* return size of parsed output buffer
*/
static int cyttsp5_ic_parse_input ( struct device * dev , const char * buf ,
size_t buf_size , u8 * ic_buf , size_t ic_buf_size )
{
const char * pbuf = buf ;
unsigned long value ;
char scan_buf [ CYTTSP5_INPUT_ELEM_SZ ] ;
u32 i = 0 ;
u32 j ;
int last = 0 ;
int ret ;
dev_dbg ( dev , " %s: pbuf=%p buf=%p size=%zu %s=%zu buf=%s \n " , __func__ ,
pbuf , buf , buf_size , " scan buf size " ,
CYTTSP5_INPUT_ELEM_SZ , buf ) ;
while ( pbuf < = ( buf + buf_size ) ) {
if ( i > = CY_MAX_CONFIG_BYTES ) {
dev_err ( dev , " %s: %s size=%d max=%d \n " , __func__ ,
" Max cmd size exceeded " , i ,
CY_MAX_CONFIG_BYTES ) ;
return - EINVAL ;
}
if ( i > = ic_buf_size ) {
dev_err ( dev , " %s: %s size=%d buf_size=%zu \n " , __func__ ,
" Buffer size exceeded " , i , ic_buf_size ) ;
return - EINVAL ;
}
while ( ( ( * pbuf = = ' ' ) | | ( * pbuf = = ' , ' ) )
& & ( pbuf < ( buf + buf_size ) ) ) {
last = * pbuf ;
pbuf + + ;
}
if ( pbuf > = ( buf + buf_size ) )
break ;
memset ( scan_buf , 0 , CYTTSP5_INPUT_ELEM_SZ ) ;
if ( ( last = = ' , ' ) & & ( * pbuf = = ' , ' ) ) {
dev_err ( dev , " %s: %s \" ,, \" not allowed. \n " , __func__ ,
" Invalid data format. " ) ;
return - EINVAL ;
}
for ( j = 0 ; j < ( CYTTSP5_INPUT_ELEM_SZ - 1 )
& & ( pbuf < ( buf + buf_size ) )
& & ( * pbuf ! = ' ' )
& & ( * pbuf ! = ' , ' ) ; j + + ) {
last = * pbuf ;
scan_buf [ j ] = * pbuf + + ;
}
ret = kstrtoul ( scan_buf , 16 , & value ) ;
if ( ret < 0 ) {
dev_err ( dev , " %s: %s '%s' %s%s i=%d r=%d \n " , __func__ ,
" Invalid data format. " , scan_buf ,
" Use \" 0xHH,...,0xHH \" " , " instead. " ,
i , ret ) ;
return ret ;
}
ic_buf [ i ] = value ;
i + + ;
}
return i ;
}
static ssize_t cyttsp5_command_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
ssize_t length ;
int rc ;
mutex_lock ( & dad - > sysfs_lock ) ;
dad - > status = 0 ;
dad - > response_length = 0 ;
length = cyttsp5_ic_parse_input ( dev , buf , size , dad - > ic_buf ,
CY_MAX_PRBUF_SIZE ) ;
if ( length < = 0 ) {
dev_err ( dev , " %s: %s Group Data store \n " , __func__ ,
" Malformed input for " ) ;
goto exit ;
}
/* write ic_buf to log */
cyttsp5_pr_buf ( dev , dad - > ic_buf , length , " ic_buf " ) ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > nonhid_cmd - > user_cmd ( dev , 1 , CY_MAX_PRBUF_SIZE ,
dad - > response_buf , length , dad - > ic_buf ,
& dad - > response_length ) ;
pm_runtime_put ( dev ) ;
if ( rc ) {
dad - > response_length = 0 ;
dev_err ( dev , " %s: Failed to store command \n " , __func__ ) ;
} else {
dad - > status = 1 ;
}
exit :
mutex_unlock ( & dad - > sysfs_lock ) ;
dev_vdbg ( dev , " %s: return size=%zu \n " , __func__ , size ) ;
return size ;
}
static DEVICE_ATTR ( command , S_IWUSR , NULL , cyttsp5_command_store ) ;
static int cmcp_check_config_fw_match ( struct device * dev ,
struct configuration * configuration )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
int32_t tx_num = dad - > configs - > tx_num ;
int32_t rx_num = dad - > configs - > rx_num ;
int32_t button_num = dad - > configs - > btn_num ;
int ret = 0 ;
if ( tx_num ! = dad - > si - > sensing_conf_data . tx_num ) {
dev_err ( dev , " %s: TX number mismatch! \n " , __func__ ) ;
ret = - EINVAL ;
}
if ( rx_num ! = dad - > si - > sensing_conf_data . rx_num ) {
dev_err ( dev , " %s: RX number mismatch! \n " , __func__ ) ;
ret = - EINVAL ;
}
if ( button_num ! = dad - > si - > num_btns ) {
dev_err ( dev , " %s: Button number mismatch! \n " , __func__ ) ;
ret = - EINVAL ;
}
return ret ;
}
static int validate_cm_test_results ( struct device * dev ,
struct configuration * configuration , struct cmcp_data * cmcp_info ,
struct result * result , bool * pass , int test_item )
{
int32_t tx_num = cmcp_info - > tx_num ;
int32_t rx_num = cmcp_info - > rx_num ;
int32_t button_num = cmcp_info - > btn_num ;
uint32_t sensor_num = tx_num * rx_num ;
int32_t * cm_sensor_data = cmcp_info - > cm_data_panel ;
int32_t cm_button_delta ;
int32_t cm_sensor_calibration ;
int32_t * cm_button_data = cmcp_info - > cm_btn_data ;
struct gd_sensor * gd_sensor_col = cmcp_info - > gd_sensor_col ;
struct gd_sensor * gd_sensor_row = cmcp_info - > gd_sensor_row ;
int32_t * cm_sensor_column_delta = cmcp_info - > cm_sensor_column_delta ;
int32_t * cm_sensor_row_delta = cmcp_info - > cm_sensor_row_delta ;
int ret = 0 ;
int i , j ;
dev_vdbg ( dev , " %s: start \n " , __func__ ) ;
if ( ( test_item & CM_PANEL ) = = CM_PANEL ) {
dev_vdbg ( dev , " Check each sensor Cm data for min max value \n " ) ;
/* Check each sensor Cm data for min/max values */
result - > cm_sensor_validation_pass = true ;
for ( i = 0 ; i < sensor_num ; i + + ) {
int row = i % rx_num ;
int col = i / rx_num ;
int32_t cm_sensor_min =
configuration - > cm_min_max_table_sensor [ ( row * tx_num + col ) * 2 ] ;
int32_t cm_sensor_max =
configuration - > cm_min_max_table_sensor [ ( row * tx_num + col ) * 2 + 1 ] ;
if ( ( cm_sensor_data [ i ] < cm_sensor_min )
| | ( cm_sensor_data [ i ] > cm_sensor_max ) ) {
dev_err ( dev , " %s: Sensor[%d,%d]:%d (%d,%d) \n " ,
" Cm sensor min/max test " ,
row , col ,
cm_sensor_data [ i ] ,
cm_sensor_min , cm_sensor_max ) ;
result - > cm_sensor_validation_pass = false ;
}
}
/*check cm gradient column data*/
result - > cm_sensor_gd_col_pass = true ;
for ( i = 0 ;
i < configuration - > cm_max_table_gradient_cols_percent_size ;
i + + ) {
if ( ( gd_sensor_col + i ) - > gradient_val >
10 * configuration - > cm_max_table_gradient_cols_percent [ i ] ) {
dev_err ( dev ,
" %s: cm_max_table_gradient_cols_percent[%d]:%d, gradient_val:%d \n " ,
__func__ ,
i ,
configuration - > cm_max_table_gradient_cols_percent [ i ] ,
( gd_sensor_col + i ) - > gradient_val ) ;
result - > cm_sensor_gd_col_pass = false ;
}
}
/*check cm gradient row data*/
result - > cm_sensor_gd_row_pass = true ;
for ( j = 0 ;
j < configuration - > cm_max_table_gradient_rows_percent_size ;
j + + ) {
if ( ( gd_sensor_row + j ) - > gradient_val >
10 * configuration - > cm_max_table_gradient_rows_percent [ j ] ) {
dev_err ( dev ,
" %s: cm_max_table_gradient_rows_percent[%d]:%d, gradient_val:%d \n " ,
__func__ ,
j , configuration - > cm_max_table_gradient_rows_percent [ j ] ,
( gd_sensor_row + j ) - > gradient_val ) ;
result - > cm_sensor_gd_row_pass = false ;
}
}
result - > cm_sensor_row_delta_pass = true ;
result - > cm_sensor_col_delta_pass = true ;
result - > cm_sensor_calibration_pass = true ;
result - > cm_sensor_delta_pass = true ;
/*
Check each row Cm data
with neighbor for difference
*/
for ( i = 0 ; i < tx_num ; i + + ) {
for ( j = 1 ; j < rx_num ; j + + ) {
int32_t cm_sensor_row_diff =
ABS ( cm_sensor_data [ i * rx_num + j ] -
cm_sensor_data [ i * rx_num + j - 1 ] ) ;
cm_sensor_row_delta [ i * rx_num + j - 1 ] =
cm_sensor_row_diff ;
if ( cm_sensor_row_diff
> configuration - > cm_range_limit_row ) {
dev_err ( dev ,
" %s: Sensor[%d,%d]:%d (%d) \n " ,
" Cm sensor row range limit test " ,
j , i ,
cm_sensor_row_diff ,
configuration - > cm_range_limit_row ) ;
result - > cm_sensor_row_delta_pass = false ;
}
}
}
/* Check each column Cm data
with neighbor for difference
*/
for ( i = 1 ; i < tx_num ; i + + ) {
for ( j = 0 ; j < rx_num ; j + + ) {
int32_t cm_sensor_col_diff =
ABS ( ( int ) cm_sensor_data [ i * rx_num + j ] -
( int ) cm_sensor_data [ ( i - 1 ) * rx_num + j ] ) ;
cm_sensor_column_delta [ ( i - 1 ) * rx_num + j ] =
cm_sensor_col_diff ;
if ( cm_sensor_col_diff >
configuration - > cm_range_limit_col ) {
dev_err ( dev ,
" %s: Sensor[%d,%d]:%d (%d) \n " ,
" Cm sensor column range limit test " ,
j , i ,
cm_sensor_col_diff ,
configuration - > cm_range_limit_col ) ;
result - > cm_sensor_col_delta_pass = false ;
}
}
}
/* Check sensor calculated Cm for min/max values */
cm_sensor_calibration = cmcp_info - > cm_cal_data_panel ;
if ( cm_sensor_calibration <
configuration - > cm_min_limit_cal
| | cm_sensor_calibration >
configuration - > cm_max_limit_cal ) {
dev_err ( dev , " %s: Cm_cal:%d (%d,%d) \n " ,
" Cm sensor Cm_cal min/max test " ,
cm_sensor_calibration ,
configuration - > cm_min_limit_cal ,
configuration - > cm_max_limit_cal ) ;
result - > cm_sensor_calibration_pass = false ;
}
/* Check sensor Cm delta for range limit */
if ( cmcp_info - > cm_sensor_delta
> 10 * configuration - > cm_max_delta_sensor_percent ) {
dev_err ( dev ,
" %s: Cm_sensor_delta:%d (%d) \n " ,
" Cm sensor delta range limit test " ,
cmcp_info - > cm_sensor_delta ,
configuration - > cm_max_delta_sensor_percent ) ;
result - > cm_sensor_delta_pass = false ;
}
result - > cm_test_pass = result - > cm_sensor_gd_col_pass
& & result - > cm_sensor_gd_row_pass
& & result - > cm_sensor_validation_pass
& & result - > cm_sensor_row_delta_pass
& & result - > cm_sensor_col_delta_pass
& & result - > cm_sensor_calibration_pass
& & result - > cm_sensor_delta_pass ;
}
if ( ( ( test_item & CM_BTN ) = = CM_BTN ) & & ( cmcp_info - > btn_num ) ) {
/* Check each button Cm data for min/max values */
result - > cm_button_validation_pass = true ;
for ( i = 0 ; i < button_num ; i + + ) {
int32_t cm_button_min =
configuration - > cm_min_max_table_button [ i * 2 ] ;
int32_t cm_button_max =
configuration - > cm_min_max_table_button [ i * 2 + 1 ] ;
if ( ( cm_button_data [ i ] < = cm_button_min )
| | ( cm_button_data [ i ] > = cm_button_max ) ) {
dev_err ( dev ,
" %s: Button[%d]:%d (%d,%d) \n " ,
" Cm button min/max test " ,
i ,
cm_button_data [ i ] ,
cm_button_min , cm_button_max ) ;
result - > cm_button_validation_pass = false ;
}
}
/* Check button Cm delta for range limit */
result - > cm_button_delta_pass = true ;
cm_button_delta = ABS ( ( cmcp_info - > cm_ave_data_btn -
cmcp_info - > cm_cal_data_btn ) * 100 /
cmcp_info - > cm_ave_data_btn ) ;
if ( cm_button_delta >
configuration - > cm_max_delta_button_percent ) {
dev_err ( dev ,
" %s: Cm_button_delta:%d (%d) \n " ,
" Cm button delta range limit test " ,
cm_button_delta ,
configuration - > cm_max_delta_button_percent ) ;
result - > cm_button_delta_pass = false ;
}
result - > cm_test_pass = result - > cm_test_pass
& & result - > cm_button_validation_pass
& & result - > cm_button_delta_pass ;
}
if ( pass )
* pass = result - > cm_test_pass ;
return ret ;
}
static int validate_cp_test_results ( struct device * dev ,
struct configuration * configuration , struct cmcp_data * cmcp_info ,
struct result * result , bool * pass , int test_item )
{
int i = 0 ;
uint32_t configuration_rx_num ;
uint32_t configuration_tx_num ;
int32_t * cp_sensor_tx_data = cmcp_info - > cp_tx_data_panel ;
int32_t * cp_sensor_rx_data = cmcp_info - > cp_rx_data_panel ;
int32_t cp_button_delta ;
int32_t cp_button_average ;
result - > cp_test_pass = true ;
configuration_rx_num = configuration - > cp_min_max_table_rx_size / 2 ;
configuration_tx_num = configuration - > cp_min_max_table_tx_size / 2 ;
dev_vdbg ( dev , " %s start \n " , __func__ ) ;
if ( ( test_item & CP_PANEL ) = = CP_PANEL ) {
int32_t cp_sensor_tx_delta ;
int32_t cp_sensor_rx_delta ;
/* Check Sensor Cp delta for range limit */
result - > cp_sensor_delta_pass = true ;
/*check cp_sensor_tx_delta */
for ( i = 0 ; i < configuration_tx_num ; i + + ) {
cp_sensor_tx_delta =
ABS ( ( cmcp_info - > cp_tx_cal_data_panel [ i ] -
cmcp_info - > cp_tx_data_panel [ i ] ) * 100 /
cmcp_info - > cp_tx_data_panel [ i ] ) ;
if ( cp_sensor_tx_delta >
configuration - > cp_max_delta_sensor_tx_percent ) {
dev_err ( dev ,
" %s: Cp_sensor_tx_delta:%d (%d) \n " ,
" Cp sensor delta range limit test " ,
cp_sensor_tx_delta ,
configuration - > cp_max_delta_sensor_tx_percent ) ;
result - > cp_sensor_delta_pass = false ;
}
}
/*check cp_sensor_rx_delta */
for ( i = 0 ; i < configuration_rx_num ; i + + ) {
cp_sensor_rx_delta =
ABS ( ( cmcp_info - > cp_rx_cal_data_panel [ i ] -
cmcp_info - > cp_rx_data_panel [ i ] ) * 100 /
cmcp_info - > cp_rx_data_panel [ i ] ) ;
if ( cp_sensor_rx_delta >
configuration - > cp_max_delta_sensor_rx_percent ) {
dev_err ( dev ,
" %s: Cp_sensor_rx_delta:%d(%d) \n " ,
" Cp sensor delta range limit test " ,
cp_sensor_rx_delta ,
configuration - > cp_max_delta_sensor_rx_percent ) ;
result - > cp_sensor_delta_pass = false ;
}
}
/* Check sensor Cp rx for min/max values */
result - > cp_rx_validation_pass = true ;
for ( i = 0 ; i < configuration_rx_num ; i + + ) {
int32_t cp_rx_min =
configuration - > cp_min_max_table_rx [ i * 2 ] ;
int32_t cp_rx_max =
configuration - > cp_min_max_table_rx [ i * 2 + 1 ] ;
if ( ( cp_sensor_rx_data [ i ] < = cp_rx_min )
| | ( cp_sensor_rx_data [ i ] > = cp_rx_max ) ) {
dev_err ( dev ,
" %s: Cp Rx[%d]:%d (%d,%d) \n " ,
" Cp Rx min/max test " ,
i ,
( int ) cp_sensor_rx_data [ i ] ,
cp_rx_min , cp_rx_max ) ;
result - > cp_rx_validation_pass = false ;
}
}
/* Check sensor Cp tx for min/max values */
result - > cp_tx_validation_pass = true ;
for ( i = 0 ; i < configuration_tx_num ; i + + ) {
int32_t cp_tx_min =
configuration - > cp_min_max_table_tx [ i * 2 ] ;
int32_t cp_tx_max =
configuration - > cp_min_max_table_tx [ i * 2 + 1 ] ;
if ( ( cp_sensor_tx_data [ i ] < = cp_tx_min )
| | ( cp_sensor_tx_data [ i ] > = cp_tx_max ) ) {
dev_err ( dev ,
" %s: Cp Tx[%d]:%d(%d,%d) \n " ,
" Cp Tx min/max test " ,
i ,
cp_sensor_tx_data [ i ] ,
cp_tx_min , cp_tx_max ) ;
result - > cp_tx_validation_pass = false ;
}
}
result - > cp_test_pass = result - > cp_test_pass
& & result - > cp_sensor_delta_pass
& & result - > cp_rx_validation_pass
& & result - > cp_tx_validation_pass ;
}
if ( ( ( test_item & CP_BTN ) = = CP_BTN ) & & ( cmcp_info - > btn_num ) ) {
result - > cp_button_delta_pass = true ;
/* Check button Cp delta for range limit */
cp_button_delta = ABS ( ( cmcp_info - > cp_btn_cal
- cmcp_info - > cp_button_ave ) * 100 /
cmcp_info - > cp_button_ave ) ;
if ( cp_button_delta >
configuration - > cp_max_delta_button_percent ) {
dev_err ( dev ,
" %s: Cp_button_delta:%d (%d) \n " ,
" Cp button delta range limit test " ,
cp_button_delta ,
configuration - > cp_max_delta_button_percent ) ;
result - > cp_button_delta_pass = false ;
}
/* Check button Cp average for min/max values */
result - > cp_button_average_pass = true ;
cp_button_average = cmcp_info - > cp_button_ave ;
if ( cp_button_average < configuration - > min_button
| | cp_button_average >
configuration - > max_button ) {
dev_err ( dev ,
" %s: Button Cp average fails min/max test \n " ,
__func__ ) ;
dev_err ( dev ,
" %s: Cp_button_average:%d (%d,%d) \n " ,
" Cp button average min/max test " ,
cp_button_average ,
configuration - > min_button ,
configuration - > max_button ) ;
result - > cp_button_average_pass = false ;
}
/* Check each button Cp data for min/max values */
result - > cp_button_validation_pass = true ;
for ( i = 0 ; i < cmcp_info - > btn_num ; i + + ) {
int32_t cp_button_min =
configuration - > cp_min_max_table_button [ i * 2 ] ;
int32_t cp_button_max =
configuration - > cp_min_max_table_button [ i * 2 + 1 ] ;
if ( ( cmcp_info - > cp_btn_data [ i ] < = cp_button_min )
| | ( cmcp_info - > cp_btn_data [ i ] > = cp_button_max ) ) {
dev_err ( dev ,
" %s: Button[%d]:%d (%d,%d) \n " ,
" Cp button min/max test " ,
i ,
cmcp_info - > cp_btn_data [ i ] ,
cp_button_min , cp_button_max ) ;
result - > cp_button_validation_pass = false ;
}
}
result - > cp_test_pass = result - > cp_test_pass
& & result - > cp_button_delta_pass
& & result - > cp_button_average_pass
& & result - > cp_button_validation_pass ;
}
if ( pass )
* pass = result - > cp_test_pass ;
return 0 ;
}
static void calculate_gradient_row ( struct gd_sensor * gd_sensor_row_head ,
uint16_t row_num , int exclude_row_edge , int exclude_col_edge )
{
int i = 0 ;
uint16_t cm_min_cur = 0 ;
uint16_t cm_max_cur = 0 ;
uint16_t cm_ave_cur = 0 ;
uint16_t cm_ave_next = 0 ;
uint16_t cm_ave_prev = 0 ;
struct gd_sensor * p = gd_sensor_row_head ;
if ( exclude_row_edge ) {
for ( i = 0 ; i < row_num ; i + + ) {
if ( ! exclude_col_edge ) {
cm_ave_cur = ( p + i ) - > cm_ave ;
cm_min_cur = ( p + i ) - > cm_min ;
cm_max_cur = ( p + i ) - > cm_max ;
if ( i < ( row_num - 1 ) )
cm_ave_next = ( p + i + 1 ) - > cm_ave ;
if ( i > 0 )
cm_ave_prev = ( p + i - 1 ) - > cm_ave ;
} else {
cm_ave_cur = ( p + i ) - > cm_ave_exclude_edge ;
cm_min_cur = ( p + i ) - > cm_min_exclude_edge ;
cm_max_cur = ( p + i ) - > cm_max_exclude_edge ;
if ( i < ( row_num - 1 ) )
cm_ave_next =
( p + i + 1 ) - > cm_ave_exclude_edge ;
if ( i > 0 )
cm_ave_prev =
( p + i - 1 ) - > cm_ave_exclude_edge ;
}
if ( cm_ave_cur = = 0 )
cm_ave_cur = 1 ;
/*multiple 1000 to increate accuracy*/
if ( ( i = = 0 ) | | ( i = = ( row_num - 1 ) ) ) {
( p + i ) - > gradient_val =
( cm_max_cur - cm_min_cur ) * 1000 /
cm_ave_cur ;
} else if ( i = = 1 ) {
( p + i ) - > gradient_val = ( cm_max_cur - cm_min_cur
+ ABS ( cm_ave_cur - cm_ave_next ) ) * 1000 /
cm_ave_cur ;
} else {
( p + i ) - > gradient_val = ( cm_max_cur - cm_min_cur
+ ABS ( cm_ave_cur - cm_ave_prev ) ) * 1000 /
cm_ave_cur ;
}
}
} else if ( ! exclude_row_edge ) {
for ( i = 0 ; i < row_num ; i + + ) {
if ( ! exclude_col_edge ) {
cm_ave_cur = ( p + i ) - > cm_ave ;
cm_min_cur = ( p + i ) - > cm_min ;
cm_max_cur = ( p + i ) - > cm_max ;
if ( i < ( row_num - 1 ) )
cm_ave_next = ( p + i + 1 ) - > cm_ave ;
if ( i > 0 )
cm_ave_prev = ( p + i - 1 ) - > cm_ave ;
} else {
cm_ave_cur = ( p + i ) - > cm_ave_exclude_edge ;
cm_min_cur = ( p + i ) - > cm_min_exclude_edge ;
cm_max_cur = ( p + i ) - > cm_max_exclude_edge ;
if ( i < ( row_num - 1 ) )
cm_ave_next =
( p + i + 1 ) - > cm_ave_exclude_edge ;
if ( i > 0 )
cm_ave_prev =
( p + i - 1 ) - > cm_ave_exclude_edge ;
}
if ( cm_ave_cur = = 0 )
cm_ave_cur = 1 ;
/*multiple 1000 to increate accuracy*/
if ( i < = 1 )
( p + i ) - > gradient_val = ( cm_max_cur - cm_min_cur
+ ABS ( cm_ave_cur - cm_ave_next ) ) * 1000 /
cm_ave_cur ;
else
( p + i ) - > gradient_val = ( cm_max_cur - cm_min_cur
+ ABS ( cm_ave_cur - cm_ave_prev ) ) * 1000 /
cm_ave_cur ;
}
}
}
static void calculate_gradient_col ( struct gd_sensor * gd_sensor_row_head ,
uint16_t col_num , int exclude_row_edge , int exclude_col_edge )
{
int i = 0 ;
int32_t cm_min_cur = 0 ;
int32_t cm_max_cur = 0 ;
int32_t cm_ave_cur = 0 ;
int32_t cm_ave_next = 0 ;
int32_t cm_ave_prev = 0 ;
struct gd_sensor * p = gd_sensor_row_head ;
if ( ! exclude_col_edge ) {
for ( i = 0 ; i < col_num ; i + + ) {
if ( ! exclude_row_edge ) {
cm_ave_cur = ( p + i ) - > cm_ave ;
cm_min_cur = ( p + i ) - > cm_min ;
cm_max_cur = ( p + i ) - > cm_max ;
if ( i < ( col_num - 1 ) )
cm_ave_next = ( p + i + 1 ) - > cm_ave ;
if ( i > 0 )
cm_ave_prev = ( p + i - 1 ) - > cm_ave ;
} else {
cm_ave_cur = ( p + i ) - > cm_ave_exclude_edge ;
cm_min_cur = ( p + i ) - > cm_min_exclude_edge ;
cm_max_cur = ( p + i ) - > cm_max_exclude_edge ;
if ( i < ( col_num - 1 ) )
cm_ave_next =
( p + i + 1 ) - > cm_ave_exclude_edge ;
if ( i > 0 )
cm_ave_prev =
( p + i - 1 ) - > cm_ave_exclude_edge ;
}
if ( cm_ave_cur = = 0 )
cm_ave_cur = 1 ;
/*multiple 1000 to increate accuracy*/
if ( i < = 1 )
( p + i ) - > gradient_val = ( cm_max_cur - cm_min_cur
+ ABS ( cm_ave_cur - cm_ave_next ) ) * 1000 /
cm_ave_cur ;
else
( p + i ) - > gradient_val = ( cm_max_cur - cm_min_cur
+ ABS ( cm_ave_cur - cm_ave_prev ) ) * 1000 /
cm_ave_cur ;
}
} else if ( exclude_col_edge ) {
for ( i = 0 ; i < col_num ; i + + ) {
if ( ! exclude_row_edge ) {
cm_ave_cur = ( p + i ) - > cm_ave ;
cm_min_cur = ( p + i ) - > cm_min ;
cm_max_cur = ( p + i ) - > cm_max ;
if ( i < ( col_num - 1 ) )
cm_ave_next = ( p + i + 1 ) - > cm_ave ;
if ( i > 0 )
cm_ave_prev = ( p + i - 1 ) - > cm_ave ;
} else {
cm_ave_cur = ( p + i ) - > cm_ave_exclude_edge ;
cm_min_cur = ( p + i ) - > cm_min_exclude_edge ;
cm_max_cur = ( p + i ) - > cm_max_exclude_edge ;
if ( i < ( col_num - 1 ) )
cm_ave_next =
( p + i + 1 ) - > cm_ave_exclude_edge ;
if ( i > 0 )
cm_ave_prev =
( p + i - 1 ) - > cm_ave_exclude_edge ;
}
if ( cm_ave_cur = = 0 )
cm_ave_cur = 1 ;
/*multiple 1000 to increate accuracy*/
if ( ( i = = 0 ) | | ( i = = ( col_num - 1 ) ) )
( p + i ) - > gradient_val =
( cm_max_cur - cm_min_cur ) * 1000 /
cm_ave_cur ;
else if ( i = = 1 )
( p + i ) - > gradient_val =
( cm_max_cur - cm_min_cur +
ABS ( cm_ave_cur - cm_ave_next ) )
* 1000 / cm_ave_cur ;
else
( p + i ) - > gradient_val =
( cm_max_cur - cm_min_cur +
ABS ( cm_ave_cur - cm_ave_prev ) )
* 1000 / cm_ave_cur ;
}
}
}
static void fill_gd_sensor_table ( struct gd_sensor * head , int32_t index ,
int32_t cm_max , int32_t cm_min , int32_t cm_ave ,
int32_t cm_max_exclude_edge , int32_t cm_min_exclude_edge ,
int32_t cm_ave_exclude_edge )
{
( head + index ) - > cm_max = cm_max ;
( head + index ) - > cm_min = cm_min ;
( head + index ) - > cm_ave = cm_ave ;
( head + index ) - > cm_ave_exclude_edge = cm_ave_exclude_edge ;
( head + index ) - > cm_max_exclude_edge = cm_max_exclude_edge ;
( head + index ) - > cm_min_exclude_edge = cm_min_exclude_edge ;
}
static void calculate_gd_info ( struct gd_sensor * gd_sensor_col ,
struct gd_sensor * gd_sensor_row , int tx_num , int rx_num ,
int32_t * cm_sensor_data , int cm_excluding_row_edge ,
int cm_excluding_col_edge )
{
int32_t cm_max ;
int32_t cm_min ;
int32_t cm_ave ;
int32_t cm_max_exclude_edge ;
int32_t cm_min_exclude_edge ;
int32_t cm_ave_exclude_edge ;
int32_t cm_data ;
int i ;
int j ;
/*calculate all the gradient related info for column*/
for ( i = 0 ; i < tx_num ; i + + ) {
/*re-initialize for a new col*/
cm_max = cm_sensor_data [ i * rx_num ] ;
cm_min = cm_max ;
cm_ave = 0 ;
cm_max_exclude_edge = cm_sensor_data [ i * rx_num + 1 ] ;
cm_min_exclude_edge = cm_max_exclude_edge ;
cm_ave_exclude_edge = 0 ;
for ( j = 0 ; j < rx_num ; j + + ) {
cm_data = cm_sensor_data [ i * rx_num + j ] ;
if ( cm_data > cm_max )
cm_max = cm_data ;
if ( cm_data < cm_min )
cm_min = cm_data ;
cm_ave + = cm_data ;
/*calculate exclude edge data*/
if ( ( j > 0 ) & & ( j < ( rx_num - 1 ) ) ) {
if ( cm_data > cm_max_exclude_edge )
cm_max_exclude_edge = cm_data ;
if ( cm_data < cm_min_exclude_edge )
cm_min_exclude_edge = cm_data ;
cm_ave_exclude_edge + = cm_data ;
}
}
cm_ave / = rx_num ;
cm_ave_exclude_edge / = ( rx_num - 2 ) ;
fill_gd_sensor_table ( gd_sensor_col , i , cm_max , cm_min , cm_ave ,
cm_max_exclude_edge , cm_min_exclude_edge , cm_ave_exclude_edge ) ;
}
calculate_gradient_col ( gd_sensor_col , tx_num , cm_excluding_row_edge ,
cm_excluding_col_edge ) ;
/*calculate all the gradient related info for row*/
for ( j = 0 ; j < rx_num ; j + + ) {
/*re-initialize for a new row*/
cm_max = cm_sensor_data [ j ] ;
cm_min = cm_max ;
cm_ave = 0 ;
cm_max_exclude_edge = cm_sensor_data [ rx_num + j ] ;
cm_min_exclude_edge = cm_max_exclude_edge ;
cm_ave_exclude_edge = 0 ;
for ( i = 0 ; i < tx_num ; i + + ) {
cm_data = cm_sensor_data [ i * rx_num + j ] ;
if ( cm_data > cm_max )
cm_max = cm_data ;
if ( cm_data < cm_min )
cm_min = cm_data ;
cm_ave + = cm_data ;
/*calculate exclude edge data*/
if ( ( i > 0 ) & & ( i < ( tx_num - 1 ) ) ) {
if ( cm_data > cm_max_exclude_edge )
cm_max_exclude_edge = cm_data ;
if ( cm_data < cm_min_exclude_edge )
cm_min_exclude_edge = cm_data ;
cm_ave_exclude_edge + = cm_data ;
}
}
cm_ave / = tx_num ;
cm_ave_exclude_edge / = ( tx_num - 2 ) ;
fill_gd_sensor_table ( gd_sensor_row , j , cm_max , cm_min , cm_ave ,
cm_max_exclude_edge , cm_min_exclude_edge , cm_ave_exclude_edge ) ;
}
calculate_gradient_row ( gd_sensor_row , rx_num , cm_excluding_row_edge ,
cm_excluding_col_edge ) ;
}
static int cyttsp5_get_cmcp_info ( struct cyttsp5_device_access_data * dad ,
struct cmcp_data * cmcp_info )
{
struct device * dev ;
int32_t * cm_data_panel = cmcp_info - > cm_data_panel ;
int32_t * cp_tx_data_panel = cmcp_info - > cp_tx_data_panel ;
int32_t * cp_rx_data_panel = cmcp_info - > cp_rx_data_panel ;
int32_t * cp_tx_cal_data_panel = cmcp_info - > cp_tx_cal_data_panel ;
int32_t * cp_rx_cal_data_panel = cmcp_info - > cp_rx_cal_data_panel ;
int32_t * cm_btn_data = cmcp_info - > cm_btn_data ;
int32_t * cp_btn_data = cmcp_info - > cp_btn_data ;
struct gd_sensor * gd_sensor_col = cmcp_info - > gd_sensor_col ;
struct gd_sensor * gd_sensor_row = cmcp_info - > gd_sensor_row ;
struct result * result = dad - > result ;
int32_t cp_btn_cal = 0 ;
int32_t cm_btn_cal = 0 ;
int32_t cp_btn_ave = 0 ;
int32_t cm_ave_data_panel = 0 ;
int32_t cm_ave_data_btn = 0 ;
int32_t cm_delta_data_btn = 0 ;
int32_t cp_tx_ave_data_panel = 0 ;
int32_t cp_rx_ave_data_panel = 0 ;
u8 tmp_buf [ 3 ] ;
int tx_num ;
int rx_num ;
int btn_num ;
int rc = 0 ;
int i ;
dev = dad - > dev ;
cmcp_info - > tx_num = dad - > si - > sensing_conf_data . tx_num ;
cmcp_info - > rx_num = dad - > si - > sensing_conf_data . rx_num ;
cmcp_info - > btn_num = dad - > si - > num_btns ;
tx_num = cmcp_info - > tx_num ;
rx_num = cmcp_info - > rx_num ;
btn_num = cmcp_info - > btn_num ;
dev_vdbg ( dev , " %s tx_num=%d " , __func__ , tx_num ) ;
dev_vdbg ( dev , " %s rx_num=%d " , __func__ , rx_num ) ;
dev_vdbg ( dev , " %s btn_num=%d " , __func__ , btn_num ) ;
/*short test*/
result - > short_test_pass = true ;
rc = cyttsp5_run_and_get_selftest_result_noprint (
dev , tmp_buf , sizeof ( tmp_buf ) ,
CY_ST_ID_AUTOSHORTS , PIP_CMD_MAX_LENGTH , false ) ;
if ( rc ) {
dev_err ( dev , " short test not supported " ) ;
goto exit ;
}
if ( dad - > ic_buf [ 1 ] ! = 0 )
result - > short_test_pass = false ;
/*Get cm_panel data*/
rc = cyttsp5_run_and_get_selftest_result_noprint (
dev , tmp_buf , sizeof ( tmp_buf ) ,
CY_ST_ID_CM_PANEL , PIP_CMD_MAX_LENGTH , true ) ;
if ( rc ) {
dev_err ( dev , " Get CM Panel not supported " ) ;
goto exit ;
}
if ( cm_data_panel ! = NULL ) {
for ( i = 0 ; i < tx_num * rx_num ; i + + ) {
cm_data_panel [ i ] =
10 * ( dad - > ic_buf [ CM_PANEL_DATA_OFFSET + i * 2 ] + 256
* dad - > ic_buf [ CM_PANEL_DATA_OFFSET + i * 2 + 1 ] ) ;
dev_vdbg ( dev ,
" cm_data_panel[%d]=%d \n " ,
i , cm_data_panel [ i ] ) ;
cm_ave_data_panel + = cm_data_panel [ i ] ;
}
cm_ave_data_panel / = ( tx_num * rx_num ) ;
cmcp_info - > cm_ave_data_panel = cm_ave_data_panel ;
cmcp_info - > cm_cal_data_panel =
10 * ( dad - > ic_buf [ CM_PANEL_DATA_OFFSET + i * 2 ]
+ 256 * dad - > ic_buf [ CM_PANEL_DATA_OFFSET + i * 2 + 1 ] ) ;
/*multiple 1000 to increate accuracy*/
cmcp_info - > cm_sensor_delta = ABS ( ( cmcp_info - > cm_ave_data_panel -
cmcp_info - > cm_cal_data_panel ) * 1000 /
cmcp_info - > cm_ave_data_panel ) ;
}
/*calculate gradient panel sensor column/row here*/
calculate_gd_info ( gd_sensor_col , gd_sensor_row , tx_num , rx_num ,
cm_data_panel , 1 , 1 ) ;
for ( i = 0 ; i < tx_num ; i + + ) {
dev_vdbg ( dev ,
" i=%d max=%d,min=%d,ave=%d, gradient=%d " ,
i , gd_sensor_col [ i ] . cm_max , gd_sensor_col [ i ] . cm_min ,
gd_sensor_col [ i ] . cm_ave , gd_sensor_col [ i ] . gradient_val ) ;
}
for ( i = 0 ; i < rx_num ; i + + ) {
dev_vdbg ( dev ,
" i=%d max=%d,min=%d,ave=%d, gradient=%d " ,
i , gd_sensor_row [ i ] . cm_max , gd_sensor_row [ i ] . cm_min ,
gd_sensor_row [ i ] . cm_ave , gd_sensor_row [ i ] . gradient_val ) ;
}
/*Get cp data*/
rc = cyttsp5_run_and_get_selftest_result_noprint (
dev , tmp_buf , sizeof ( tmp_buf ) ,
CY_ST_ID_CP_PANEL , PIP_CMD_MAX_LENGTH , true ) ;
if ( rc ) {
dev_err ( dev , " Get CP Panel not supported " ) ;
goto exit ;
}
/*Get cp_tx_data_panel*/
if ( cp_tx_data_panel ! = NULL ) {
for ( i = 0 ; i < tx_num ; i + + ) {
cp_tx_data_panel [ i ] =
10 * ( dad - > ic_buf [ CP_PANEL_DATA_OFFSET + i * 2 ]
+ 256 * dad - > ic_buf [ CP_PANEL_DATA_OFFSET + i * 2 + 1 ] ) ;
dev_vdbg ( dev ,
" cp_tx_data_panel[%d]=%d \n " ,
i , cp_tx_data_panel [ i ] ) ;
cp_tx_ave_data_panel + = cp_tx_data_panel [ i ] ;
}
cp_tx_ave_data_panel / = tx_num ;
cmcp_info - > cp_tx_ave_data_panel = cp_tx_ave_data_panel ;
}
/*Get cp_tx_cal_data_panel*/
if ( cp_tx_cal_data_panel ! = NULL ) {
for ( i = 0 ; i < tx_num ; i + + ) {
cp_tx_cal_data_panel [ i ] =
10 * ( dad - > ic_buf [ CP_PANEL_DATA_OFFSET + tx_num * 2 + i * 2 ]
+ 256 * dad - > ic_buf [ CP_PANEL_DATA_OFFSET + tx_num * 2 + i * 2 + 1 ] ) ;
dev_vdbg ( dev , " cp_tx_cal_data_panel[%d]=%d \n " ,
i , cp_tx_cal_data_panel [ i ] ) ;
}
}
/*get cp_sensor_tx_delta,using the first sensor cal value for temp */
/*multiple 1000 to increase accuracy*/
cmcp_info - > cp_sensor_tx_delta = ABS ( ( cp_tx_cal_data_panel [ 0 ]
- cp_tx_ave_data_panel ) * 1000 / cp_tx_ave_data_panel ) ;
/*Get cp_rx_data_panel*/
if ( cp_rx_data_panel ! = NULL ) {
for ( i = 0 ; i < rx_num ; i + + ) {
cp_rx_data_panel [ i ] =
10 * ( dad - > ic_buf [ CP_PANEL_DATA_OFFSET + tx_num * 4 + i * 2 ] +
256 * dad - > ic_buf [ CP_PANEL_DATA_OFFSET + tx_num * 4 + i * 2 + 1 ] ) ;
dev_vdbg ( dev ,
" cp_rx_data_panel[%d]=%d \n " , i , cp_rx_data_panel [ i ] ) ;
cp_rx_ave_data_panel + = cp_rx_data_panel [ i ] ;
}
cp_rx_ave_data_panel / = rx_num ;
cmcp_info - > cp_rx_ave_data_panel = cp_rx_ave_data_panel ;
}
/*Get cp_rx_cal_data_panel*/
if ( cp_rx_cal_data_panel ! = NULL ) {
for ( i = 0 ; i < rx_num ; i + + ) {
cp_rx_cal_data_panel [ i ] =
10 * ( dad - > ic_buf [ CP_PANEL_DATA_OFFSET + tx_num * 4 + rx_num * 2 + i * 2 ] +
256 *
dad - > ic_buf [ CP_PANEL_DATA_OFFSET + tx_num * 4 + rx_num * 2 + i * 2 + 1 ] ) ;
dev_vdbg ( dev ,
" cp_rx_cal_data_panel[%d]=%d \n " ,
i ,
cp_rx_cal_data_panel [ i ] ) ;
}
}
/*get cp_sensor_rx_delta,using the first sensor cal value for temp */
/*multiple 1000 to increase accuracy*/
cmcp_info - > cp_sensor_rx_delta = ABS ( ( cp_rx_cal_data_panel [ 0 ]
- cp_rx_ave_data_panel ) * 1000 / cp_rx_ave_data_panel ) ;
if ( btn_num = = 0 )
goto skip_button_test ;
/*get cm btn data*/
rc = cyttsp5_run_and_get_selftest_result_noprint (
dev , tmp_buf , sizeof ( tmp_buf ) ,
CY_ST_ID_CM_BUTTON , PIP_CMD_MAX_LENGTH , true ) ;
if ( rc ) {
dev_err ( dev , " Get CM BTN not supported " ) ;
goto exit ;
}
if ( cm_btn_data ! = NULL ) {
for ( i = 0 ; i < btn_num ; i + + ) {
cm_btn_data [ i ] =
10 * ( dad - > ic_buf [ CM_BTN_DATA_OFFSET + i * 2 ] +
256 * dad - > ic_buf [ CM_BTN_DATA_OFFSET + i * 2 + 1 ] ) ;
dev_vdbg ( dev ,
" cm_btn_data[%d]=%d \n " ,
i , cm_btn_data [ i ] ) ;
cm_ave_data_btn + = cm_btn_data [ i ] ;
}
cm_ave_data_btn / = btn_num ;
cm_btn_cal = 10 * ( dad - > ic_buf [ CM_BTN_DATA_OFFSET + i * 2 ]
+ 256 * dad - > ic_buf [ CM_BTN_DATA_OFFSET + i * 2 + 1 ] ) ;
/*multiple 1000 to increase accuracy*/
cm_delta_data_btn = ABS ( ( cm_ave_data_btn - cm_btn_cal )
* 1000 / cm_ave_data_btn ) ;
dev_vdbg ( dev , " cm_btn_cal=%d \n " , cm_btn_cal ) ;
cmcp_info - > cm_ave_data_btn = cm_ave_data_btn ;
cmcp_info - > cm_cal_data_btn = cm_btn_cal ;
cmcp_info - > cm_delta_data_btn = cm_delta_data_btn ;
}
/*get cp btn data*/
rc = cyttsp5_run_and_get_selftest_result_noprint (
dev , tmp_buf , sizeof ( tmp_buf ) ,
CY_ST_ID_CP_BUTTON , PIP_CMD_MAX_LENGTH , true ) ;
if ( rc ) {
dev_err ( dev , " Get CP BTN not supported " ) ;
goto exit ;
}
if ( cp_btn_data ! = NULL ) {
for ( i = 0 ; i < btn_num ; i + + ) {
cp_btn_data [ i ] =
10 * ( dad - > ic_buf [ CP_BTN_DATA_OFFSET + i * 2 ] +
256 * dad - > ic_buf [ CP_BTN_DATA_OFFSET + i * 2 + 1 ] ) ;
cp_btn_ave + = cp_btn_data [ i ] ;
dev_vdbg ( dev ,
" cp_btn_data[%d]=%d \n " ,
i , cp_btn_data [ i ] ) ;
}
cp_btn_ave / = btn_num ;
cp_btn_cal = 10 * ( dad - > ic_buf [ CP_BTN_DATA_OFFSET + i * 2 ]
+ 256 * dad - > ic_buf [ CP_BTN_DATA_OFFSET + i * 2 + 1 ] ) ;
cmcp_info - > cp_button_ave = cp_btn_ave ;
cmcp_info - > cp_btn_cal = cp_btn_cal ;
/*multiple 1000 to increase accuracy*/
cmcp_info - > cp_button_delta = ABS ( ( cp_btn_cal
- cp_btn_ave ) * 1000 / cp_btn_ave ) ;
dev_vdbg ( dev , " cp_btn_cal=%d \n " , cp_btn_cal ) ;
dev_vdbg ( dev , " cp_btn_ave=%d \n " , cp_btn_ave ) ;
}
skip_button_test :
exit :
return rc ;
}
static void cyttsp5_free_cmcp_buf ( struct cmcp_data * cmcp_info )
{
if ( cmcp_info - > gd_sensor_col ! = NULL )
kfree ( cmcp_info - > gd_sensor_col ) ;
if ( cmcp_info - > gd_sensor_row ! = NULL )
kfree ( cmcp_info - > gd_sensor_row ) ;
if ( cmcp_info - > cm_data_panel ! = NULL )
kfree ( cmcp_info - > cm_data_panel ) ;
if ( cmcp_info - > cp_tx_data_panel ! = NULL )
kfree ( cmcp_info - > cp_tx_data_panel ) ;
if ( cmcp_info - > cp_rx_data_panel ! = NULL )
kfree ( cmcp_info - > cp_rx_data_panel ) ;
if ( cmcp_info - > cp_tx_cal_data_panel ! = NULL )
kfree ( cmcp_info - > cp_tx_cal_data_panel ) ;
if ( cmcp_info - > cp_rx_cal_data_panel ! = NULL )
kfree ( cmcp_info - > cp_rx_cal_data_panel ) ;
if ( cmcp_info - > cm_btn_data ! = NULL )
kfree ( cmcp_info - > cm_btn_data ) ;
if ( cmcp_info - > cp_btn_data ! = NULL )
kfree ( cmcp_info - > cp_btn_data ) ;
if ( cmcp_info - > cm_sensor_column_delta ! = NULL )
kfree ( cmcp_info - > cm_sensor_column_delta ) ;
if ( cmcp_info - > cm_sensor_row_delta ! = NULL )
kfree ( cmcp_info - > cm_sensor_row_delta ) ;
}
static int cyttsp5_cmcp_get_test_item ( int item_input )
{
int test_item = 0 ;
switch ( item_input ) {
case CMCP_FULL :
test_item = CMCP_FULL_CASE ;
break ;
case CMCP_CM_PANEL :
test_item = CM_PANEL ;
break ;
case CMCP_CP_PANEL :
test_item = CP_PANEL ;
break ;
case CMCP_CM_BTN :
test_item = CM_BTN ;
break ;
case CMCP_CP_BTN :
test_item = CP_BTN ;
break ;
}
return test_item ;
}
static ssize_t cyttsp5_cmcp_test_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
struct cmcp_data * cmcp_info = dad - > cmcp_info ;
struct result * result = dad - > result ;
struct configuration * configuration = dad - > configs ;
bool final_pass = true ;
static const char * const cmcp_test_case_array [ ] = { " Full Cm/Cp test " ,
" Cm panel test " , " Cp panel test " ,
" Cm button test " , " Cp button test " } ;
int index = 0 ;
int test_item = 0 ;
int no_builtin_file = 0 ;
int rc ;
u8 status ;
int self_test_id_supported = 0 ;
dev = dad - > dev ;
if ( ( configuration = = NULL ) | | ( cmcp_info = = NULL ) )
goto exit ;
mutex_lock ( & dad - > sysfs_lock ) ;
if ( dad - > cmcp_test_in_progress ) {
mutex_unlock ( & dad - > sysfs_lock ) ;
goto cmcp_not_ready ;
}
dad - > cmcp_test_in_progress = 1 ;
dad - > test_executed = 0 ;
test_item = cyttsp5_cmcp_get_test_item ( dad - > cmcp_test_items ) ;
if ( dad - > builtin_cmcp_threshold_status < 0 ) {
dev_err ( dev , " %s: No cmcp threshold file. \n " , __func__ ) ;
no_builtin_file = 1 ;
mutex_unlock ( & dad - > sysfs_lock ) ;
goto start_testing ;
}
if ( dad - > cmcp_test_items < 0 ) {
dev_vdbg ( dev ,
" %s: Invalid test item! Should be 0~4! \n " , __func__ ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
goto invalid_item ;
}
dev_vdbg ( dev , " %s: Test item is %s, %d \n " , __func__ ,
cmcp_test_case_array [ dad - > cmcp_test_items ] , test_item ) ;
if ( ( dad - > si - > num_btns = = 0 )
& & ( ( dad - > cmcp_test_items = = CMCP_CM_BTN )
| | ( dad - > cmcp_test_items = = CMCP_CP_BTN ) ) ) {
dev_vdbg ( dev , " %s: FW doesn't support button! \n " , __func__ ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
goto invalid_item_btn ;
}
mutex_unlock ( & dad - > sysfs_lock ) ;
if ( cmcp_check_config_fw_match ( dev , configuration ) )
goto mismatch ;
start_testing :
dev_vdbg ( dev , " %s: Start Cm/Cp test! \n " , __func__ ) ;
result - > cm_test_pass = true ;
result - > cp_test_pass = true ;
/*stop watchdog*/
rc = cmd - > request_stop_wd ( dev ) ;
if ( rc )
dev_err ( dev , " stop watchdog failed " ) ;
/*force single tx*/
rc = cmd - > nonhid_cmd - > set_param ( dev , 0 , 0x1F , 1 , 1 ) ;
if ( rc )
dev_err ( dev , " force single tx failed " ) ;
/*suspend_scanning */
rc = cmd - > nonhid_cmd - > suspend_scanning ( dev , 0 ) ;
if ( rc )
dev_err ( dev , " suspend_scanning failed " ) ;
/*do calibration*/
if ( ! dad - > cmcp_force_calibrate ) {
dev_vdbg ( dev , " do calibration in single tx mode " ) ;
rc = _cyttsp5_calibrate_idacs_cmd ( dev , 0 , & status ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on calibrate idacs for mutual r=%d \n " ,
__func__ , rc ) ;
}
rc = _cyttsp5_calibrate_idacs_cmd ( dev , 1 , & status ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on calibrate idacs for buttons r=%d \n " ,
__func__ , rc ) ;
}
rc = _cyttsp5_calibrate_idacs_cmd ( dev , 2 , & status ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on calibrate idacs for self r=%d \n " ,
__func__ , rc ) ;
}
}
/*resume_scanning */
rc = cmd - > nonhid_cmd - > resume_scanning ( dev , 0 ) ;
if ( rc )
dev_err ( dev , " resume_scanning failed " ) ;
/*get all cmcp data from FW*/
self_test_id_supported =
cyttsp5_get_cmcp_info ( dad , cmcp_info ) ;
if ( self_test_id_supported )
dev_err ( dev , " cyttsp5_get_cmcp_info failed " ) ;
/*restore to multi tx*/
rc = cmd - > nonhid_cmd - > set_param ( dev , 0 , 0x1F , 0 , 1 ) ;
if ( rc )
dev_err ( dev , " restore multi tx failed " ) ;
/*suspend_scanning */
rc = cmd - > nonhid_cmd - > suspend_scanning ( dev , 0 ) ;
if ( rc )
dev_err ( dev , " suspend_scanning failed " ) ;
/*do calibration*/
if ( ! dad - > cmcp_force_calibrate ) {
dev_vdbg ( dev , " do calibration in multi tx mode " ) ;
rc = _cyttsp5_calibrate_idacs_cmd ( dev , 0 , & status ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on calibrate idacs for mutual r=%d \n " ,
__func__ , rc ) ;
}
rc = _cyttsp5_calibrate_idacs_cmd ( dev , 1 , & status ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on calibrate idacs for buttons r=%d \n " ,
__func__ , rc ) ;
}
rc = _cyttsp5_calibrate_idacs_cmd ( dev , 2 , & status ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on calibrate idacs for self r=%d \n " ,
__func__ , rc ) ;
}
}
/*resume_scanning */
rc = cmd - > nonhid_cmd - > resume_scanning ( dev , 0 ) ;
if ( rc )
dev_err ( dev , " resume_scanning failed " ) ;
/*start watchdog*/
rc = cmd - > request_start_wd ( dev ) ;
if ( rc )
dev_err ( dev , " start watchdog failed " ) ;
if ( self_test_id_supported )
goto self_test_id_failed ;
if ( no_builtin_file )
goto no_builtin ;
if ( test_item & & CM_ENABLED )
validate_cm_test_results ( dev , configuration , cmcp_info ,
result , & final_pass , test_item ) ;
if ( test_item & & CP_ENABLED )
validate_cp_test_results ( dev , configuration , cmcp_info ,
result , & final_pass , test_item ) ;
no_builtin :
if ( ( dad - > cmcp_test_items = = CMCP_FULL )
& & ( dad - > cmcp_range_check = = 0 ) ) {
/*full test and full check*/
result - > test_summary =
result - > cm_test_pass
& & result - > cp_test_pass
& & result - > short_test_pass ;
} else if ( ( dad - > cmcp_test_items = = CMCP_FULL )
& & ( dad - > cmcp_range_check = = 1 ) ) {
/*full test and basic check*/
result - > test_summary =
result - > cm_sensor_gd_col_pass
& & result - > cm_sensor_gd_row_pass
& & result - > cm_sensor_validation_pass
& & result - > cp_rx_validation_pass
& & result - > cp_tx_validation_pass
& & result - > short_test_pass ;
} else if ( dad - > cmcp_test_items = = CMCP_CM_PANEL ) {
/*cm panel test result only*/
result - > test_summary =
result - > cm_sensor_gd_col_pass
& & result - > cm_sensor_gd_row_pass
& & result - > cm_sensor_validation_pass
& & result - > cm_sensor_row_delta_pass
& & result - > cm_sensor_col_delta_pass
& & result - > cm_sensor_calibration_pass
& & result - > cm_sensor_delta_pass ;
} else if ( dad - > cmcp_test_items = = CMCP_CP_PANEL ) {
/*cp panel test result only*/
result - > test_summary =
result - > cp_sensor_delta_pass
& & result - > cp_rx_validation_pass
& & result - > cp_tx_validation_pass ;
} else if ( dad - > cmcp_test_items = = CMCP_CM_BTN ) {
/*cm button test result only*/
result - > test_summary =
result - > cm_button_validation_pass
& & result - > cm_button_delta_pass ;
} else if ( dad - > cmcp_test_items = = CMCP_CP_BTN ) {
/*cp button test result only*/
result - > test_summary =
result - > cp_button_delta_pass
& & result - > cp_button_average_pass
& & result - > cp_button_validation_pass ;
}
mutex_lock ( & dad - > sysfs_lock ) ;
dad - > test_executed = 1 ;
mutex_unlock ( & dad - > sysfs_lock ) ;
dev_vdbg ( dev , " %s: Finish Cm/Cp test! \n " , __func__ ) ;
index = snprintf ( buf , CY_MAX_PRBUF_SIZE ,
" Status 1 \n " ) ;
goto cmcp_ready ;
mismatch :
index = snprintf ( buf , CY_MAX_PRBUF_SIZE ,
" Status 2 \n Input cmcp threshold file mismatches with FW \n " ) ;
goto cmcp_ready ;
invalid_item_btn :
index = snprintf ( buf , CY_MAX_PRBUF_SIZE ,
" Status 3 \n FW doesn't support button! \n " ) ;
goto cmcp_ready ;
invalid_item :
index = snprintf ( buf , CY_MAX_PRBUF_SIZE ,
" Status 4 \n Wrong test item or range check input! \n Only support below items: \n 0 - Cm/Cp Panel & Button with Gradient (Typical) \n 1 - Cm Panel with Gradient \n 2 - Cp Panel \n 3 - Cm Button \n 4 - Cp Button \n Only support below range check: \n 0 - Full Range Checking (default) \n 1 - Basic Range Checking(TSG5 style) \n " ) ;
goto cmcp_ready ;
self_test_id_failed :
index = snprintf ( buf , CY_MAX_PRBUF_SIZE ,
" Status 5 \n get self test ID not supported! " ) ;
goto cmcp_ready ;
cmcp_not_ready :
index = snprintf ( buf , CY_MAX_PRBUF_SIZE ,
" Status 0 \n " ) ;
goto cmcp_ready ;
cmcp_ready :
mutex_lock ( & dad - > sysfs_lock ) ;
dad - > cmcp_test_in_progress = 0 ;
mutex_unlock ( & dad - > sysfs_lock ) ;
exit :
return index ;
}
static ssize_t cyttsp5_cmcp_test_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
u8 test_item = 0 ;
u8 range_check = 0 ;
u8 force_calibrate = 0 ;
int ret ;
static const char * const cmcp_test_case_array [ ] = { " Full Cm/Cp test " ,
" Cm panel test " , " Cp panel test " ,
" Cm button test " , " Cp button test " } ;
static const char * const cmcp_test_range_check_array [ ] = {
" Full (default) " , " Basic " } ;
static const char * const cmcp_test_force_cal_array [ ] = {
" Calibrate When Testing (default) " , " No Calibration " } ;
ssize_t length = 0 ;
pm_runtime_get_sync ( dev ) ;
mutex_lock ( & dad - > sysfs_lock ) ;
length = cyttsp5_ic_parse_input ( dev , buf , size , dad - > ic_buf ,
CY_MAX_PRBUF_SIZE ) ;
if ( length < = 0 | | length > 3 ) {
dev_err ( dev , " %s: Input format error! \n " , __func__ ) ;
dad - > cmcp_test_items = - EINVAL ;
ret = - EINVAL ;
goto error ;
}
/* Get test item */
test_item = dad - > ic_buf [ 0 ] ;
/* Get range check */
if ( length > = 2 )
range_check = dad - > ic_buf [ 1 ] ;
/* Get force calibration */
if ( length = = 3 )
force_calibrate = dad - > ic_buf [ 2 ] ;
/* Test item limitation:
0 : Perform all Tests
1 : CM Panel with Gradient
2 : CP Panel
3 : CM Button
4 : CP Button
Ranage check limitation :
0 : full check
1 : basic check
Force calibrate limitation :
0 : do calibration
1 : don ' t do calibration
*/
if ( ( test_item < 0 ) | | ( test_item > 4 ) | | ( range_check > 1 )
| | ( force_calibrate > 1 ) ) {
dev_err ( dev ,
" %s: Test item should be 0~4; Range check should be 0~1; Force calibrate should be 0~1 \n " ,
__func__ ) ;
dad - > cmcp_test_items = - EINVAL ;
ret = - EINVAL ;
goto error ;
}
/*if it is not all Test, then
range_check should be 0
because other test does
not has concept of basic
check
*/
if ( test_item > 0 & & test_item < 5 )
range_check = 0 ;
dad - > cmcp_test_items = test_item ;
dad - > cmcp_range_check = range_check ;
dad - > cmcp_force_calibrate = force_calibrate ;
dev_vdbg ( dev , " %s: Test item is %s; Range check is %s; Force calibrate is %s. \n " ,
__func__ ,
cmcp_test_case_array [ test_item ] ,
cmcp_test_range_check_array [ range_check ] ,
cmcp_test_force_cal_array [ force_calibrate ] ) ;
error :
mutex_unlock ( & dad - > sysfs_lock ) ;
pm_runtime_put ( dev ) ;
if ( ret )
return ret ;
return size ;
}
static DEVICE_ATTR ( cmcp_test , S_IRUSR | S_IWUSR ,
cyttsp5_cmcp_test_show , cyttsp5_cmcp_test_store ) ;
int prepare_print_string ( char * out_buf , char * in_buf , int index )
{
if ( ( out_buf = = NULL ) | | ( in_buf = = NULL ) )
return index ;
index + = scnprintf ( & out_buf [ index ] , MAX_BUF_LEN - index ,
" %s " , in_buf ) ;
return index ;
}
int prepare_print_data ( char * out_buf , int32_t * in_buf , int index , int data_num )
{
int i ;
if ( ( out_buf = = NULL ) | | ( in_buf = = NULL ) )
return index ;
for ( i = 0 ; i < data_num ; i + + )
index + = scnprintf ( & out_buf [ index ] , MAX_BUF_LEN - index ,
" %d, " , in_buf [ i ] ) ;
return index ;
}
int save_header ( char * out_buf , int index , struct result * result )
{
struct rtc_time tm ;
char time_buf [ 100 ] = { 0 } ;
2021-03-15 11:38:13 -06:00
tm = rtc_ktime_to_tm ( ktime_get_real ( ) ) ;
2021-02-07 10:37:17 -07:00
scnprintf ( time_buf , 100 , " %d/%d/%d,TIME,%d:%d:%d, " , tm . tm_year + 1900 ,
tm . tm_mon , tm . tm_mday , tm . tm_hour , tm . tm_min , tm . tm_sec ) ;
index = prepare_print_string ( out_buf , " ,.header, \n " , index ) ;
index = prepare_print_string ( out_buf , " ,DATE, " , index ) ;
index = prepare_print_string ( out_buf , & time_buf [ 0 ] , index ) ;
index = prepare_print_string ( out_buf , " , \n " , index ) ;
index = prepare_print_string ( out_buf , " ,SW_VERSION, " , index ) ;
index = prepare_print_string ( out_buf , CY_DRIVER_VERSION , index ) ;
index = prepare_print_string ( out_buf , " , \n " , index ) ;
index = prepare_print_string ( out_buf , " ,.end, \n " , index ) ;
index = prepare_print_string ( out_buf , " ,.engineering data, \n " , index ) ;
return index ;
}
static int print_silicon_id ( char * out_buf , char * in_buf , int index )
{
index = prepare_print_string ( out_buf , " ,1, " , index ) ;
index = prepare_print_string ( out_buf , & in_buf [ 0 ] , index ) ;
return index ;
}
int save_engineering_data ( struct device * dev , char * out_buf , int index ,
struct cmcp_data * cmcp_info , struct configuration * configuration ,
struct result * result , int test_item , int no_builtin_file )
{
int i ;
int j ;
int tx_num = cmcp_info - > tx_num ;
int rx_num = cmcp_info - > rx_num ;
int btn_num = cmcp_info - > btn_num ;
int tmp = 0 ;
uint32_t fw_revision_control ;
uint32_t fw_config_ver ;
char device_id [ 20 ] = { 0 } ;
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
fw_revision_control = dad - > si - > cydata . revctrl ;
fw_config_ver = dad - > si - > cydata . fw_ver_conf ;
/*calculate silicon id*/
result - > device_id_low = 0 ;
result - > device_id_high = 0 ;
for ( i = 0 ; i < 4 ; i + + )
result - > device_id_low =
( result - > device_id_low < < 8 ) + dad - > si - > cydata . mfg_id [ i ] ;
for ( i = 4 ; i < 8 ; i + + )
result - > device_id_high =
( result - > device_id_high < < 8 ) + dad - > si - > cydata . mfg_id [ i ] ;
scnprintf ( device_id , 20 , " %x%x " ,
result - > device_id_high , result - > device_id_low ) ;
/*print test summary*/
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
if ( result - > test_summary )
index = prepare_print_string ( out_buf , " ,PASS, \n " , index ) ;
else
index = prepare_print_string ( out_buf , " ,FAIL, \n " , index ) ;
/*revision ctrl number*/
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf , " ,FW revision Control, " , index ) ;
index = prepare_print_data ( out_buf , & fw_revision_control , index , 1 ) ;
index = prepare_print_string ( out_buf , " \n " , index ) ;
/*config version*/
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf , " ,CONFIG_VER, " , index ) ;
index = prepare_print_data ( out_buf , & fw_config_ver , index , 1 ) ;
index = prepare_print_string ( out_buf , " \n " , index ) ;
/*short test*/
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
if ( result - > short_test_pass )
index = prepare_print_string ( out_buf , " ,Shorts,PASS, \n " , index ) ;
else
index = prepare_print_string ( out_buf , " ,Shorts,FAIL, \n " , index ) ;
if ( ( test_item & CM_ENABLED ) = = CM_ENABLED ) {
/*print BUTNS_CM_DATA_ROW00*/
if ( ( ( test_item & CM_BTN ) = = CM_BTN ) & & ( btn_num > 0 ) ) {
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,BUTNS_CM_DATA_ROW00, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cm_btn_data [ 0 ] ,
index ,
btn_num ) ;
index = prepare_print_string ( out_buf , " \n " , index ) ;
}
if ( ( test_item & CM_PANEL ) = = CM_PANEL ) {
/*print CM_DATA_ROW*/
for ( i = 0 ; i < rx_num ; i + + ) {
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,CM_DATA_ROW " ,
index ) ;
index = prepare_print_data ( out_buf , & i ,
index , 1 ) ;
for ( j = 0 ; j < tx_num ; j + + )
index = prepare_print_data ( out_buf ,
& cmcp_info - > cm_data_panel [ j * rx_num + i ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
if ( ! no_builtin_file ) {
/*print CM_MAX_GRADIENT_COLS_PERCENT*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,CM_MAX_GRADIENT_COLS_PERCENT, " ,
index ) ;
for ( i = 0 ; i < tx_num ; i + + ) {
char tmp_buf [ 10 ] = { 0 } ;
scnprintf ( tmp_buf , 10 , " %d.%d, " ,
cmcp_info - > gd_sensor_col [ i ] . gradient_val / 10 ,
cmcp_info - > gd_sensor_col [ i ] . gradient_val % 10 ) ;
index = prepare_print_string ( out_buf ,
& tmp_buf [ 0 ] , index ) ;
}
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print CM_MAX_GRADIENT_ROWS_PERCENT*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,CM_MAX_GRADIENT_ROWS_PERCENT, " ,
index ) ;
for ( i = 0 ; i < rx_num ; i + + ) {
char tmp_buf [ 10 ] = { 0 } ;
scnprintf ( tmp_buf , 10 , " %d.%d, " ,
cmcp_info - > gd_sensor_row [ i ] . gradient_val / 10 ,
cmcp_info - > gd_sensor_row [ i ] . gradient_val % 10 ) ;
index = prepare_print_string ( out_buf ,
& tmp_buf [ 0 ] , index ) ;
}
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
if ( ! dad - > cmcp_range_check ) {
/*print CM_DELTA_COLUMN*/
for ( i = 0 ; i < rx_num ; i + + ) {
index = print_silicon_id (
out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string (
out_buf ,
" ,Sensor Cm Validation,DELTA_COLUMNS_ROW " ,
index ) ;
index = prepare_print_data (
out_buf ,
& i , index , 1 ) ;
index = prepare_print_data (
out_buf ,
& tmp , index , 1 ) ;
for ( j = 1 ; j < tx_num ; j + + )
index = prepare_print_data (
out_buf ,
& cmcp_info - > cm_sensor_column_delta [ ( j - 1 ) * rx_num + i ] ,
index , 1 ) ;
index = prepare_print_string (
out_buf ,
" \n " , index ) ;
}
/*print CM_DELTA_ROW*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] ,
index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,DELTA_ROWS_ROW " ,
index ) ;
index = prepare_print_data ( out_buf ,
& tmp , index , 1 ) ;
for ( j = 0 ; j < tx_num ; j + + )
index = prepare_print_data (
out_buf ,
& tmp , index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
for ( i = 1 ; i < rx_num ; i + + ) {
index = print_silicon_id (
out_buf ,
& device_id [ 0 ] ,
index ) ;
index = prepare_print_string (
out_buf ,
" ,Sensor Cm Validation,DELTA_ROWS_ROW " ,
index ) ;
index = prepare_print_data (
out_buf , & i ,
index , 1 ) ;
for ( j = 0 ; j < tx_num ; j + + )
index = prepare_print_data (
out_buf ,
& cmcp_info - > cm_sensor_row_delta [ j * rx_num + i - 1 ] ,
index , 1 ) ;
index = prepare_print_string (
out_buf ,
" \n " , index ) ;
}
/*print pass/fail Sensor Cm Validation*/
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
if ( result - > cm_test_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,PASS, \n " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,FAIL, \n " ,
index ) ;
}
}
}
if ( ! no_builtin_file ) {
if ( ( ( test_item & CM_BTN ) = = CM_BTN ) & & ( btn_num > 0 )
& & ( ! dad - > cmcp_range_check ) ) {
char tmp_buf [ 10 ] = { 0 } ;
/*print Button Element by Element */
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
if ( result - > cm_button_validation_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Button Element by Element,PASS \n " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Button Element by Element,FAIL \n " ,
index ) ;
/*
* print Sensor Cm Validation
* - Buttons Range Buttons Range
*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Buttons Range,Buttons Range, " ,
index ) ;
scnprintf ( tmp_buf , 10 , " %d.%d, " ,
cmcp_info - > cm_delta_data_btn / 10 ,
cmcp_info - > cm_delta_data_btn % 10 ) ;
index = prepare_print_string ( out_buf ,
& tmp_buf [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Sensor Cm Validation
* - Buttons Range Cm_button_avg
*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Buttons Range,Cm_button_avg, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cm_ave_data_btn ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Sensor Cm Validation
* - Buttons Range Cm_button_avg
*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Buttons Range,Cm_button_cal, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cm_cal_data_btn ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Sensor Cm Validation
* - Buttons Range pass / fail
*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_button_delta_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Buttons Range,PASS,LIMITS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Buttons Range,FAIL,LIMITS, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_max_delta_button_percent ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
if ( ( test_item & CM_PANEL ) = = CM_PANEL & &
! dad - > cmcp_range_check ) {
char tmp_buf [ 10 ] = { 0 } ;
/*print Cm_sensor_cal */
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Calibration,Cm_sensor_cal, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cm_cal_data_panel ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cm_sensor_cal limit*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_sensor_calibration_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Calibration,PASS,LIMITS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Calibration,FAIL,LIMITS, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_min_limit_cal ,
index , 1 ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_max_limit_cal ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Columns Delta Matrix*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_sensor_col_delta_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Columns Delta Matrix,PASS,LIMITS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Columns Delta Matrix,FAIL,LIMITS, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_range_limit_col ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cm Validation - Element by Element*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_sensor_validation_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Element by Element,PASS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Element by Element,FAIL, " ,
index ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cm Validation -Gradient Cols*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_sensor_gd_col_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Gradient Cols,PASS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Gradient Cols,FAIL, " ,
index ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cm Validation -Gradient Rows*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_sensor_gd_row_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Gradient Rows,PASS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Gradient Rows,FAIL, " ,
index ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Sensor Cm Validation
* - Rows Delta Matrix
*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_sensor_row_delta_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Rows Delta Matrix,PASS,LIMITS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Rows Delta Matrix,FAIL,LIMITS, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_range_limit_row ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cm_sensor_avg */
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Sensor Range,Cm_sensor_avg, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cm_ave_data_panel ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*printSensor Cm Validation -
* Sensor Range , Sensor Range
*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Sensor Range,Sensor Range, " ,
index ) ;
scnprintf ( tmp_buf , 10 , " %d.%d, " ,
cmcp_info - > cm_sensor_delta / 10 ,
cmcp_info - > cm_sensor_delta % 10 ) ;
index = prepare_print_string ( out_buf ,
& tmp_buf [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Sensor Cm Validation - Sensor Range*/
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
if ( result - > cm_sensor_delta_pass )
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Sensor Range,PASS,LIMITS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation - Sensor Range,FAIL,LIMITS, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_max_delta_sensor_percent ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
}
}
if ( ( test_item & CP_ENABLED ) = = CP_ENABLED ) {
if ( ( ( test_item & CP_BTN ) = = CP_BTN ) & & ( btn_num > 0 ) ) {
/*print BUTNS_CP_DATA_ROW00 */
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,BUTNS_CP_DATA_ROW00, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_btn_data [ 0 ] ,
index , btn_num ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
if ( ! no_builtin_file & & ! dad - > cmcp_range_check ) {
/*print Cp Button Element by Element */
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
if ( result - > cp_button_validation_pass )
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check - Button Element by Element,PASS \n " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check - Button Element by Element,FAIL \n " ,
index ) ;
/*print cp_button_ave */
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_button_avg, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_button_ave ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cp_button_cal */
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_button_cal, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_btn_cal ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
}
if ( ( test_item & CP_PANEL ) = = CP_PANEL ) {
/*print CP_DATA_RX */
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,CP_DATA_RX, " , index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_rx_data_panel [ 0 ] , index , rx_num ) ;
index = prepare_print_string ( out_buf , " \n " , index ) ;
/*print CP_DATA_TX */
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,CP_DATA_TX, " , index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_tx_data_panel [ 0 ] , index , tx_num ) ;
index = prepare_print_string ( out_buf , " \n " , index ) ;
}
if ( ( ( test_item & CP_BTN ) = = CP_BTN ) & & ( btn_num > 0 )
& & ! dad - > cmcp_range_check ) {
if ( ! no_builtin_file ) {
char tmp_buf [ 10 ] = { 0 } ;
/*print Cp_delta_button */
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_delta_button, " ,
index ) ;
scnprintf ( tmp_buf , 10 , " %d.%d, " ,
cmcp_info - > cp_button_delta / 10 ,
cmcp_info - > cp_button_delta % 10 ) ;
index = prepare_print_string ( out_buf ,
& tmp_buf [ 0 ] , index ) ;
index = prepare_print_string ( out_buf , " \n " ,
index ) ;
}
}
if ( ( test_item & CP_PANEL ) = = CP_PANEL & &
! dad - > cmcp_range_check ) {
if ( ! no_builtin_file ) {
char tmp_buf [ 10 ] = { 0 } ;
/*print Cp_delta_rx */
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_delta_rx, " ,
index ) ;
scnprintf ( tmp_buf , 10 , " %d.%d, " ,
cmcp_info - > cp_sensor_rx_delta / 10 ,
cmcp_info - > cp_sensor_rx_delta % 10 ) ;
index = prepare_print_string ( out_buf ,
& tmp_buf [ 0 ] , index ) ;
index = prepare_print_string ( out_buf , " \n " ,
index ) ;
/*print Cp_delta_tx */
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_delta_tx, " ,
index ) ;
scnprintf ( tmp_buf , 10 , " %d.%d, " ,
cmcp_info - > cp_sensor_tx_delta / 10 ,
cmcp_info - > cp_sensor_tx_delta % 10 ) ;
index = prepare_print_string ( out_buf ,
& tmp_buf [ 0 ] , index ) ;
index = prepare_print_string ( out_buf , " \n " ,
index ) ;
/*print Cp_sensor_avg_rx */
index = print_silicon_id ( out_buf , & device_id [ 0 ] ,
index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_sensor_avg_rx, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_rx_ave_data_panel ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cp_sensor_avg_tx */
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_sensor_avg_tx, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_tx_ave_data_panel ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cp_sensor_cal_rx */
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_sensor_cal_rx, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_rx_cal_data_panel [ 0 ] ,
index , rx_num ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print Cp_sensor_cal_tx */
index = print_silicon_id ( out_buf ,
& device_id [ 0 ] , index ) ;
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,Cp_sensor_cal_tx, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& cmcp_info - > cp_tx_cal_data_panel [ 0 ] ,
index , tx_num ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
}
if ( ! no_builtin_file & & ! dad - > cmcp_range_check ) {
/*print cp test limits */
index = print_silicon_id ( out_buf , & device_id [ 0 ] , index ) ;
if ( result - > cp_test_pass )
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,PASS, LIMITS, " ,
index ) ;
else
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,FAIL, LIMITS, " ,
index ) ;
index = prepare_print_string ( out_buf ,
" CP_MAX_DELTA_SENSOR_RX_PERCENT, " , index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cp_max_delta_sensor_rx_percent ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" CP_MAX_DELTA_SENSOR_TX_PERCENT, " , index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cp_max_delta_sensor_tx_percent ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" CP_MAX_DELTA_BUTTON_PERCENT, " , index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cp_max_delta_button_percent ,
index , 1 ) ;
index = prepare_print_string ( out_buf , " \n " , index ) ;
}
}
if ( ! no_builtin_file ) {
if ( ( test_item & CM_ENABLED ) = = CM_ENABLED ) {
if ( ( test_item & CM_PANEL ) = = CM_PANEL ) {
/*print columns gradient limit*/
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,MAX_LIMITS,CM_MAX_GRADIENT_COLS_PERCENT, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_max_table_gradient_cols_percent [ 0 ] ,
index ,
configuration - > cm_max_table_gradient_cols_percent_size ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print rows gradient limit*/
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,MAX_LIMITS,CM_MAX_GRADIENT_ROWS_PERCENT, " ,
index ) ;
index = prepare_print_data ( out_buf ,
& configuration - > cm_max_table_gradient_rows_percent [ 0 ] ,
index ,
configuration - > cm_max_table_gradient_rows_percent_size ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print cm max limit*/
for ( i = 0 ; i < rx_num ; i + + ) {
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,MAX_LIMITS,CM_DATA_ROW " ,
index ) ;
index = prepare_print_data ( out_buf ,
& i , index , 1 ) ;
for ( j = 0 ; j < tx_num ; j + + )
index = prepare_print_data (
out_buf ,
& configuration - > cm_min_max_table_sensor [ i * tx_num * 2 + j * 2 + 1 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
}
if ( ( ( test_item & CM_BTN ) = = CM_BTN ) & & ( btn_num > 0 ) ) {
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,MAX LIMITS,M_BUTNS, " ,
index ) ;
for ( j = 0 ; j < btn_num ; j + + ) {
index = prepare_print_data ( out_buf ,
& configuration - > cm_min_max_table_button [ 2 * j + 1 ] ,
index , 1 ) ;
}
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation MAX LIMITS \n " , index ) ;
if ( ( test_item & CM_PANEL ) = = CM_PANEL ) {
/*print cm min limit*/
for ( i = 0 ; i < rx_num ; i + + ) {
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,MIN_LIMITS,CM_DATA_ROW " ,
index ) ;
index = prepare_print_data ( out_buf , & i ,
index , 1 ) ;
for ( j = 0 ; j < tx_num ; j + + )
index = prepare_print_data (
out_buf ,
& configuration - > cm_min_max_table_sensor [ i * tx_num * 2 + j * 2 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
}
if ( ( ( test_item & CM_BTN ) = = CM_BTN ) & & ( btn_num > 0 ) ) {
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation,MIN LIMITS,M_BUTNS, " ,
index ) ;
for ( j = 0 ; j < btn_num ; j + + ) {
index = prepare_print_data ( out_buf ,
& configuration - > cm_min_max_table_button [ 2 * j ] ,
index , 1 ) ;
}
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
index = prepare_print_string ( out_buf ,
" ,Sensor Cm Validation MIN LIMITS \n " , index ) ;
}
if ( ( test_item & CP_ENABLED ) = = CP_ENABLED ) {
if ( ( test_item & CP_PANEL ) = = CP_PANEL ) {
/*print cp tx max limit*/
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,MAX_LIMITS,TX, " ,
index ) ;
for ( i = 0 ; i < tx_num ; i + + )
index = prepare_print_data ( out_buf ,
& configuration - > cp_min_max_table_tx [ i * 2 + 1 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print cp rx max limit*/
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,MAX_LIMITS,RX, " ,
index ) ;
for ( i = 0 ; i < rx_num ; i + + )
index = prepare_print_data ( out_buf ,
& configuration - > cp_min_max_table_rx [ i * 2 + 1 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
/*print cp btn max limit*/
if ( ( ( test_item & CP_BTN ) = = CP_BTN ) & & ( btn_num > 0 ) ) {
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,MAX_LIMITS,S_BUTNS, " ,
index ) ;
for ( i = 0 ; i < btn_num ; i + + )
index = prepare_print_data ( out_buf ,
& configuration - > cp_min_max_table_button [ i * 2 + 1 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
if ( ( test_item & CP_PANEL ) = = CP_PANEL ) {
/*print cp tx min limit*/
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,MIN_LIMITS,TX, " ,
index ) ;
for ( i = 0 ; i < tx_num ; i + + )
index = prepare_print_data ( out_buf ,
& configuration - > cp_min_max_table_tx [ i * 2 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
/*print cp rx min limit*/
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,MIN_LIMITS,RX, " ,
index ) ;
for ( i = 0 ; i < rx_num ; i + + )
index = prepare_print_data ( out_buf ,
& configuration - > cp_min_max_table_rx [ i * 2 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
/*print cp btn min limit*/
if ( ( ( test_item & CP_BTN ) = = CP_BTN ) & & ( btn_num > 0 ) ) {
index = prepare_print_string ( out_buf ,
" ,Self-cap Calibration Check,MIN_LIMITS,S_BUTNS, " ,
index ) ;
for ( i = 0 ; i < btn_num ; i + + )
index = prepare_print_data ( out_buf ,
& configuration - > cp_min_max_table_button [ i * 2 ] ,
index , 1 ) ;
index = prepare_print_string ( out_buf ,
" \n " , index ) ;
}
}
}
return index ;
}
int result_save ( struct device * dev , char * buf ,
struct configuration * configuration , struct result * result ,
struct cmcp_data * cmcp_info , loff_t * ppos , size_t count , int test_item ,
int no_builtin_file )
{
u8 * out_buf = NULL ;
int index = 0 ;
int byte_left ;
out_buf = kzalloc ( MAX_BUF_LEN , GFP_KERNEL ) ;
if ( configuration = = NULL )
dev_err ( dev , " config is NULL " ) ;
if ( result = = NULL )
dev_err ( dev , " result is NULL " ) ;
if ( cmcp_info = = NULL )
dev_err ( dev , " cmcp_info is NULL " ) ;
index = save_header ( out_buf , index , result ) ;
index = save_engineering_data ( dev , out_buf , index ,
cmcp_info , configuration , result ,
test_item , no_builtin_file ) ;
byte_left = simple_read_from_buffer ( buf , count , ppos , out_buf , index ) ;
kfree ( out_buf ) ;
return byte_left ;
}
static int cmcp_results_debugfs_open ( struct inode * inode ,
struct file * filp )
{
filp - > private_data = inode - > i_private ;
return 0 ;
}
static int cmcp_results_debugfs_close ( struct inode * inode ,
struct file * filp )
{
filp - > private_data = NULL ;
return 0 ;
}
static ssize_t cmcp_results_debugfs_read ( struct file * filp ,
char __user * buf , size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_data * dad = filp - > private_data ;
struct device * dev ;
struct cmcp_data * cmcp_info = dad - > cmcp_info ;
struct result * result = dad - > result ;
struct configuration * configuration = dad - > configs ;
int ret = 0 ;
int test_item ;
int no_builtin_file = 0 ;
int test_executed = 0 ;
dev = dad - > dev ;
mutex_lock ( & dad - > sysfs_lock ) ;
test_executed = dad - > test_executed ;
test_item = cyttsp5_cmcp_get_test_item ( dad - > cmcp_test_items ) ;
if ( dad - > builtin_cmcp_threshold_status < 0 ) {
dev_err ( dev , " %s: No cmcp threshold file. \n " , __func__ ) ;
no_builtin_file = 1 ;
}
mutex_unlock ( & dad - > sysfs_lock ) ;
if ( test_executed )
/*save result to buf*/
ret = result_save ( dev , buf , configuration , result , cmcp_info ,
ppos , count , test_item , no_builtin_file ) ;
else {
char warning_info [ ] =
" No test result available! \n " ;
dev_err ( dev , " %s: No test result available! \n " , __func__ ) ;
return simple_read_from_buffer ( buf , count , ppos , warning_info ,
strlen ( warning_info ) ) ;
}
return ret ;
}
static const struct file_operations cmcp_results_debugfs_fops = {
. open = cmcp_results_debugfs_open ,
. release = cmcp_results_debugfs_close ,
. read = cmcp_results_debugfs_read ,
. write = NULL ,
} ;
static ssize_t cyttsp5_cmcp_threshold_loading_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
bool cmcp_threshold_loading ;
mutex_lock ( & dad - > cmcp_threshold_lock ) ;
cmcp_threshold_loading = dad - > cmcp_threshold_loading ;
mutex_unlock ( & dad - > cmcp_threshold_lock ) ;
return sprintf ( buf , " %d \n " , cmcp_threshold_loading ) ;
}
/* Return the buffer offset of new test case */
u32 cmcp_return_offset_of_new_case ( const char * bufPtr , u32 first_time )
{
static u32 offset , first_search ;
if ( first_time = = 0 ) {
first_search = 0 ;
offset = 0 ;
}
if ( first_search ! = 0 ) {
/* Search one case */
for ( ; ; ) {
/* Search ASCII_LF */
while ( * bufPtr + + ! = ASCII_LF )
offset + + ;
offset + + ;
/* Single line: end loop
* Multiple lines : continue loop */
if ( * bufPtr ! = ASCII_COMMA )
break ;
}
} else
first_search = 1 ;
return offset ;
}
/* Get test case information from cmcp threshold file */
u32 cmcp_get_case_info_from_threshold_file ( struct device * dev , const char * buf ,
struct test_case_search * search_array , u32 file_size )
{
u32 case_num = 0 , buffer_offset = 0 , name_count = 0 , first_search = 0 ;
dev_vdbg ( dev , " %s: Search cmcp threshold file \n " , __func__ ) ;
/* Get all the test cases */
for ( case_num = 0 ; case_num < MAX_CASE_NUM ; case_num + + ) {
buffer_offset =
cmcp_return_offset_of_new_case ( & buf [ buffer_offset ] ,
first_search ) ;
first_search = 1 ;
if ( buf [ buffer_offset ] = = 0 )
break ;
for ( name_count = 0 ; name_count < NAME_SIZE_MAX ; name_count + + ) {
/* File end */
if ( buf [ buffer_offset + name_count ] = = ASCII_COMMA )
break ;
search_array [ case_num ] . name [ name_count ] =
buf [ buffer_offset + name_count ] ;
}
/* Exit when buffer offset is larger than file size */
if ( buffer_offset > = file_size )
break ;
search_array [ case_num ] . name_size = name_count ;
search_array [ case_num ] . offset = buffer_offset ;
/*
dev_vdbg ( dev ,
" Find case %d: Name is %s; Name size is %d; Case offset is %d \n " ,
case_num ,
search_array [ case_num ] . name ,
search_array [ case_num ] . name_size ,
search_array [ case_num ] . offset ) ;
*/
}
return case_num ;
}
/* Compose one value based on data of each bit */
int cmcp_compose_data ( char * buf , u32 count )
{
u32 base_array [ ] = { 1 , 1e1 , 1e2 , 1e3 , 1e4 , 1e5 , 1e6 , 1e7 , 1e8 , 1e9 } ;
int value = 0 ;
u32 index = 0 ;
for ( index = 0 ; index < count ; index + + )
value + = buf [ index ] * base_array [ count - 1 - index ] ;
return value ;
}
/* Return one value */
int cmcp_return_one_value ( struct device * dev ,
const char * buf , u32 * offset , u32 * line_num )
{
int value = - 1 ;
char tmp_buffer [ 10 ] ;
u32 count = 0 ;
u32 tmp_offset = * offset ;
static u32 line_count = 1 ;
/* Bypass extra commas */
while ( buf [ tmp_offset ] = = ASCII_COMMA
& & buf [ tmp_offset + 1 ] = = ASCII_COMMA )
tmp_offset + + ;
/* Windows and Linux difference at the end of one line */
if ( buf [ tmp_offset ] = = ASCII_COMMA
& & buf [ tmp_offset + 1 ] = = ASCII_CR
& & buf [ tmp_offset + 2 ] = = ASCII_LF )
tmp_offset + = 2 ;
else if ( buf [ tmp_offset ] = = ASCII_COMMA
& & buf [ tmp_offset + 1 ] = = ASCII_LF )
tmp_offset + = 1 ;
/* New line for multiple lines */
if ( buf [ tmp_offset ] = = ASCII_LF & & buf [ tmp_offset + 1 ] = = ASCII_COMMA ) {
tmp_offset + + ;
line_count + + ;
/*dev_vdbg(dev, "\n");*/
}
/* Beginning */
if ( buf [ tmp_offset ] = = ASCII_COMMA ) {
tmp_offset + + ;
for ( ; ; ) {
if ( ( buf [ tmp_offset ] > = ASCII_ZERO )
& & ( buf [ tmp_offset ] < = ASCII_NINE ) ) {
tmp_buffer [ count + + ] =
buf [ tmp_offset ] - ASCII_ZERO ;
tmp_offset + + ;
} else {
if ( count ! = 0 ) {
value = cmcp_compose_data ( tmp_buffer ,
count ) ;
/*dev_vdbg(dev, ",%d", value);*/
} else {
/* 0 indicates no data available */
value = - 1 ;
}
break ;
}
}
} else {
/* Multiple line: line count */
* line_num = line_count ;
/* Reset for next case */
line_count = 1 ;
}
* offset = tmp_offset ;
return value ;
}
/* Get configuration information */
void cmcp_get_configuration_info ( struct device * dev ,
const char * buf , struct test_case_search * search_array ,
u32 case_count , struct test_case_field * field_array ,
struct configuration * config )
{
u32 count = 0 , sub_count = 0 ;
u32 exist_or_not = 0 ;
u32 value_offset = 0 ;
int retval = 0 ;
u32 data_num = 0 ;
u32 line_num = 1 ;
dev_vdbg ( dev ,
" %s: Fill configuration struct per cmcp threshold file \n " ,
__func__ ) ;
/* Search cases */
for ( count = 0 ; count < MAX_CASE_NUM ; count + + ) {
exist_or_not = 0 ;
for ( sub_count = 0 ; sub_count < case_count ; sub_count + + ) {
if ( ! strncmp ( field_array [ count ] . name ,
search_array [ sub_count ] . name ,
field_array [ count ] . name_size ) ) {
exist_or_not = 1 ;
break ;
}
}
field_array [ count ] . exist_or_not = exist_or_not ;
/* Clear data number */
data_num = 0 ;
if ( exist_or_not = = 1 ) {
switch ( field_array [ count ] . type ) {
case TEST_CASE_TYPE_NO :
field_array [ count ] . data_num = 0 ;
field_array [ count ] . line_num = 1 ;
break ;
case TEST_CASE_TYPE_ONE :
value_offset = search_array [ sub_count ] . offset
+ search_array [ sub_count ] . name_size ;
* field_array [ count ] . bufptr =
cmcp_return_one_value ( dev , buf ,
& value_offset , 0 ) ;
field_array [ count ] . data_num = 1 ;
field_array [ count ] . line_num = 1 ;
break ;
case TEST_CASE_TYPE_MUL :
case TEST_CASE_TYPE_MUL_LINES :
line_num = 1 ;
value_offset = search_array [ sub_count ] . offset
+ search_array [ sub_count ] . name_size ;
for ( ; ; ) {
retval = cmcp_return_one_value ( dev ,
buf , & value_offset , & line_num ) ;
if ( retval > = 0 ) {
* field_array [ count ] . bufptr + + =
retval ;
data_num + + ;
} else
break ;
}
field_array [ count ] . data_num = data_num ;
field_array [ count ] . line_num = line_num ;
break ;
default :
break ;
}
dev_vdbg ( dev ,
" %s: %s: Data number is %d, line number is %d \n " ,
__func__ ,
field_array [ count ] . name ,
field_array [ count ] . data_num ,
field_array [ count ] . line_num ) ;
} else
dev_vdbg ( dev , " %s: !!! %s doesn't exist \n " ,
__func__ , field_array [ count ] . name ) ;
}
}
/* Get basic information, like tx, rx, button number */
void cmcp_get_basic_info ( struct device * dev ,
struct test_case_field * field_array , struct configuration * config )
{
# define CMCP_DEBUG 0
u32 tx_num = 0 ;
# if CMCP_DEBUG
u32 index = 0 ;
# endif
config - > is_valid_or_not = 1 ; /* Set to valid by default */
config - > cm_enabled = 0 ;
config - > cp_enabled = 0 ;
if ( field_array [ CM_TEST_INPUTS ] . exist_or_not )
config - > cm_enabled = 1 ;
if ( field_array [ CP_TEST_INPUTS ] . exist_or_not )
config - > cp_enabled = 1 ;
/* Get basic information only when CM and CP are enabled */
if ( config - > cm_enabled & & config - > cp_enabled ) {
dev_vdbg ( dev , " %s: Find CM and CP thresholds \n " , __func__ ) ;
config - > rx_num =
field_array [ PER_ELEMENT_MIN_MAX_TABLE_SENSOR ] . line_num ;
tx_num =
( field_array [ PER_ELEMENT_MIN_MAX_TABLE_SENSOR ] . data_num > > 1 )
/ field_array [ PER_ELEMENT_MIN_MAX_TABLE_SENSOR ] . line_num ;
config - > tx_num = tx_num ;
config - > btn_num =
field_array [ PER_ELEMENT_MIN_MAX_TABLE_BUTTON ] . data_num > > 1 ;
config - > cm_min_max_table_button_size =
field_array [ PER_ELEMENT_MIN_MAX_TABLE_BUTTON ] . data_num ;
config - > cm_min_max_table_sensor_size =
field_array [ PER_ELEMENT_MIN_MAX_TABLE_SENSOR ] . data_num ;
config - > cp_min_max_table_rx_size =
field_array [ PER_ELEMENT_MIN_MAX_RX ] . data_num ;
config - > cp_min_max_table_tx_size =
field_array [ PER_ELEMENT_MIN_MAX_TX ] . data_num ;
config - > cm_max_table_gradient_cols_percent_size =
field_array [ CM_GRADIENT_CHECK_COL ] . data_num ;
config - > cm_max_table_gradient_rows_percent_size =
field_array [ CM_GRADIENT_CHECK_ROW ] . data_num ;
config - > cp_min_max_table_button_size =
field_array [ CP_PER_ELEMENT_MIN_MAX_BUTTON ] . data_num ;
# if CMCP_DEBUG
dev_vdbg ( dev , " %d \n " , config - > cm_excluding_col_edge ) ;
dev_vdbg ( dev , " %d \n " , config - > cm_excluding_row_edge ) ;
for ( index = 0 ;
index < config - > cm_max_table_gradient_cols_percent_size ;
index + + )
dev_vdbg ( dev , " %d \n " ,
config - > cm_max_table_gradient_cols_percent [ index ] ) ;
for ( index = 0 ;
index < config - > cm_max_table_gradient_rows_percent_size ;
index + + )
dev_vdbg ( dev , " %d \n " ,
config - > cm_max_table_gradient_rows_percent [ index ] ) ;
dev_vdbg ( dev , " %d \n " , config - > cm_range_limit_row ) ;
dev_vdbg ( dev , " %d \n " , config - > cm_range_limit_col ) ;
dev_vdbg ( dev , " %d \n " , config - > cm_min_limit_cal ) ;
dev_vdbg ( dev , " %d \n " , config - > cm_max_limit_cal ) ;
dev_vdbg ( dev , " %d \n " , config - > cm_max_delta_sensor_percent ) ;
dev_vdbg ( dev , " %d \n " , config - > cm_max_delta_button_percent ) ;
for ( index = 0 ;
index < config - > cm_min_max_table_button_size ; index + + )
dev_vdbg ( dev , " %d \n " ,
config - > cm_min_max_table_button [ index ] ) ;
for ( index = 0 ;
index < config - > cm_min_max_table_sensor_size ; index + + )
dev_vdbg ( dev , " %d \n " ,
config - > cm_min_max_table_sensor [ index ] ) ;
dev_vdbg ( dev , " %d \n " ,
config - > cp_max_delta_sensor_rx_percent ) ;
dev_vdbg ( dev , " %d \n " ,
config - > cp_max_delta_sensor_tx_percent ) ;
dev_vdbg ( dev , " %d \n " ,
config - > cp_max_delta_button_percent ) ;
dev_vdbg ( dev , " %d \n " ,
config - > min_button ) ;
dev_vdbg ( dev , " %d \n " ,
config - > max_button ) ;
for ( index = 0 ;
index < config - > cp_min_max_table_button_size ; index + + )
dev_vdbg ( dev , " %d \n " ,
config - > cp_min_max_table_button [ index ] ) ;
for ( index = 0 ;
index < config - > cp_min_max_table_rx_size ; index + + )
dev_vdbg ( dev , " %d \n " ,
config - > cp_min_max_table_rx [ index ] ) ;
for ( index = 0 ;
index < config - > cp_min_max_table_tx_size ; index + + )
dev_vdbg ( dev , " %d \n " ,
config - > cp_min_max_table_tx [ index ] ) ;
# endif
/* Invalid mutual data length */
if ( ( field_array [ PER_ELEMENT_MIN_MAX_TABLE_SENSOR ] . data_num > >
1 ) % field_array [ PER_ELEMENT_MIN_MAX_TABLE_SENSOR ] . line_num ) {
config - > is_valid_or_not = 0 ;
dev_vdbg ( dev , " Invalid mutual data length \n " ) ;
}
} else {
if ( ! config - > cm_enabled )
dev_vdbg ( dev ,
" %s: Miss CM thresholds or CM data format is wrong! \n " ,
__func__ ) ;
if ( ! config - > cp_enabled )
dev_vdbg ( dev ,
" %s: Miss CP thresholds or CP data format is wrong! \n " ,
__func__ ) ;
config - > rx_num = 0 ;
config - > tx_num = 0 ;
config - > btn_num = 0 ;
config - > is_valid_or_not = 0 ;
}
dev_vdbg ( dev ,
" %s: \n "
" Input file is %s! \n "
" CM test: %s \n "
" CP test: %s \n "
" rx_num is %d \n "
" tx_num is %d \n "
" btn_num is %d \n " ,
__func__ ,
config - > is_valid_or_not = = 1 ? " VALID " : " !!! INVALID !!! " ,
config - > cm_enabled = = 1 ? " Found " : " Not found " ,
config - > cp_enabled = = 1 ? " Found " : " Not found " ,
config - > rx_num ,
config - > tx_num ,
config - > btn_num ) ;
}
void cmcp_test_case_field_init ( struct test_case_field * test_field_array ,
struct configuration * configs )
{
struct test_case_field test_case_field_array [ MAX_CASE_NUM ] = {
{ " CM TEST INPUTS " , 14 , TEST_CASE_TYPE_NO ,
NULL , 0 , 0 , 0 } ,
{ " CM_EXCLUDING_COL_EDGE " , 21 , TEST_CASE_TYPE_ONE ,
& configs - > cm_excluding_col_edge , 0 , 0 , 0 } ,
{ " CM_EXCLUDING_ROW_EDGE " , 21 , TEST_CASE_TYPE_ONE ,
& configs - > cm_excluding_row_edge , 0 , 0 , 0 } ,
{ " CM_GRADIENT_CHECK_COL " , 21 , TEST_CASE_TYPE_MUL ,
& configs - > cm_max_table_gradient_cols_percent [ 0 ] ,
0 , 0 , 0 } ,
{ " CM_GRADIENT_CHECK_ROW " , 21 , TEST_CASE_TYPE_MUL ,
& configs - > cm_max_table_gradient_rows_percent [ 0 ] ,
0 , 0 , 0 } ,
{ " CM_RANGE_LIMIT_ROW " , 18 , TEST_CASE_TYPE_ONE ,
& configs - > cm_range_limit_row , 0 , 0 , 0 } ,
{ " CM_RANGE_LIMIT_COL " , 18 , TEST_CASE_TYPE_ONE ,
& configs - > cm_range_limit_col , 0 , 0 , 0 } ,
{ " CM_MIN_LIMIT_CAL " , 16 , TEST_CASE_TYPE_ONE ,
& configs - > cm_min_limit_cal , 0 , 0 , 0 } ,
{ " CM_MAX_LIMIT_CAL " , 16 , TEST_CASE_TYPE_ONE ,
& configs - > cm_max_limit_cal , 0 , 0 , 0 } ,
{ " CM_MAX_DELTA_SENSOR_PERCENT " , 27 , TEST_CASE_TYPE_ONE ,
& configs - > cm_max_delta_sensor_percent , 0 , 0 , 0 } ,
{ " CM_MAX_DELTA_BUTTON_PERCENT " , 27 , TEST_CASE_TYPE_ONE ,
& configs - > cm_max_delta_button_percent , 0 , 0 , 0 } ,
{ " PER_ELEMENT_MIN_MAX_TABLE_BUTTON " , 32 , TEST_CASE_TYPE_MUL ,
& configs - > cm_min_max_table_button [ 0 ] , 0 , 0 , 0 } ,
{ " PER_ELEMENT_MIN_MAX_TABLE_SENSOR " , 32 ,
TEST_CASE_TYPE_MUL_LINES ,
& configs - > cm_min_max_table_sensor [ 0 ] , 0 , 0 , 0 } ,
{ " CP TEST INPUTS " , 14 , TEST_CASE_TYPE_NO ,
NULL , 0 , 0 , 0 } ,
{ " CP_PER_ELEMENT_MIN_MAX_BUTTON " , 29 , TEST_CASE_TYPE_MUL ,
& configs - > cp_min_max_table_button [ 0 ] , 0 , 0 , 0 } ,
{ " CP_MAX_DELTA_SENSOR_RX_PERCENT " , 30 , TEST_CASE_TYPE_ONE ,
& configs - > cp_max_delta_sensor_rx_percent ,
0 , 0 , 0 } ,
{ " CP_MAX_DELTA_SENSOR_TX_PERCENT " , 30 , TEST_CASE_TYPE_ONE ,
& configs - > cp_max_delta_sensor_tx_percent ,
0 , 0 , 0 } ,
{ " CP_MAX_DELTA_BUTTON_PERCENT " , 27 , TEST_CASE_TYPE_ONE ,
& configs - > cp_max_delta_button_percent , 0 , 0 , 0 } ,
{ " MIN_BUTTON " , 10 , TEST_CASE_TYPE_ONE ,
& configs - > min_button , 0 , 0 , 0 } ,
{ " MAX_BUTTON " , 10 , TEST_CASE_TYPE_ONE ,
& configs - > max_button , 0 , 0 , 0 } ,
{ " PER_ELEMENT_MIN_MAX_RX " , 22 , TEST_CASE_TYPE_MUL ,
& configs - > cp_min_max_table_rx [ 0 ] , 0 , 0 , 0 } ,
{ " PER_ELEMENT_MIN_MAX_TX " , 22 , TEST_CASE_TYPE_MUL ,
& configs - > cp_min_max_table_tx [ 0 ] , 0 , 0 , 0 } ,
} ;
memcpy ( test_field_array , test_case_field_array ,
sizeof ( struct test_case_field ) * MAX_CASE_NUM ) ;
}
static ssize_t cyttsp5_parse_cmcp_threshold_file_common (
struct device * dev , const char * buf , u32 file_size )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
ssize_t rc = 0 ;
u32 case_count = 0 ;
dev_vdbg ( dev ,
" %s: Start parsing cmcp threshold file. File size is %d \n " ,
__func__ , file_size ) ;
cmcp_test_case_field_init ( dad - > test_field_array , dad - > configs ) ;
/* Get all the cases from .csv file */
case_count = cmcp_get_case_info_from_threshold_file ( dev ,
buf , dad - > test_search_array , file_size ) ;
/* Search cases */
cmcp_get_configuration_info ( dev ,
buf ,
dad - > test_search_array , case_count , dad - > test_field_array ,
dad - > configs ) ;
/* Get basic information */
cmcp_get_basic_info ( dev , dad - > test_field_array , dad - > configs ) ;
return rc ;
}
static ssize_t cyttsp5_cmcp_threshold_loading_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
long value ;
int rc ;
rc = kstrtol ( buf , 10 , & value ) ;
if ( rc < 0 | | value < - 1 | | value > 1 ) {
dev_err ( dev , " %s: Invalid value \n " , __func__ ) ;
return size ;
}
mutex_lock ( & dad - > cmcp_threshold_lock ) ;
if ( value = = 1 )
dad - > cmcp_threshold_loading = true ;
else if ( value = = - 1 )
dad - > cmcp_threshold_loading = false ;
else if ( value = = 0 & & dad - > cmcp_threshold_loading ) {
dad - > cmcp_threshold_loading = false ;
if ( dad - > cmcp_threshold_size = = 0 ) {
dev_err ( dev , " %s: No cmcp threshold data \n " , __func__ ) ;
goto exit_free ;
}
/* Clear test executed flag */
dad - > test_executed = 0 ;
cyttsp5_parse_cmcp_threshold_file_common ( dev ,
& dad - > cmcp_threshold_data [ 0 ] , dad - > cmcp_threshold_size ) ;
/* Mark valid */
dad - > builtin_cmcp_threshold_status = 0 ;
/* Restore test item to default value when new file input */
dad - > cmcp_test_items = 0 ;
}
exit_free :
kfree ( dad - > cmcp_threshold_data ) ;
dad - > cmcp_threshold_data = NULL ;
dad - > cmcp_threshold_size = 0 ;
mutex_unlock ( & dad - > cmcp_threshold_lock ) ;
if ( rc )
return rc ;
return size ;
}
static DEVICE_ATTR ( cmcp_threshold_loading , S_IRUSR | S_IWUSR ,
cyttsp5_cmcp_threshold_loading_show ,
cyttsp5_cmcp_threshold_loading_store ) ;
/*
* cmcp threshold data write
*/
static ssize_t cyttsp5_cmcp_threshold_data_write ( struct file * filp ,
struct kobject * kobj , struct bin_attribute * bin_attr ,
char * buf , loff_t offset , size_t count )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
u8 * p ;
dev_vdbg ( dev , " %s: offset:%lld count:%zu \n " , __func__ , offset , count ) ;
mutex_lock ( & dad - > cmcp_threshold_lock ) ;
if ( ! dad - > cmcp_threshold_loading ) {
mutex_unlock ( & dad - > cmcp_threshold_lock ) ;
return - ENODEV ;
}
p = krealloc ( dad - > cmcp_threshold_data , offset + count , GFP_KERNEL ) ;
if ( ! p ) {
kfree ( dad - > cmcp_threshold_data ) ;
dad - > cmcp_threshold_data = NULL ;
mutex_unlock ( & dad - > cmcp_threshold_lock ) ;
return - ENOMEM ;
}
dad - > cmcp_threshold_data = p ;
memcpy ( & dad - > cmcp_threshold_data [ offset ] , buf , count ) ;
dad - > cmcp_threshold_size + = count ;
mutex_unlock ( & dad - > cmcp_threshold_lock ) ;
return count ;
}
static struct bin_attribute bin_attr_cmcp_threshold_data = {
. attr = {
. name = " cmcp_threshold_data " ,
. mode = S_IWUSR ,
} ,
. size = 0 ,
. write = cyttsp5_cmcp_threshold_data_write ,
} ;
/*
* Suspend scan command
*/
static int cyttsp5_suspend_scan_cmd_ ( struct device * dev )
{
int rc ;
rc = cmd - > nonhid_cmd - > suspend_scanning ( dev , 0 ) ;
if ( rc < 0 )
dev_err ( dev , " %s: Suspend scan failed r=%d \n " ,
__func__ , rc ) ;
return rc ;
}
/*
* Resume scan command
*/
static int cyttsp5_resume_scan_cmd_ ( struct device * dev )
{
int rc ;
rc = cmd - > nonhid_cmd - > resume_scanning ( dev , 0 ) ;
if ( rc < 0 )
dev_err ( dev , " %s: Resume scan failed r=%d \n " ,
__func__ , rc ) ;
return rc ;
}
/*
* Execute scan command
*/
static int cyttsp5_exec_scan_cmd_ ( struct device * dev )
{
int rc ;
rc = cmd - > nonhid_cmd - > exec_panel_scan ( dev , 0 ) ;
if ( rc < 0 )
dev_err ( dev , " %s: Heatmap start scan failed r=%d \n " ,
__func__ , rc ) ;
return rc ;
}
/*
* Retrieve panel data command
*/
static int cyttsp5_ret_scan_data_cmd_ ( struct device * dev , u16 read_offset ,
u16 read_count , u8 data_id , u8 * response , u8 * config ,
u16 * actual_read_len , u8 * return_buf )
{
int rc ;
rc = cmd - > nonhid_cmd - > retrieve_panel_scan ( dev , 0 , read_offset ,
read_count , data_id , response , config , actual_read_len ,
return_buf ) ;
if ( rc < 0 )
dev_err ( dev , " %s: Retrieve scan data failed r=%d \n " ,
__func__ , rc ) ;
return rc ;
}
/*
* Get data structure command
*/
static int cyttsp5_get_data_structure_cmd_ ( struct device * dev , u16 read_offset ,
u16 read_length , u8 data_id , u8 * status , u8 * data_format ,
u16 * actual_read_len , u8 * data )
{
int rc ;
rc = cmd - > nonhid_cmd - > get_data_structure ( dev , 0 , read_offset ,
read_length , data_id , status , data_format ,
actual_read_len , data ) ;
if ( rc < 0 )
dev_err ( dev , " %s: Get data structure failed r=%d \n " ,
__func__ , rc ) ;
return rc ;
}
/*
* Run self test command
*/
static int cyttsp5_run_selftest_cmd_ ( struct device * dev , u8 test_id ,
u8 write_idacs_to_flash , u8 * status , u8 * summary_result ,
u8 * results_available )
{
int rc ;
rc = cmd - > nonhid_cmd - > run_selftest ( dev , 0 , test_id ,
write_idacs_to_flash , status , summary_result ,
results_available ) ;
if ( rc < 0 )
dev_err ( dev , " %s: Run self test failed r=%d \n " ,
__func__ , rc ) ;
return rc ;
}
/*
* Get self test result command
*/
static int cyttsp5_get_selftest_result_cmd_ ( struct device * dev ,
u16 read_offset , u16 read_length , u8 test_id , u8 * status ,
u16 * actual_read_len , u8 * data )
{
int rc ;
rc = cmd - > nonhid_cmd - > get_selftest_result ( dev , 0 , read_offset ,
read_length , test_id , status , actual_read_len , data ) ;
if ( rc < 0 )
dev_err ( dev , " %s: Get self test result failed r=%d \n " ,
__func__ , rc ) ;
return rc ;
}
/*
* Calibrate IDACs command
*/
static int _cyttsp5_calibrate_idacs_cmd ( struct device * dev ,
u8 sensing_mode , u8 * status )
{
int rc ;
rc = cmd - > nonhid_cmd - > calibrate_idacs ( dev , 0 , sensing_mode , status ) ;
return rc ;
}
/*
* Initialize Baselines command
*/
static int _cyttsp5_initialize_baselines_cmd ( struct device * dev ,
u8 sensing_mode , u8 * status )
{
int rc ;
rc = cmd - > nonhid_cmd - > initialize_baselines ( dev , 0 , sensing_mode ,
status ) ;
return rc ;
}
static int prepare_print_buffer ( int status , u8 * in_buf , int length ,
u8 * out_buf , size_t out_buf_size )
{
int index = 0 ;
int i ;
index + = scnprintf ( out_buf , out_buf_size , " status %d \n " , status ) ;
for ( i = 0 ; i < length ; i + + ) {
index + = scnprintf ( & out_buf [ index ] , out_buf_size - index ,
" %02X \n " , in_buf [ i ] ) ;
}
return index ;
}
static ssize_t cyttsp5_run_and_get_selftest_result_noprint ( struct device * dev ,
char * buf , size_t buf_len , u8 test_id , u16 read_length ,
bool get_result_on_pass )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
int status = STATUS_FAIL ;
u8 cmd_status = 0 ;
u8 summary_result = 0 ;
u16 act_length = 0 ;
int length = 0 ;
int rc ;
mutex_lock ( & dad - > sysfs_lock ) ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > request_exclusive ( dev , CY_REQUEST_EXCLUSIVE_TIMEOUT ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on request exclusive r=%d \n " ,
__func__ , rc ) ;
goto put_pm_runtime ;
}
rc = cyttsp5_suspend_scan_cmd_ ( dev ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on suspend scan r=%d \n " ,
__func__ , rc ) ;
goto release_exclusive ;
}
rc = cyttsp5_run_selftest_cmd_ ( dev , test_id , 0 ,
& cmd_status , & summary_result , NULL ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on run self test for test_id:%d r=%d \n " ,
__func__ , test_id , rc ) ;
goto resume_scan ;
}
/* Form response buffer */
dad - > ic_buf [ 0 ] = cmd_status ;
dad - > ic_buf [ 1 ] = summary_result ;
length = 2 ;
/* Get data if command status is success */
if ( cmd_status ! = CY_CMD_STATUS_SUCCESS )
goto status_success ;
/* Get data unless test result is pass */
if ( summary_result = = CY_ST_RESULT_PASS & & ! get_result_on_pass )
goto status_success ;
rc = cyttsp5_get_selftest_result_cmd_ ( dev , 0 , read_length ,
test_id , & cmd_status , & act_length , & dad - > ic_buf [ 6 ] ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on get self test result r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
dad - > ic_buf [ 2 ] = cmd_status ;
dad - > ic_buf [ 3 ] = test_id ;
dad - > ic_buf [ 4 ] = LOW_BYTE ( act_length ) ;
dad - > ic_buf [ 5 ] = HI_BYTE ( act_length ) ;
length = 6 + act_length ;
status_success :
status = STATUS_SUCCESS ;
resume_scan :
cyttsp5_resume_scan_cmd_ ( dev ) ;
release_exclusive :
cmd - > release_exclusive ( dev ) ;
put_pm_runtime :
pm_runtime_put ( dev ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
return status ;
}
static ssize_t cyttsp5_run_and_get_selftest_result ( struct device * dev ,
char * buf , size_t buf_len , u8 test_id , u16 read_length ,
bool get_result_on_pass )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
int status = STATUS_FAIL ;
u8 cmd_status = 0 ;
u8 summary_result = 0 ;
u16 act_length = 0 ;
int length = 0 ;
int size ;
int rc ;
mutex_lock ( & dad - > sysfs_lock ) ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > request_exclusive ( dev , CY_REQUEST_EXCLUSIVE_TIMEOUT ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on request exclusive r=%d \n " ,
__func__ , rc ) ;
goto put_pm_runtime ;
}
rc = cyttsp5_suspend_scan_cmd_ ( dev ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on suspend scan r=%d \n " ,
__func__ , rc ) ;
goto release_exclusive ;
}
rc = cyttsp5_run_selftest_cmd_ ( dev , test_id , 0 ,
& cmd_status , & summary_result , NULL ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on run self test for test_id:%d r=%d \n " ,
__func__ , test_id , rc ) ;
goto resume_scan ;
}
/* Form response buffer */
dad - > ic_buf [ 0 ] = cmd_status ;
dad - > ic_buf [ 1 ] = summary_result ;
length = 2 ;
/* Get data if command status is success */
if ( cmd_status ! = CY_CMD_STATUS_SUCCESS )
goto status_success ;
/* Get data unless test result is pass */
if ( summary_result = = CY_ST_RESULT_PASS & & ! get_result_on_pass )
goto status_success ;
rc = cyttsp5_get_selftest_result_cmd_ ( dev , 0 , read_length ,
test_id , & cmd_status , & act_length , & dad - > ic_buf [ 6 ] ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on get self test result r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
dad - > ic_buf [ 2 ] = cmd_status ;
dad - > ic_buf [ 3 ] = test_id ;
dad - > ic_buf [ 4 ] = LOW_BYTE ( act_length ) ;
dad - > ic_buf [ 5 ] = HI_BYTE ( act_length ) ;
length = 6 + act_length ;
status_success :
status = STATUS_SUCCESS ;
resume_scan :
cyttsp5_resume_scan_cmd_ ( dev ) ;
release_exclusive :
cmd - > release_exclusive ( dev ) ;
put_pm_runtime :
pm_runtime_put ( dev ) ;
if ( status = = STATUS_FAIL )
length = 0 ;
size = prepare_print_buffer ( status , dad - > ic_buf , length , buf , buf_len ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
return size ;
}
struct cyttsp5_device_access_debugfs_data {
struct cyttsp5_device_access_data * dad ;
ssize_t pr_buf_len ;
u8 pr_buf [ 3 * CY_MAX_PRBUF_SIZE ] ;
} ;
static int cyttsp5_device_access_debugfs_open ( struct inode * inode ,
struct file * filp )
{
struct cyttsp5_device_access_data * dad = inode - > i_private ;
struct cyttsp5_device_access_debugfs_data * data ;
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
data - > dad = dad ;
filp - > private_data = data ;
return nonseekable_open ( inode , filp ) ;
}
static int cyttsp5_device_access_debugfs_release ( struct inode * inode ,
struct file * filp )
{
kfree ( filp - > private_data ) ;
return 0 ;
}
# define CY_DEBUGFS_FOPS(_name, _read, _write) \
static const struct file_operations _name # # _debugfs_fops = { \
. open = cyttsp5_device_access_debugfs_open , \
. release = cyttsp5_device_access_debugfs_release , \
. read = _read , \
. write = _write , \
}
static ssize_t panel_scan_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
struct device * dev = dad - > dev ;
int status = STATUS_FAIL ;
u8 config ;
u16 actual_read_len ;
int length = 0 ;
u8 element_size = 0 ;
u8 * buf_offset ;
int elem_offset = 0 ;
int rc ;
if ( * ppos )
goto exit ;
mutex_lock ( & dad - > sysfs_lock ) ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > request_exclusive ( dev , CY_REQUEST_EXCLUSIVE_TIMEOUT ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on request exclusive r=%d \n " ,
__func__ , rc ) ;
goto put_pm_runtime ;
}
rc = cyttsp5_suspend_scan_cmd_ ( dev ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on suspend scan r=%d \n " ,
__func__ , rc ) ;
goto release_exclusive ;
}
rc = cyttsp5_exec_scan_cmd_ ( dev ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on execute panel scan r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
/* Set length to max to read all */
rc = cyttsp5_ret_scan_data_cmd_ ( dev , 0 , 0xFFFF ,
dad - > panel_scan_data_id , dad - > ic_buf , & config ,
& actual_read_len , NULL ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on retrieve panel scan r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
length = get_unaligned_le16 ( & dad - > ic_buf [ 0 ] ) ;
buf_offset = dad - > ic_buf + length ;
element_size = config & 0x07 ;
elem_offset = actual_read_len ;
while ( actual_read_len > 0 ) {
rc = cyttsp5_ret_scan_data_cmd_ ( dev , elem_offset , 0xFFFF ,
dad - > panel_scan_data_id , NULL , & config ,
& actual_read_len , buf_offset ) ;
if ( rc < 0 )
goto resume_scan ;
length + = actual_read_len * element_size ;
buf_offset = dad - > ic_buf + length ;
elem_offset + = actual_read_len ;
}
/* Reconstruct cmd header */
put_unaligned_le16 ( length , & dad - > ic_buf [ 0 ] ) ;
put_unaligned_le16 ( elem_offset , & dad - > ic_buf [ 7 ] ) ;
/* Do not print command header */
length - = 5 ;
status = STATUS_SUCCESS ;
resume_scan :
cyttsp5_resume_scan_cmd_ ( dev ) ;
release_exclusive :
cmd - > release_exclusive ( dev ) ;
put_pm_runtime :
pm_runtime_put ( dev ) ;
if ( status = = STATUS_FAIL )
length = 0 ;
data - > pr_buf_len = prepare_print_buffer ( status , & dad - > ic_buf [ 5 ] ,
length , data - > pr_buf , sizeof ( data - > pr_buf ) ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
exit :
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
static ssize_t panel_scan_debugfs_write ( struct file * filp ,
const char __user * buf , size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
ssize_t length ;
int rc = 0 ;
rc = simple_write_to_buffer ( data - > pr_buf , sizeof ( data - > pr_buf ) , ppos ,
buf , count ) ;
if ( rc < 0 )
return rc ;
count = rc ;
mutex_lock ( & dad - > sysfs_lock ) ;
length = cyttsp5_ic_parse_input ( dad - > dev , data - > pr_buf , count ,
dad - > ic_buf , CY_MAX_PRBUF_SIZE ) ;
if ( length ! = 1 ) {
dev_err ( dad - > dev , " %s: Malformed input \n " , __func__ ) ;
rc = - EINVAL ;
goto exit_unlock ;
}
dad - > panel_scan_data_id = dad - > ic_buf [ 0 ] ;
exit_unlock :
mutex_unlock ( & dad - > sysfs_lock ) ;
if ( rc )
return rc ;
return count ;
}
CY_DEBUGFS_FOPS ( panel_scan , panel_scan_debugfs_read , panel_scan_debugfs_write ) ;
static ssize_t get_idac_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
struct device * dev = dad - > dev ;
int status = STATUS_FAIL ;
u8 cmd_status = 0 ;
u8 data_format = 0 ;
u16 act_length = 0 ;
int length = 0 ;
int rc ;
if ( * ppos )
goto exit ;
mutex_lock ( & dad - > sysfs_lock ) ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > request_exclusive ( dev , CY_REQUEST_EXCLUSIVE_TIMEOUT ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on request exclusive r=%d \n " ,
__func__ , rc ) ;
goto put_pm_runtime ;
}
rc = cyttsp5_suspend_scan_cmd_ ( dev ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on suspend scan r=%d \n " ,
__func__ , rc ) ;
goto release_exclusive ;
}
rc = cyttsp5_get_data_structure_cmd_ ( dev , 0 , PIP_CMD_MAX_LENGTH ,
dad - > get_idac_data_id , & cmd_status , & data_format ,
& act_length , & dad - > ic_buf [ 5 ] ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on get data structure r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
dad - > ic_buf [ 0 ] = cmd_status ;
dad - > ic_buf [ 1 ] = dad - > get_idac_data_id ;
dad - > ic_buf [ 2 ] = LOW_BYTE ( act_length ) ;
dad - > ic_buf [ 3 ] = HI_BYTE ( act_length ) ;
dad - > ic_buf [ 4 ] = data_format ;
length = 5 + act_length ;
status = STATUS_SUCCESS ;
resume_scan :
cyttsp5_resume_scan_cmd_ ( dev ) ;
release_exclusive :
cmd - > release_exclusive ( dev ) ;
put_pm_runtime :
pm_runtime_put ( dev ) ;
if ( status = = STATUS_FAIL )
length = 0 ;
data - > pr_buf_len = prepare_print_buffer ( status , dad - > ic_buf , length ,
data - > pr_buf , sizeof ( data - > pr_buf ) ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
exit :
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
static ssize_t get_idac_debugfs_write ( struct file * filp ,
const char __user * buf , size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
ssize_t length ;
int rc = 0 ;
rc = simple_write_to_buffer ( data - > pr_buf , sizeof ( data - > pr_buf ) , ppos ,
buf , count ) ;
if ( rc < 0 )
return rc ;
count = rc ;
mutex_lock ( & dad - > sysfs_lock ) ;
length = cyttsp5_ic_parse_input ( dad - > dev , data - > pr_buf , count ,
dad - > ic_buf , CY_MAX_PRBUF_SIZE ) ;
if ( length ! = 1 ) {
dev_err ( dad - > dev , " %s: Malformed input \n " , __func__ ) ;
rc = - EINVAL ;
goto exit_unlock ;
}
dad - > get_idac_data_id = dad - > ic_buf [ 0 ] ;
exit_unlock :
mutex_unlock ( & dad - > sysfs_lock ) ;
if ( rc )
return rc ;
return count ;
}
CY_DEBUGFS_FOPS ( get_idac , get_idac_debugfs_read , get_idac_debugfs_write ) ;
static ssize_t calibrate_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
struct device * dev = dad - > dev ;
int status = STATUS_FAIL ;
int length = 0 ;
int rc ;
if ( * ppos )
goto exit ;
mutex_lock ( & dad - > sysfs_lock ) ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > request_exclusive ( dev , CY_REQUEST_EXCLUSIVE_TIMEOUT ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on request exclusive r=%d \n " ,
__func__ , rc ) ;
goto put_pm_runtime ;
}
rc = cyttsp5_suspend_scan_cmd_ ( dev ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on suspend scan r=%d \n " ,
__func__ , rc ) ;
goto release_exclusive ;
}
rc = _cyttsp5_calibrate_idacs_cmd ( dev , dad - > calibrate_sensing_mode ,
& dad - > ic_buf [ 0 ] ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on calibrate idacs r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
length = 1 ;
/* Check if baseline initialization is requested */
if ( dad - > calibrate_initialize_baselines ) {
/* Perform baseline initialization for all modes */
rc = _cyttsp5_initialize_baselines_cmd ( dev , CY_IB_SM_MUTCAP |
CY_IB_SM_SELFCAP | CY_IB_SM_BUTTON ,
& dad - > ic_buf [ length ] ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on initialize baselines r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
length + + ;
}
status = STATUS_SUCCESS ;
resume_scan :
cyttsp5_resume_scan_cmd_ ( dev ) ;
release_exclusive :
cmd - > release_exclusive ( dev ) ;
put_pm_runtime :
pm_runtime_put ( dev ) ;
if ( status = = STATUS_FAIL )
length = 0 ;
data - > pr_buf_len = prepare_print_buffer ( status , dad - > ic_buf , length ,
data - > pr_buf , sizeof ( data - > pr_buf ) ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
exit :
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
static ssize_t calibrate_debugfs_write ( struct file * filp ,
const char __user * buf , size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
ssize_t length ;
int rc = 0 ;
rc = simple_write_to_buffer ( data - > pr_buf , sizeof ( data - > pr_buf ) , ppos ,
buf , count ) ;
if ( rc < 0 )
return rc ;
count = rc ;
mutex_lock ( & dad - > sysfs_lock ) ;
length = cyttsp5_ic_parse_input ( dad - > dev , data - > pr_buf , count ,
dad - > ic_buf , CY_MAX_PRBUF_SIZE ) ;
if ( length ! = 2 ) {
dev_err ( dad - > dev , " %s: Malformed input \n " , __func__ ) ;
rc = - EINVAL ;
goto exit_unlock ;
}
dad - > calibrate_sensing_mode = dad - > ic_buf [ 0 ] ;
dad - > calibrate_initialize_baselines = dad - > ic_buf [ 1 ] ;
exit_unlock :
mutex_unlock ( & dad - > sysfs_lock ) ;
if ( rc )
return rc ;
return count ;
}
CY_DEBUGFS_FOPS ( calibrate , calibrate_debugfs_read , calibrate_debugfs_write ) ;
static ssize_t baseline_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
struct device * dev = dad - > dev ;
int status = STATUS_FAIL ;
int length = 0 ;
int rc ;
if ( * ppos )
goto exit ;
mutex_lock ( & dad - > sysfs_lock ) ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > request_exclusive ( dev , CY_REQUEST_EXCLUSIVE_TIMEOUT ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on request exclusive r=%d \n " ,
__func__ , rc ) ;
goto put_pm_runtime ;
}
rc = cyttsp5_suspend_scan_cmd_ ( dev ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on suspend scan r=%d \n " ,
__func__ , rc ) ;
goto release_exclusive ;
}
rc = _cyttsp5_initialize_baselines_cmd ( dev , dad - > baseline_sensing_mode ,
& dad - > ic_buf [ 0 ] ) ;
if ( rc < 0 ) {
dev_err ( dev , " %s: Error on initialize baselines r=%d \n " ,
__func__ , rc ) ;
goto resume_scan ;
}
length = 1 ;
status = STATUS_SUCCESS ;
resume_scan :
cyttsp5_resume_scan_cmd_ ( dev ) ;
release_exclusive :
cmd - > release_exclusive ( dev ) ;
put_pm_runtime :
pm_runtime_put ( dev ) ;
if ( status = = STATUS_FAIL )
length = 0 ;
data - > pr_buf_len = prepare_print_buffer ( status , dad - > ic_buf , length ,
data - > pr_buf , sizeof ( data - > pr_buf ) ) ;
mutex_unlock ( & dad - > sysfs_lock ) ;
exit :
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
static ssize_t baseline_debugfs_write ( struct file * filp ,
const char __user * buf , size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
struct cyttsp5_device_access_data * dad = data - > dad ;
ssize_t length ;
int rc = 0 ;
rc = simple_write_to_buffer ( data - > pr_buf , sizeof ( data - > pr_buf ) , ppos ,
buf , count ) ;
if ( rc < 0 )
return rc ;
count = rc ;
mutex_lock ( & dad - > sysfs_lock ) ;
length = cyttsp5_ic_parse_input ( dad - > dev , buf , count , dad - > ic_buf ,
CY_MAX_PRBUF_SIZE ) ;
if ( length ! = 1 ) {
dev_err ( dad - > dev , " %s: Malformed input \n " , __func__ ) ;
rc = - EINVAL ;
goto exit_unlock ;
}
dad - > baseline_sensing_mode = dad - > ic_buf [ 0 ] ;
exit_unlock :
mutex_unlock ( & dad - > sysfs_lock ) ;
if ( rc )
return rc ;
return count ;
}
CY_DEBUGFS_FOPS ( baseline , baseline_debugfs_read , baseline_debugfs_write ) ;
static ssize_t auto_shorts_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
if ( ! * ppos )
/* Set length to PIP_CMD_MAX_LENGTH to read all */
data - > pr_buf_len = cyttsp5_run_and_get_selftest_result (
data - > dad - > dev , data - > pr_buf , sizeof ( data - > pr_buf ) ,
CY_ST_ID_AUTOSHORTS , PIP_CMD_MAX_LENGTH , false ) ;
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
CY_DEBUGFS_FOPS ( auto_shorts , auto_shorts_debugfs_read , NULL ) ;
static ssize_t opens_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
if ( ! * ppos )
/* Set length to PIP_CMD_MAX_LENGTH to read all */
data - > pr_buf_len = cyttsp5_run_and_get_selftest_result (
data - > dad - > dev , data - > pr_buf , sizeof ( data - > pr_buf ) ,
CY_ST_ID_OPENS , PIP_CMD_MAX_LENGTH , false ) ;
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
CY_DEBUGFS_FOPS ( opens , opens_debugfs_read , NULL ) ;
static ssize_t cm_panel_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
if ( ! * ppos )
/* Set length to PIP_CMD_MAX_LENGTH to read all */
data - > pr_buf_len = cyttsp5_run_and_get_selftest_result (
data - > dad - > dev , data - > pr_buf , sizeof ( data - > pr_buf ) ,
CY_ST_ID_CM_PANEL , PIP_CMD_MAX_LENGTH , true ) ;
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
CY_DEBUGFS_FOPS ( cm_panel , cm_panel_debugfs_read , NULL ) ;
static ssize_t cp_panel_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
if ( ! * ppos )
/* Set length to PIP_CMD_MAX_LENGTH to read all */
data - > pr_buf_len = cyttsp5_run_and_get_selftest_result (
data - > dad - > dev , data - > pr_buf , sizeof ( data - > pr_buf ) ,
CY_ST_ID_CP_PANEL , PIP_CMD_MAX_LENGTH , true ) ;
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
CY_DEBUGFS_FOPS ( cp_panel , cp_panel_debugfs_read , NULL ) ;
static ssize_t cm_button_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
if ( ! * ppos )
/* Set length to PIP_CMD_MAX_LENGTH to read all */
data - > pr_buf_len = cyttsp5_run_and_get_selftest_result (
data - > dad - > dev , data - > pr_buf , sizeof ( data - > pr_buf ) ,
CY_ST_ID_CM_BUTTON , PIP_CMD_MAX_LENGTH , true ) ;
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
CY_DEBUGFS_FOPS ( cm_button , cm_button_debugfs_read , NULL ) ;
static ssize_t cp_button_debugfs_read ( struct file * filp , char __user * buf ,
size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_debugfs_data * data = filp - > private_data ;
if ( ! * ppos )
/* Set length to PIP_CMD_MAX_LENGTH to read all */
data - > pr_buf_len = cyttsp5_run_and_get_selftest_result (
data - > dad - > dev , data - > pr_buf , sizeof ( data - > pr_buf ) ,
CY_ST_ID_CP_BUTTON , PIP_CMD_MAX_LENGTH , true ) ;
return simple_read_from_buffer ( buf , count , ppos , data - > pr_buf ,
data - > pr_buf_len ) ;
}
CY_DEBUGFS_FOPS ( cp_button , cp_button_debugfs_read , NULL ) ;
# ifdef TTHE_TUNER_SUPPORT
static ssize_t tthe_get_panel_data_debugfs_read ( struct file * filp ,
char __user * buf , size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_data * dad = filp - > private_data ;
struct device * dev ;
u8 config ;
u16 actual_read_len ;
u16 length = 0 ;
u8 element_size = 0 ;
u8 * buf_offset ;
u8 * buf_out ;
int elem ;
int elem_offset = 0 ;
int print_idx = 0 ;
int rc ;
int rc1 ;
int i ;
mutex_lock ( & dad - > debugfs_lock ) ;
dev = dad - > dev ;
buf_out = dad - > tthe_get_panel_data_buf ;
if ( ! buf_out )
goto release_mutex ;
pm_runtime_get_sync ( dev ) ;
rc = cmd - > request_exclusive ( dev , CY_REQUEST_EXCLUSIVE_TIMEOUT ) ;
if ( rc < 0 )
goto put_runtime ;
if ( dad - > heatmap . scan_start ) {
/* To fix CDT206291: avoid multiple scans when
return data is larger than 4096 bytes in one cycle */
dad - > heatmap . scan_start = 0 ;
/* Start scan */
rc = cyttsp5_exec_scan_cmd_ ( dev ) ;
if ( rc < 0 )
goto release_exclusive ;
}
elem = dad - > heatmap . num_element ;
# if defined(CY_ENABLE_MAX_ELEN)
if ( elem > CY_MAX_ELEN ) {
rc = cyttsp5_ret_scan_data_cmd_ ( dev , elem_offset ,
CY_MAX_ELEN , dad - > heatmap . data_type , dad - > ic_buf ,
& config , & actual_read_len , NULL ) ;
} else {
rc = cyttsp5_ret_scan_data_cmd_ ( dev , elem_offset , elem ,
dad - > heatmap . data_type , dad - > ic_buf , & config ,
& actual_read_len , NULL ) ;
}
# else
rc = cyttsp5_ret_scan_data_cmd_ ( dev , elem_offset , elem ,
dad - > heatmap . data_type , dad - > ic_buf , & config ,
& actual_read_len , NULL ) ;
# endif
if ( rc < 0 )
goto release_exclusive ;
length = get_unaligned_le16 ( & dad - > ic_buf [ 0 ] ) ;
buf_offset = dad - > ic_buf + length ;
element_size = config & CY_CMD_RET_PANEL_ELMNT_SZ_MASK ;
elem - = actual_read_len ;
elem_offset = actual_read_len ;
while ( elem > 0 ) {
# ifdef CY_ENABLE_MAX_ELEN
if ( elem > CY_MAX_ELEN ) {
rc = cyttsp5_ret_scan_data_cmd_ ( dev , elem_offset ,
CY_MAX_ELEN , dad - > heatmap . data_type , NULL , & config ,
& actual_read_len , buf_offset ) ;
} else {
rc = cyttsp5_ret_scan_data_cmd_ ( dev , elem_offset , elem ,
dad - > heatmap . data_type , NULL , & config ,
& actual_read_len , buf_offset ) ;
}
# else
rc = cyttsp5_ret_scan_data_cmd_ ( dev , elem_offset , elem ,
dad - > heatmap . data_type , NULL , & config ,
& actual_read_len , buf_offset ) ;
# endif
if ( rc < 0 )
goto release_exclusive ;
if ( ! actual_read_len )
break ;
length + = actual_read_len * element_size ;
buf_offset = dad - > ic_buf + length ;
elem - = actual_read_len ;
elem_offset + = actual_read_len ;
}
/* Reconstruct cmd header */
put_unaligned_le16 ( length , & dad - > ic_buf [ 0 ] ) ;
put_unaligned_le16 ( elem_offset , & dad - > ic_buf [ 7 ] ) ;
release_exclusive :
rc1 = cmd - > release_exclusive ( dev ) ;
put_runtime :
pm_runtime_put ( dev ) ;
if ( rc < 0 )
goto release_mutex ;
print_idx + = scnprintf ( buf_out , TTHE_TUNER_MAX_BUF , " CY_DATA: " ) ;
for ( i = 0 ; i < length ; i + + )
print_idx + = scnprintf ( buf_out + print_idx ,
TTHE_TUNER_MAX_BUF - print_idx ,
" %02X " , dad - > ic_buf [ i ] ) ;
print_idx + = scnprintf ( buf_out + print_idx ,
TTHE_TUNER_MAX_BUF - print_idx ,
" :(%d bytes) \n " , length ) ;
rc = simple_read_from_buffer ( buf , count , ppos , buf_out , print_idx ) ;
print_idx = rc ;
release_mutex :
mutex_unlock ( & dad - > debugfs_lock ) ;
return print_idx ;
}
static ssize_t tthe_get_panel_data_debugfs_write ( struct file * filp ,
const char __user * buf , size_t count , loff_t * ppos )
{
struct cyttsp5_device_access_data * dad = filp - > private_data ;
struct device * dev = dad - > dev ;
ssize_t length ;
int max_read ;
u8 * buf_in = dad - > tthe_get_panel_data_buf ;
int ret ;
mutex_lock ( & dad - > debugfs_lock ) ;
ret = copy_from_user ( buf_in + ( * ppos ) , buf , count ) ;
if ( ret )
goto exit ;
buf_in [ count ] = 0 ;
length = cyttsp5_ic_parse_input ( dev , buf_in , count , dad - > ic_buf ,
CY_MAX_PRBUF_SIZE ) ;
if ( length < = 0 ) {
dev_err ( dev , " %s: %s Group Data store \n " , __func__ ,
" Malformed input for " ) ;
goto exit ;
}
/* update parameter value */
dad - > heatmap . num_element = get_unaligned_le16 ( & dad - > ic_buf [ 3 ] ) ;
dad - > heatmap . data_type = dad - > ic_buf [ 5 ] ;
if ( dad - > ic_buf [ 6 ] > 0 )
dad - > heatmap . scan_start = true ;
else
dad - > heatmap . scan_start = false ;
/* elem can not be bigger then buffer size */
max_read = CY_CMD_RET_PANEL_HDR ;
max_read + = dad - > heatmap . num_element * CY_CMD_RET_PANEL_ELMNT_SZ_MAX ;
if ( max_read > = CY_MAX_PRBUF_SIZE ) {
dad - > heatmap . num_element =
( CY_MAX_PRBUF_SIZE - CY_CMD_RET_PANEL_HDR )
/ CY_CMD_RET_PANEL_ELMNT_SZ_MAX ;
dev_err ( dev , " %s: Will get %d element \n " , __func__ ,
dad - > heatmap . num_element ) ;
}
exit :
mutex_unlock ( & dad - > debugfs_lock ) ;
dev_vdbg ( dev , " %s: return count=%zu \n " , __func__ , count ) ;
return count ;
}
static int tthe_get_panel_data_debugfs_open ( struct inode * inode ,
struct file * filp )
{
struct cyttsp5_device_access_data * dad = inode - > i_private ;
mutex_lock ( & dad - > debugfs_lock ) ;
if ( dad - > tthe_get_panel_data_is_open ) {
mutex_unlock ( & dad - > debugfs_lock ) ;
return - EBUSY ;
}
filp - > private_data = inode - > i_private ;
dad - > tthe_get_panel_data_is_open = 1 ;
mutex_unlock ( & dad - > debugfs_lock ) ;
return 0 ;
}
static int tthe_get_panel_data_debugfs_close ( struct inode * inode ,
struct file * filp )
{
struct cyttsp5_device_access_data * dad = filp - > private_data ;
mutex_lock ( & dad - > debugfs_lock ) ;
filp - > private_data = NULL ;
dad - > tthe_get_panel_data_is_open = 0 ;
mutex_unlock ( & dad - > debugfs_lock ) ;
return 0 ;
}
static const struct file_operations tthe_get_panel_data_fops = {
. open = tthe_get_panel_data_debugfs_open ,
. release = tthe_get_panel_data_debugfs_close ,
. read = tthe_get_panel_data_debugfs_read ,
. write = tthe_get_panel_data_debugfs_write ,
} ;
# endif
static int cyttsp5_setup_sysfs ( struct device * dev )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
int rc ;
rc = device_create_file ( dev , & dev_attr_command ) ;
if ( rc ) {
dev_err ( dev , " %s: Error, could not create command \n " ,
__func__ ) ;
goto exit ;
}
rc = device_create_file ( dev , & dev_attr_status ) ;
if ( rc ) {
dev_err ( dev , " %s: Error, could not create status \n " ,
__func__ ) ;
goto unregister_command ;
}
rc = device_create_file ( dev , & dev_attr_response ) ;
if ( rc ) {
dev_err ( dev , " %s: Error, could not create response \n " ,
__func__ ) ;
goto unregister_status ;
}
dad - > base_dentry = debugfs_create_dir ( dev_name ( dev ) , NULL ) ;
if ( IS_ERR_OR_NULL ( dad - > base_dentry ) ) {
dev_err ( dev , " %s: Error, could not create base directory \n " ,
__func__ ) ;
goto unregister_response ;
}
dad - > mfg_test_dentry = debugfs_create_dir ( " mfg_test " ,
dad - > base_dentry ) ;
if ( IS_ERR_OR_NULL ( dad - > mfg_test_dentry ) ) {
dev_err ( dev , " %s: Error, could not create mfg_test directory \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " panel_scan " , 0600 ,
dad - > mfg_test_dentry , dad ,
& panel_scan_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create panel_scan \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " get_idac " , 0600 ,
dad - > mfg_test_dentry , dad , & get_idac_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create get_idac \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " auto_shorts " , 0400 ,
dad - > mfg_test_dentry , dad ,
& auto_shorts_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create auto_shorts \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " opens " , 0400 ,
dad - > mfg_test_dentry , dad , & opens_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create opens \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " calibrate " , 0600 ,
dad - > mfg_test_dentry , dad , & calibrate_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create calibrate \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " baseline " , 0600 ,
dad - > mfg_test_dentry , dad , & baseline_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create baseline \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " cm_panel " , 0400 ,
dad - > mfg_test_dentry , dad , & cm_panel_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create cm_panel \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " cp_panel " , 0400 ,
dad - > mfg_test_dentry , dad , & cp_panel_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create cp_panel \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " cm_button " , 0400 ,
dad - > mfg_test_dentry , dad , & cm_button_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create cm_button \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
if ( IS_ERR_OR_NULL ( debugfs_create_file ( " cp_button " , 0400 ,
dad - > mfg_test_dentry , dad , & cp_button_debugfs_fops ) ) ) {
dev_err ( dev , " %s: Error, could not create cp_button \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
dad - > cmcp_results_debugfs = debugfs_create_file ( " cmcp_results " , 0644 ,
dad - > mfg_test_dentry , dad , & cmcp_results_debugfs_fops ) ;
if ( IS_ERR_OR_NULL ( dad - > cmcp_results_debugfs ) ) {
dev_err ( dev , " %s: Error, could not create cmcp_results \n " ,
__func__ ) ;
dad - > cmcp_results_debugfs = NULL ;
goto unregister_base_dir ;
}
# ifdef TTHE_TUNER_SUPPORT
dad - > tthe_get_panel_data_debugfs = debugfs_create_file (
CYTTSP5_TTHE_TUNER_GET_PANEL_DATA_FILE_NAME ,
0644 , NULL , dad , & tthe_get_panel_data_fops ) ;
if ( IS_ERR_OR_NULL ( dad - > tthe_get_panel_data_debugfs ) ) {
dev_err ( dev , " %s: Error, could not create get_panel_data \n " ,
__func__ ) ;
dad - > tthe_get_panel_data_debugfs = NULL ;
goto unregister_base_dir ;
}
# endif
rc = device_create_file ( dev , & dev_attr_cmcp_test ) ;
if ( rc ) {
dev_err ( dev , " %s: Error, could not create cmcp_test \n " ,
__func__ ) ;
goto unregister_base_dir ;
}
rc = device_create_file ( dev , & dev_attr_cmcp_threshold_loading ) ;
if ( rc ) {
dev_err ( dev , " %s: Error, could not create cmcp_thresold_loading \n " ,
__func__ ) ;
goto unregister_cmcp_test ;
}
rc = device_create_bin_file ( dev , & bin_attr_cmcp_threshold_data ) ;
if ( rc ) {
dev_err ( dev , " %s: Error, could not create cmcp_thresold_data \n " ,
__func__ ) ;
goto unregister_cmcp_thresold_loading ;
}
dad - > sysfs_nodes_created = true ;
return rc ;
unregister_cmcp_thresold_loading :
device_remove_file ( dev , & dev_attr_cmcp_threshold_loading ) ;
unregister_cmcp_test :
device_remove_file ( dev , & dev_attr_cmcp_test ) ;
unregister_base_dir :
debugfs_remove_recursive ( dad - > base_dentry ) ;
unregister_response :
device_remove_file ( dev , & dev_attr_response ) ;
unregister_status :
device_remove_file ( dev , & dev_attr_status ) ;
unregister_command :
device_remove_file ( dev , & dev_attr_command ) ;
exit :
return rc ;
}
static int cyttsp5_setup_sysfs_attention ( struct device * dev )
{
struct cyttsp5_device_access_data * dad
= cyttsp5_get_device_access_data ( dev ) ;
int rc = 0 ;
dad - > si = cmd - > request_sysinfo ( dev ) ;
if ( ! dad - > si )
return - EINVAL ;
rc = cyttsp5_setup_sysfs ( dev ) ;
cmd - > unsubscribe_attention ( dev , CY_ATTEN_STARTUP ,
CYTTSP5_DEVICE_ACCESS_NAME , cyttsp5_setup_sysfs_attention ,
0 ) ;
return rc ;
}
# ifdef CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP5_DEVICE_ACCESS_API
int cyttsp5_device_access_user_command ( const char * core_name , u16 read_len ,
u8 * read_buf , u16 write_len , u8 * write_buf ,
u16 * actual_read_len )
{
struct cyttsp5_core_data * cd ;
int rc ;
might_sleep ( ) ;
/* Check parameters */
if ( ! read_buf | | ! write_buf | | ! actual_read_len )
return - EINVAL ;
if ( ! core_name )
core_name = CY_DEFAULT_CORE_ID ;
/* Find device */
cd = cyttsp5_get_core_data ( ( char * ) core_name ) ;
if ( ! cd ) {
pr_err ( " %s: No device. \n " , __func__ ) ;
return - ENODEV ;
}
pm_runtime_get_sync ( cd - > dev ) ;
rc = cmd - > nonhid_cmd - > user_cmd ( cd - > dev , 1 , read_len , read_buf ,
write_len , write_buf , actual_read_len ) ;
pm_runtime_put ( cd - > dev ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( cyttsp5_device_access_user_command ) ;
struct command_work {
struct work_struct work ;
const char * core_name ;
u16 read_len ;
u8 * read_buf ;
u16 write_len ;
u8 * write_buf ;
void ( * cont ) ( const char * core_name , u16 read_len , u8 * read_buf ,
u16 write_len , u8 * write_buf , u16 actual_read_length ,
int rc ) ;
} ;
static void cyttsp5_device_access_user_command_work_func (
struct work_struct * work )
{
struct command_work * cmd_work =
container_of ( work , struct command_work , work ) ;
u16 actual_read_length ;
int rc ;
rc = cyttsp5_device_access_user_command ( cmd_work - > core_name ,
cmd_work - > read_len , cmd_work - > read_buf ,
cmd_work - > write_len , cmd_work - > write_buf ,
& actual_read_length ) ;
if ( cmd_work - > cont )
cmd_work - > cont ( cmd_work - > core_name ,
cmd_work - > read_len , cmd_work - > read_buf ,
cmd_work - > write_len , cmd_work - > write_buf ,
actual_read_length , rc ) ;
kfree ( cmd_work ) ;
}
int cyttsp5_device_access_user_command_async ( const char * core_name ,
u16 read_len , u8 * read_buf , u16 write_len , u8 * write_buf ,
void ( * cont ) ( const char * core_name , u16 read_len , u8 * read_buf ,
u16 write_len , u8 * write_buf , u16 actual_read_length ,
int rc ) )
{
struct command_work * cmd_work ;
cmd_work = kzalloc ( sizeof ( * cmd_work ) , GFP_ATOMIC ) ;
if ( ! cmd_work )
return - ENOMEM ;
cmd_work - > core_name = core_name ;
cmd_work - > read_len = read_len ;
cmd_work - > read_buf = read_buf ;
cmd_work - > write_len = write_len ;
cmd_work - > write_buf = write_buf ;
cmd_work - > cont = cont ;
INIT_WORK ( & cmd_work - > work ,
cyttsp5_device_access_user_command_work_func ) ;
schedule_work ( & cmd_work - > work ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( cyttsp5_device_access_user_command_async ) ;
# endif
static void cyttsp5_cmcp_parse_threshold_file ( const struct firmware * fw ,
void * context )
{
struct device * dev = context ;
struct cyttsp5_device_access_data * dad =
cyttsp5_get_device_access_data ( dev ) ;
if ( ! fw ) {
dev_info ( dev , " %s: No builtin cmcp threshold file \n " , __func__ ) ;
goto exit ;
}
if ( ! fw - > data | | ! fw - > size ) {
dev_err ( dev , " %s: Invalid builtin cmcp threshold file \n " ,
__func__ ) ;
goto exit ;
}
dev_dbg ( dev , " %s: Found cmcp threshold file. \n " , __func__ ) ;
cyttsp5_parse_cmcp_threshold_file_common ( dev , & fw - > data [ 0 ] , fw - > size ) ;
dad - > builtin_cmcp_threshold_status = 0 ;
complete ( & dad - > builtin_cmcp_threshold_complete ) ;
return ;
exit :
release_firmware ( fw ) ;
dad - > builtin_cmcp_threshold_status = - EINVAL ;
complete ( & dad - > builtin_cmcp_threshold_complete ) ;
}
static void cyttsp5_parse_cmcp_threshold_builtin (
struct work_struct * cmcp_threshold_update )
{
struct cyttsp5_device_access_data * dad =
container_of ( cmcp_threshold_update ,
struct cyttsp5_device_access_data ,
cmcp_threshold_update ) ;
struct device * dev = dad - > dev ;
int retval ;
dad - > si = cmd - > request_sysinfo ( dev ) ;
if ( ! dad - > si ) {
dev_err ( dev , " %s: Fail get sysinfo pointer from core \n " ,
__func__ ) ;
return ;
}
dev_vdbg ( dev , " %s: Enabling cmcp threshold class loader built-in \n " ,
__func__ ) ;
retval = request_firmware_nowait ( THIS_MODULE , FW_ACTION_HOTPLUG ,
CMCP_THRESHOLD_FILE_NAME , dev , GFP_KERNEL , dev ,
cyttsp5_cmcp_parse_threshold_file ) ;
if ( retval < 0 ) {
dev_err ( dev , " %s: Fail request cmcp threshold class file load \n " ,
__func__ ) ;
goto exit ;
}
/* wait until cmcp threshold upgrade finishes */
wait_for_completion ( & dad - > builtin_cmcp_threshold_complete ) ;
retval = dad - > builtin_cmcp_threshold_status ;
exit :
return ;
}
static int cyttsp5_device_access_probe ( struct device * dev , void * * data )
{
struct cyttsp5_device_access_data * dad ;
struct configuration * configurations ;
struct cmcp_data * cmcp_info ;
struct result * result ;
int tx_num = MAX_TX_SENSORS ;
int rx_num = MAX_RX_SENSORS ;
int btn_num = MAX_BUTTONS ;
struct test_case_field * test_case_field_array ;
struct test_case_search * test_case_search_array ;
int rc = 0 ;
dad = kzalloc ( sizeof ( * dad ) , GFP_KERNEL ) ;
if ( ! dad ) {
rc = - ENOMEM ;
goto cyttsp5_device_access_probe_data_failed ;
}
configurations =
kzalloc ( sizeof ( * configurations ) , GFP_KERNEL ) ;
if ( ! configurations ) {
rc = - ENOMEM ;
goto cyttsp5_device_access_probe_configs_failed ;
}
dad - > configs = configurations ;
cmcp_info = kzalloc ( sizeof ( * cmcp_info ) , GFP_KERNEL ) ;
if ( ! cmcp_info ) {
rc = - ENOMEM ;
goto cyttsp5_device_access_probe_cmcp_info_failed ;
}
dad - > cmcp_info = cmcp_info ;
cmcp_info - > tx_num = tx_num ;
cmcp_info - > rx_num = rx_num ;
cmcp_info - > btn_num = btn_num ;
result = kzalloc ( sizeof ( * result ) , GFP_KERNEL ) ;
if ( ! result ) {
rc = - ENOMEM ;
goto cyttsp5_device_access_probe_result_failed ;
}
dad - > result = result ;
test_case_field_array =
kzalloc ( sizeof ( * test_case_field_array ) * MAX_CASE_NUM ,
GFP_KERNEL ) ;
if ( ! test_case_field_array ) {
rc = - ENOMEM ;
goto cyttsp5_device_access_probe_field_array_failed ;
}
test_case_search_array =
kzalloc ( sizeof ( * test_case_search_array ) * MAX_CASE_NUM ,
GFP_KERNEL ) ;
if ( ! test_case_search_array ) {
rc = - ENOMEM ;
goto cyttsp5_device_access_probe_search_array_failed ;
}
cmcp_info - > gd_sensor_col = ( struct gd_sensor * )
kzalloc ( tx_num * sizeof ( struct gd_sensor ) , GFP_KERNEL ) ;
if ( cmcp_info - > gd_sensor_col = = NULL )
goto cyttsp5_device_access_probe_gd_sensor_col_failed ;
cmcp_info - > gd_sensor_row = ( struct gd_sensor * )
kzalloc ( rx_num * sizeof ( struct gd_sensor ) , GFP_KERNEL ) ;
if ( cmcp_info - > gd_sensor_row = = NULL )
goto cyttsp5_device_access_probe_gd_sensor_row_failed ;
cmcp_info - > cm_data_panel =
kzalloc ( ( tx_num * rx_num + 1 ) * sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cm_data_panel = = NULL )
goto cyttsp5_device_access_probe_cm_data_panel_failed ;
cmcp_info - > cp_tx_data_panel =
kzalloc ( tx_num * sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cp_tx_data_panel = = NULL )
goto cyttsp5_device_access_probe_cp_tx_data_panel_failed ;
cmcp_info - > cp_tx_cal_data_panel =
kzalloc ( tx_num * sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cp_tx_cal_data_panel = = NULL )
goto cyttsp5_device_access_probe_cp_tx_cal_data_panel_failed ;
cmcp_info - > cp_rx_data_panel =
kzalloc ( rx_num * sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cp_rx_data_panel = = NULL )
goto cyttsp5_device_access_probe_cp_rx_data_panel_failed ;
cmcp_info - > cp_rx_cal_data_panel =
kzalloc ( rx_num * sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cp_rx_cal_data_panel = = NULL )
goto cyttsp5_device_access_probe_cp_rx_cal_data_panel_failed ;
cmcp_info - > cm_btn_data = kcalloc ( btn_num , sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cm_btn_data = = NULL )
goto cyttsp5_device_access_probe_cm_btn_data_failed ;
cmcp_info - > cp_btn_data = kcalloc ( btn_num , sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cp_btn_data = = NULL )
goto cyttsp5_device_access_probe_cp_btn_data_failed ;
cmcp_info - > cm_sensor_column_delta =
kzalloc ( rx_num * tx_num * sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cm_sensor_column_delta = = NULL )
goto cyttsp5_device_access_probe_cm_sensor_column_delta_failed ;
cmcp_info - > cm_sensor_row_delta =
kzalloc ( tx_num * rx_num * sizeof ( int32_t ) , GFP_KERNEL ) ;
if ( cmcp_info - > cm_sensor_row_delta = = NULL )
goto cyttsp5_device_access_probe_cm_sensor_row_delta_failed ;
mutex_init ( & dad - > sysfs_lock ) ;
mutex_init ( & dad - > cmcp_threshold_lock ) ;
dad - > dev = dev ;
# ifdef TTHE_TUNER_SUPPORT
mutex_init ( & dad - > debugfs_lock ) ;
dad - > heatmap . num_element = 200 ;
# endif
* data = dad ;
dad - > test_field_array = test_case_field_array ;
dad - > test_search_array = test_case_search_array ;
dad - > test_executed = 0 ;
init_completion ( & dad - > builtin_cmcp_threshold_complete ) ;
/* get sysinfo */
dad - > si = cmd - > request_sysinfo ( dev ) ;
if ( dad - > si ) {
rc = cyttsp5_setup_sysfs ( dev ) ;
if ( rc )
goto cyttsp5_device_access_setup_sysfs_failed ;
} else {
dev_err ( dev , " %s: Fail get sysinfo pointer from core p=%p \n " ,
__func__ , dad - > si ) ;
cmd - > subscribe_attention ( dev , CY_ATTEN_STARTUP ,
CYTTSP5_DEVICE_ACCESS_NAME ,
cyttsp5_setup_sysfs_attention , 0 ) ;
}
INIT_WORK ( & dad - > cmcp_threshold_update ,
cyttsp5_parse_cmcp_threshold_builtin ) ;
schedule_work ( & dad - > cmcp_threshold_update ) ;
return 0 ;
cyttsp5_device_access_setup_sysfs_failed :
kfree ( cmcp_info - > cm_sensor_row_delta ) ;
cyttsp5_device_access_probe_cm_sensor_row_delta_failed :
kfree ( cmcp_info - > cm_sensor_column_delta ) ;
cyttsp5_device_access_probe_cm_sensor_column_delta_failed :
kfree ( cmcp_info - > cp_btn_data ) ;
cyttsp5_device_access_probe_cp_btn_data_failed :
kfree ( cmcp_info - > cm_btn_data ) ;
cyttsp5_device_access_probe_cm_btn_data_failed :
kfree ( cmcp_info - > cp_rx_cal_data_panel ) ;
cyttsp5_device_access_probe_cp_rx_cal_data_panel_failed :
kfree ( cmcp_info - > cp_rx_data_panel ) ;
cyttsp5_device_access_probe_cp_rx_data_panel_failed :
kfree ( cmcp_info - > cp_tx_cal_data_panel ) ;
cyttsp5_device_access_probe_cp_tx_cal_data_panel_failed :
kfree ( cmcp_info - > cp_tx_data_panel ) ;
cyttsp5_device_access_probe_cp_tx_data_panel_failed :
kfree ( cmcp_info - > cm_data_panel ) ;
cyttsp5_device_access_probe_cm_data_panel_failed :
kfree ( cmcp_info - > gd_sensor_row ) ;
cyttsp5_device_access_probe_gd_sensor_row_failed :
kfree ( cmcp_info - > gd_sensor_col ) ;
cyttsp5_device_access_probe_gd_sensor_col_failed :
kfree ( test_case_search_array ) ;
cyttsp5_device_access_probe_search_array_failed :
kfree ( test_case_field_array ) ;
cyttsp5_device_access_probe_field_array_failed :
kfree ( result ) ;
cyttsp5_device_access_probe_result_failed :
kfree ( cmcp_info ) ;
cyttsp5_device_access_probe_cmcp_info_failed :
kfree ( configurations ) ;
cyttsp5_device_access_probe_configs_failed :
kfree ( dad ) ;
cyttsp5_device_access_probe_data_failed :
dev_err ( dev , " %s failed. \n " , __func__ ) ;
return rc ;
}
static void cyttsp5_device_access_release ( struct device * dev , void * data )
{
struct cyttsp5_device_access_data * dad = data ;
if ( dad - > sysfs_nodes_created ) {
device_remove_file ( dev , & dev_attr_command ) ;
device_remove_file ( dev , & dev_attr_status ) ;
device_remove_file ( dev , & dev_attr_response ) ;
debugfs_remove ( dad - > cmcp_results_debugfs ) ;
debugfs_remove_recursive ( dad - > base_dentry ) ;
# ifdef TTHE_TUNER_SUPPORT
debugfs_remove ( dad - > tthe_get_panel_data_debugfs ) ;
# endif
device_remove_file ( dev , & dev_attr_cmcp_test ) ;
device_remove_file ( dev , & dev_attr_cmcp_threshold_loading ) ;
device_remove_bin_file ( dev , & bin_attr_cmcp_threshold_data ) ;
kfree ( dad - > cmcp_threshold_data ) ;
} else {
cmd - > unsubscribe_attention ( dev , CY_ATTEN_STARTUP ,
CYTTSP5_DEVICE_ACCESS_NAME ,
cyttsp5_setup_sysfs_attention , 0 ) ;
}
kfree ( dad - > test_search_array ) ;
kfree ( dad - > test_field_array ) ;
kfree ( dad - > configs ) ;
cyttsp5_free_cmcp_buf ( dad - > cmcp_info ) ;
kfree ( dad - > cmcp_info ) ;
kfree ( dad - > result ) ;
kfree ( dad ) ;
}
static struct cyttsp5_module device_access_module = {
. name = CYTTSP5_DEVICE_ACCESS_NAME ,
. probe = cyttsp5_device_access_probe ,
. release = cyttsp5_device_access_release ,
} ;
static int __init cyttsp5_device_access_init ( void )
{
int rc ;
cmd = cyttsp5_get_commands ( ) ;
if ( ! cmd )
return - EINVAL ;
rc = cyttsp5_register_module ( & device_access_module ) ;
if ( rc < 0 ) {
pr_err ( " %s: Error, failed registering module \n " ,
__func__ ) ;
return rc ;
}
pr_info ( " %s: Parade TTSP Device Access Driver (Built %s) rc=%d \n " ,
__func__ , CY_DRIVER_VERSION , rc ) ;
return 0 ;
}
module_init ( cyttsp5_device_access_init ) ;
static void __exit cyttsp5_device_access_exit ( void )
{
cyttsp5_unregister_module ( & device_access_module ) ;
}
module_exit ( cyttsp5_device_access_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Parade TrueTouch(R) Standard Product Device Access Driver " ) ;
MODULE_AUTHOR ( " Parade Technologies <ttdrivers@paradetech.com> " ) ;